ia64/xen-unstable
changeset 1461:138c55619f27
bitkeeper revision 1.955.1.2 (40c9fa70tPu0dbYE7l64lI-VfVdUYQ)
Merge scramble.cl.cam.ac.uk:/auto/groups/xeno/BK/xeno.bk
into scramble.cl.cam.ac.uk:/local/scratch/kaf24/var/bk/xeno-unstable.bk
Merge scramble.cl.cam.ac.uk:/auto/groups/xeno/BK/xeno.bk
into scramble.cl.cam.ac.uk:/local/scratch/kaf24/var/bk/xeno-unstable.bk
line diff
1.1 --- a/.rootkeys Fri Jun 11 15:26:55 2004 +0000 1.2 +++ b/.rootkeys Fri Jun 11 18:31:12 2004 +0000 1.3 @@ -102,6 +102,7 @@ 3e5a4e66qRlSTcjafidMB6ulECADvg linux-2.4 1.4 3e5a4e66mrtlmV75L1tjKDg8RaM5gA linux-2.4.26-xen-sparse/drivers/block/ll_rw_blk.c 1.5 3f108aeaLcGDgQdFAANLTUEid0a05w linux-2.4.26-xen-sparse/drivers/char/mem.c 1.6 3e5a4e66rw65CxyolW9PKz4GG42RcA linux-2.4.26-xen-sparse/drivers/char/tty_io.c 1.7 +40c9c0c1pPwYE3-4i-oI3ubUu7UgvQ linux-2.4.26-xen-sparse/drivers/scsi/aic7xxx/Makefile 1.8 3e5a4e669uzIE54VwucPYtGwXLAbzA linux-2.4.26-xen-sparse/fs/exec.c 1.9 3e5a4e66wbeCpsJgVf_U8Jde-CNcsA linux-2.4.26-xen-sparse/include/asm-xen/bugs.h 1.10 4048c0ddxnIa2GpBAVR-mY6mNSdeJg linux-2.4.26-xen-sparse/include/asm-xen/ctrl_if.h 1.11 @@ -163,6 +164,9 @@ 401d7e16NpnVrFSsR7lKKKfTwCYvWA tools/exa 1.12 401d7e16RJj-lbtsVEjua6HYAIiKiA tools/examples/xc_dom_create.py 1.13 403b7cf7J7FsSSoEPGhx6gXR4pIdZg tools/examples/xc_physinfo.py 1.14 401d7e16X4iojyKopo_j63AyzYZd2A tools/examples/xc_vd_tool.py 1.15 +40c9c4684Wfg8VgMKtRFa_ULi2e_tQ tools/examples/xm_dom_control.py 1.16 +40c9c468pXANclL7slGaoD0kSrIwoQ tools/examples/xm_dom_create.py 1.17 +40c9c468QKoqBHjb5Qwrm60pNVcVng tools/examples/xm_vd_tool.py 1.18 3f776bd2Xd-dUcPKlPN2vG89VGtfvQ tools/misc/Makefile 1.19 40ab2cfawIw8tsYo0dQKtp83h4qfTQ tools/misc/fakei386xen 1.20 3f6dc136ZKOjd8PIqLbFBl_v-rnkGg tools/misc/miniterm/Makefile 1.21 @@ -205,8 +209,10 @@ 3fbd0a40yT6G3M9hMpaz5xTUdl0E4g tools/xc/ 1.22 4055ee41IfFazrwadCH2J72nz-A9YA tools/xenctl/Makefile 1.23 4055ee4b_4Rvns_KzE12csI14EKK6Q tools/xenctl/lib/__init__.py 1.24 4055ee4dwy4l0MghZosxoiu6zmhc9Q tools/xenctl/lib/console_client.py 1.25 +40c9c468IienauFHQ_xJIcqnPJ8giQ tools/xenctl/lib/ip.py 1.26 4059c6a0pnxhG8hwSOivXybbGOwuXw tools/xenctl/lib/tempfile.py 1.27 3fbd4bd6GtGwZGxYUJPOheYIR7bPaA tools/xenctl/lib/utils.py 1.28 +40c9c468F36e06WH38kpYrD3JfXC0Q tools/xenctl/lib/vdisk.py 1.29 4055ee44Bu6oP7U0WxxXypbUt4dNPQ tools/xenctl/setup.py 1.30 40431ac64Hj4ixUnKmlugZKhXPFE_Q tools/xend/Makefile 1.31 4055ad95Se-FqttgxollqOAAHB94zA tools/xend/lib/__init__.py 1.32 @@ -219,6 +225,53 @@ 409ba2e729HhE7fEra4B5EqX-F8Xzw tools/xen 1.33 40431ac8wrUEj-XM7B8smFtx_HA7lQ tools/xend/lib/utils.c 1.34 4054a2fdkdATEnRw-U7AUlgu-6JiUA tools/xend/setup.py 1.35 4056cd26Qyp09iNoOjrvzg8KYzSqOw tools/xend/xend 1.36 +40c9c468icGyC5RAF1bRKsCXPDCvsA tools/xenmgr/Makefile 1.37 +40c9c468SNuObE_YWARyS0hzTPSzKg tools/xenmgr/lib/Args.py 1.38 +40c9c468Um_qc66OQeLEceIz1pgD5g tools/xenmgr/lib/EventServer.py 1.39 +40c9c468U8EVl0d3G--8YXVg6VJD3g tools/xenmgr/lib/EventTypes.py 1.40 +40c9c468QJTEuk9g4qHxGpmIi70PEQ tools/xenmgr/lib/PrettyPrint.py 1.41 +40c9c4688m3eqnC8fhLu1APm36VOVA tools/xenmgr/lib/XendClient.py 1.42 +40c9c468t6iIKTjwuYoe-UMCikDcOQ tools/xenmgr/lib/XendConsole.py 1.43 +40c9c468WnXs6eOUSff23IIGI4kMfQ tools/xenmgr/lib/XendDB.py 1.44 +40c9c468fSl3H3IypyT0ppkbb0ZT9A tools/xenmgr/lib/XendDomain.py 1.45 +40c9c468bbKq3uC7_fuNUkiMMjArdw tools/xenmgr/lib/XendDomainConfig.py 1.46 +40c9c4685ykq87_n1kVUbMr9flx9fg tools/xenmgr/lib/XendDomainInfo.py 1.47 +40c9c46854nsHmuxHQHncKk5rAs5NA tools/xenmgr/lib/XendMigrate.py 1.48 +40c9c468M96gA1EYDvNa5w5kQNYLFA tools/xenmgr/lib/XendNode.py 1.49 +40c9c4686jruMyZIqiaZRMiMoqMJtg tools/xenmgr/lib/XendRoot.py 1.50 +40c9c468P75aHqyIE156JXwc-5W92A tools/xenmgr/lib/XendVdisk.py 1.51 +40c9c468xzANp6o2D_MeCYwNmOIUsQ tools/xenmgr/lib/XendVnet.py 1.52 +40c9c468x191zetrVlMnExfsQWHxIQ tools/xenmgr/lib/__init__.py 1.53 +40c9c468S2YnCEKmk4ey8XQIST7INg tools/xenmgr/lib/encode.py 1.54 +40c9c468DCpMe542varOolW1Xc68ew tools/xenmgr/lib/server/SrvBase.py 1.55 +40c9c468IxQabrKJSWs0aEjl-27mRQ tools/xenmgr/lib/server/SrvConsole.py 1.56 +40c9c4689Io5bxfbYIfRiUvsiLX0EQ tools/xenmgr/lib/server/SrvConsoleDir.py 1.57 +40c9c468woSmBByfeXA4o_jGf2gCgA tools/xenmgr/lib/server/SrvConsoleServer.py 1.58 +40c9c468kACsmkqjxBWKHRo071L26w tools/xenmgr/lib/server/SrvDeviceDir.py 1.59 +40c9c468EQZJVkCLds-OhesJVVyZbQ tools/xenmgr/lib/server/SrvDir.py 1.60 +40c9c468TyHZUq8sk0FF_vxM6Sozrg tools/xenmgr/lib/server/SrvDomain.py 1.61 +40c9c469WzajDjutou3X7FmL9hMf3g tools/xenmgr/lib/server/SrvDomainDir.py 1.62 +40c9c469-8mYEJJTAR6w_ClrJRAfwQ tools/xenmgr/lib/server/SrvEventDir.py 1.63 +40c9c4694eu5759Dehr4Uhakei0EMg tools/xenmgr/lib/server/SrvNode.py 1.64 +40c9c469TaZ83ypsrktmPSHLEZiP5w tools/xenmgr/lib/server/SrvRoot.py 1.65 +40c9c469W3sgDMbBJYQdz5wbQweL0Q tools/xenmgr/lib/server/SrvServer.py 1.66 +40c9c469JlUVPkwGWZyVnqIsU8U6Bw tools/xenmgr/lib/server/SrvVdisk.py 1.67 +40c9c469sG8iuyxjVH3zKw8XOAyxtQ tools/xenmgr/lib/server/SrvVdiskDir.py 1.68 +40c9c469aq7oXrE1Ngqf3_lBqL0RoQ tools/xenmgr/lib/server/SrvVnetDir.py 1.69 +40c9c469Y_aimoOFfUZoS-4eV8gEKg tools/xenmgr/lib/server/__init__.py 1.70 +40c9c4692hckPol_EK0EGB16ZyDsyQ tools/xenmgr/lib/server/blkif.py 1.71 +40c9c469N2-b3GqpLHHHPZykJPLVvA tools/xenmgr/lib/server/channel.py 1.72 +40c9c469hJ_IlatRne-9QEa0-wlquw tools/xenmgr/lib/server/console.py 1.73 +40c9c469UcNJh_NuLU0ytorM0Lk5Ow tools/xenmgr/lib/server/controller.py 1.74 +40c9c469vHh-qLiiubdbKEQbJf18Zw tools/xenmgr/lib/server/cstruct.py 1.75 +40c9c469yrm31i60pGKslTi2Zgpotg tools/xenmgr/lib/server/messages.py 1.76 +40c9c46925x-Rjb0Cv2f1-l2jZrPYg tools/xenmgr/lib/server/netif.py 1.77 +40c9c469ZqILEQ8x6yWy0_51jopiCg tools/xenmgr/lib/server/params.py 1.78 +40c9c469LNxLVizOUpOjEaTKKCm8Aw tools/xenmgr/lib/sxp.py 1.79 +40c9c469kT0H9COWzA4XzPBjWK0WsA tools/xenmgr/netfix 1.80 +40c9c469n2RRwCmjWdjdyyVRWKmgWg tools/xenmgr/setup.py 1.81 +40c9c4697z76HDfkCLdMhmaEwzFoNQ tools/xenmgr/xend 1.82 +40c9c469JkN47d1oXi-e0RjAP-C6uQ tools/xenmgr/xenmgrd 1.83 403a3edbrr8RE34gkbR40zep98SXbg tools/xentrace/Makefile 1.84 40a107afN60pFdURgBv9KwEzgRl5mQ tools/xentrace/formats 1.85 4050c413PhhLNAYk3TEwP37i_iLw9Q tools/xentrace/xentrace.8
2.1 --- a/BitKeeper/etc/ignore Fri Jun 11 15:26:55 2004 +0000 2.2 +++ b/BitKeeper/etc/ignore Fri Jun 11 18:31:12 2004 +0000 2.3 @@ -25,3 +25,132 @@ xen/include/xen/compile.h 2.4 xen/tools/elf-reloc 2.5 xen/tools/figlet/figlet 2.6 TAGS 2.7 +linux-2.4.26-xen-sparse/drivers/scsi/aic7xxx/Makefile~ 2.8 +linux-2.4.26-xen/.config.old 2.9 +linux-2.4.26-xen/.depend 2.10 +linux-2.4.26-xen/.hdepend 2.11 +linux-2.4.26-xen/.version 2.12 +linux-2.4.26-xen/.config 2.13 +linux-2.4.26-xen/COPYING 2.14 +linux-2.4.26-xen/CREDITS 2.15 +linux-2.4.26-xen/Documentation/00-INDEX 2.16 +linux-2.4.26-xen/Documentation/BK-usage/00-INDEX 2.17 +linux-2.4.26-xen/Documentation/BK-usage/bk-kernel-howto.txt 2.18 +linux-2.4.26-xen/Documentation/BK-usage/bk-make-sum 2.19 +linux-2.4.26-xen/Documentation/BK-usage/bksend 2.20 +linux-2.4.26-xen/Documentation/BK-usage/bz64wrap 2.21 +linux-2.4.26-xen/Documentation/BK-usage/cset-to-linus 2.22 +linux-2.4.26-xen/Documentation/BK-usage/csets-to-patches 2.23 +linux-2.4.26-xen/Documentation/BK-usage/unbz64wrap 2.24 +linux-2.4.26-xen/Documentation/BUG-HUNTING 2.25 +linux-2.4.26-xen/Documentation/Changes 2.26 +linux-2.4.26-xen/Documentation/CodingStyle 2.27 +linux-2.4.26-xen/Documentation/Configure.help 2.28 +linux-2.4.26-xen/Documentation/DMA-mapping.txt 2.29 +linux-2.4.26-xen/Documentation/DocBook/Makefile 2.30 +linux-2.4.26-xen/Documentation/DocBook/deviceiobook.tmpl 2.31 +linux-2.4.26-xen/Documentation/DocBook/journal-api.tmpl 2.32 +linux-2.4.26-xen/Documentation/DocBook/kernel-api.tmpl 2.33 +linux-2.4.26-xen/Documentation/DocBook/kernel-hacking.tmpl 2.34 +linux-2.4.26-xen/Documentation/DocBook/kernel-locking.tmpl 2.35 +linux-2.4.26-xen/Documentation/DocBook/mcabook.tmpl 2.36 +linux-2.4.26-xen/Documentation/DocBook/mousedrivers.tmpl 2.37 +linux-2.4.26-xen/Documentation/DocBook/parport-multi.fig 2.38 +linux-2.4.26-xen/Documentation/DocBook/parport-share.fig 2.39 +linux-2.4.26-xen/Documentation/DocBook/parport-structure.fig 2.40 +linux-2.4.26-xen/Documentation/DocBook/parportbook.tmpl 2.41 +linux-2.4.26-xen/Documentation/DocBook/procfs-guide.tmpl 2.42 +linux-2.4.26-xen/Documentation/DocBook/procfs_example.c 2.43 +linux-2.4.26-xen/Documentation/DocBook/sis900.tmpl 2.44 +linux-2.4.26-xen/Documentation/DocBook/tulip-user.tmpl 2.45 +linux-2.4.26-xen/Documentation/DocBook/via-audio.tmpl 2.46 +linux-2.4.26-xen/Documentation/DocBook/videobook.tmpl 2.47 +linux-2.4.26-xen/Documentation/DocBook/wanbook.tmpl 2.48 +linux-2.4.26-xen/Documentation/DocBook/z8530book.tmpl 2.49 +linux-2.4.26-xen/Documentation/IO-mapping.txt 2.50 +linux-2.4.26-xen/Documentation/IPMI.txt 2.51 +linux-2.4.26-xen/Documentation/IRQ-affinity.txt 2.52 +linux-2.4.26-xen/Documentation/LVM-HOWTO 2.53 +linux-2.4.26-xen/Documentation/README.DAC960 2.54 +linux-2.4.26-xen/Documentation/README.moxa 2.55 +linux-2.4.26-xen/Documentation/README.nsp32_cb.eng 2.56 +linux-2.4.26-xen/Documentation/README.nsp_cs.eng 2.57 +linux-2.4.26-xen/Documentation/SAK.txt 2.58 +linux-2.4.26-xen/Documentation/SubmittingDrivers 2.59 +linux-2.4.26-xen/Documentation/SubmittingPatches 2.60 +linux-2.4.26-xen/Documentation/VGA-softcursor.txt 2.61 +linux-2.4.26-xen/Documentation/arm/Booting 2.62 +linux-2.4.26-xen/Documentation/arm/ConfigVars 2.63 +linux-2.4.26-xen/Documentation/arm/MEMC 2.64 +linux-2.4.26-xen/Documentation/arm/Netwinder 2.65 +linux-2.4.26-xen/Documentation/arm/README 2.66 +linux-2.4.26-xen/Documentation/arm/SA1100/ADSBitsy 2.67 +linux-2.4.26-xen/Documentation/arm/SA1100/Assabet 2.68 +linux-2.4.26-xen/Documentation/arm/SA1100/Brutus 2.69 +linux-2.4.26-xen/Documentation/arm/SA1100/CERF 2.70 +linux-2.4.26-xen/Documentation/arm/SA1100/DMA 2.71 +linux-2.4.26-xen/Documentation/arm/SA1100/FreeBird 2.72 +linux-2.4.26-xen/Documentation/arm/SA1100/GraphicsClient 2.73 +linux-2.4.26-xen/Documentation/arm/SA1100/GraphicsMaster 2.74 +linux-2.4.26-xen/Documentation/arm/SA1100/HUW_WEBPANEL 2.75 +linux-2.4.26-xen/Documentation/arm/SA1100/Itsy 2.76 +linux-2.4.26-xen/Documentation/arm/SA1100/LART 2.77 +linux-2.4.26-xen/Documentation/arm/SA1100/PCMCIA 2.78 +linux-2.4.26-xen/Documentation/arm/SA1100/PLEB 2.79 +linux-2.4.26-xen/Documentation/arm/SA1100/Pangolin 2.80 +linux-2.4.26-xen/Documentation/arm/SA1100/SA1100_USB 2.81 +linux-2.4.26-xen/Documentation/arm/SA1100/Tifon 2.82 +linux-2.4.26-xen/Documentation/arm/SA1100/Victor 2.83 +linux-2.4.26-xen/Documentation/arm/SA1100/Yopy 2.84 +linux-2.4.26-xen/Documentation/arm/SA1100/empeg 2.85 +linux-2.4.26-xen/Documentation/arm/SA1100/nanoEngine 2.86 +linux-2.4.26-xen/Documentation/arm/SA1100/serial_UART 2.87 +linux-2.4.26-xen/Documentation/arm/Setup 2.88 +linux-2.4.26-xen/Documentation/arm/empeg/README 2.89 +linux-2.4.26-xen/Documentation/arm/empeg/ir.txt 2.90 +linux-2.4.26-xen/Documentation/arm/empeg/mkdevs 2.91 +linux-2.4.26-xen/Documentation/arm/nwfpe/NOTES 2.92 +linux-2.4.26-xen/Documentation/arm/nwfpe/README 2.93 +linux-2.4.26-xen/Documentation/arm/nwfpe/README.FPE 2.94 +linux-2.4.26-xen/Documentation/arm/nwfpe/TODO 2.95 +linux-2.4.26-xen/Documentation/binfmt_misc.txt 2.96 +linux-2.4.26-xen/Documentation/cachetlb.txt 2.97 +linux-2.4.26-xen/Documentation/cciss.txt 2.98 +linux-2.4.26-xen/Documentation/cdrom/00-INDEX 2.99 +linux-2.4.26-xen/Documentation/cdrom/Makefile 2.100 +linux-2.4.26-xen/Documentation/cdrom/aztcd 2.101 +linux-2.4.26-xen/Documentation/cdrom/cdrom-standard.tex 2.102 +linux-2.4.26-xen/Documentation/cdrom/cdu31a 2.103 +linux-2.4.26-xen/Documentation/cdrom/cm206 2.104 +linux-2.4.26-xen/Documentation/cdrom/gscd 2.105 +linux-2.4.26-xen/Documentation/cdrom/ide-cd 2.106 +linux-2.4.26-xen/Documentation/cdrom/isp16 2.107 +linux-2.4.26-xen/Documentation/cdrom/mcd 2.108 +linux-2.4.26-xen/Documentation/cdrom/mcdx 2.109 +linux-2.4.26-xen/Documentation/cdrom/optcd 2.110 +linux-2.4.26-xen/Documentation/cdrom/sbpcd 2.111 +linux-2.4.26-xen/Documentation/cdrom/sjcd 2.112 +linux-2.4.26-xen/Documentation/cdrom/sonycd535 2.113 +linux-2.4.26-xen/Documentation/computone.txt 2.114 +linux-2.4.26-xen/Documentation/cpqarray.txt 2.115 +linux-2.4.26-xen/Documentation/cris/README 2.116 +linux-2.4.26-xen/Documentation/crypto/api-intro.txt 2.117 +linux-2.4.26-xen/Documentation/crypto/descore-readme.txt 2.118 +linux-2.4.26-xen/Documentation/devices.txt 2.119 +linux-2.4.26-xen/Documentation/digiboard.txt 2.120 +linux-2.4.26-xen/Documentation/digiepca.txt 2.121 +linux-2.4.26-xen/Documentation/dnotify.txt 2.122 +linux-2.4.26-xen/Documentation/exception.txt 2.123 +linux-2.4.26-xen/Documentation/fb/00-INDEX 2.124 +linux-2.4.26-xen/Documentation/fb/README-sstfb.txt 2.125 +linux-2.4.26-xen/Documentation/fb/aty128fb.txt 2.126 +linux-2.4.26-xen/Documentation/fb/clgenfb.txt 2.127 +linux-2.4.26-xen/Documentation/fb/framebuffer.txt 2.128 +linux-2.4.26-xen/Documentation/fb/internals.txt 2.129 +linux-2.4.26-xen/Documentation/fb/matroxfb.txt 2.130 +linux-2.4.26-xen/Documentation/fb/modedb.txt 2.131 +linux-2.4.26-xen/Documentation/fb/pvr2fb.txt 2.132 +linux-2.4.26-xen/Documentation/fb/sa1100fb.txt 2.133 +tools/xenmgr/lib/server/blkif.py~ 2.134 +tools/xenmgr/lib/server/messages.py~ 2.135 +tools/xenmgr/lib/server/netif.py~
3.1 --- a/BitKeeper/etc/logging_ok Fri Jun 11 15:26:55 2004 +0000 3.2 +++ b/BitKeeper/etc/logging_ok Fri Jun 11 18:31:12 2004 +0000 3.3 @@ -23,6 +23,7 @@ kaf24@striker.cl.cam.ac.uk 3.4 laudney@eclipse.(none) 3.5 lynx@idefix.cl.cam.ac.uk 3.6 maw48@labyrinth.cl.cam.ac.uk 3.7 +mjw@wray-m-3.hpl.hp.com 3.8 mwilli2@equilibrium.research.intel-research.net 3.9 rac61@labyrinth.cl.cam.ac.uk 3.10 rgr22@boulderdash.cl.cam.ac.uk
4.1 --- a/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/Makefile Fri Jun 11 15:26:55 2004 +0000 4.2 +++ b/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/Makefile Fri Jun 11 18:31:12 2004 +0000 4.3 @@ -1,3 +1,4 @@ 4.4 O_TARGET := drv.o 4.5 +export-objs := interface.o 4.6 obj-y := main.o control.o interface.o 4.7 include $(TOPDIR)/Rules.make
5.1 --- a/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/interface.c Fri Jun 11 15:26:55 2004 +0000 5.2 +++ b/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/interface.c Fri Jun 11 18:31:12 2004 +0000 5.3 @@ -71,13 +71,14 @@ void __netif_disconnect_complete(netif_t 5.4 5.5 void netif_create(netif_be_create_t *create) 5.6 { 5.7 + int err = 0; 5.8 domid_t domid = create->domid; 5.9 unsigned int handle = create->netif_handle; 5.10 struct net_device *dev; 5.11 netif_t **pnetif, *netif; 5.12 - char name[IFNAMSIZ]; 5.13 + char name[IFNAMSIZ] = {}; 5.14 5.15 - snprintf(name, IFNAMSIZ, "vif%u.%u", domid, handle); 5.16 + snprintf(name, IFNAMSIZ - 1, "vif%u.%u", domid, handle); 5.17 dev = alloc_netdev(sizeof(netif_t), name, ether_setup); 5.18 if ( dev == NULL ) 5.19 { 5.20 @@ -123,9 +124,9 @@ void netif_create(netif_be_create_t *cre 5.21 /* XXX In bridge mode we should force a different MAC from remote end. */ 5.22 dev->dev_addr[2] ^= 1; 5.23 5.24 - if ( register_netdev(dev) != 0 ) 5.25 - { 5.26 - DPRINTK("Could not register new net device\n"); 5.27 + err = register_netdev(dev); 5.28 + if (err) { 5.29 + DPRINTK("Could not register new net device %s: err=%d\n", dev->name, err); 5.30 create->status = NETIF_BE_STATUS_OUT_OF_MEMORY; 5.31 kfree(dev); 5.32 return; 5.33 @@ -302,3 +303,13 @@ void netif_interface_init(void) 5.34 bridge_br->bridge_forward_delay = bridge_br->forward_delay = 0; 5.35 bridge_br->stp_enabled = 0; 5.36 } 5.37 + 5.38 +#ifndef CONFIG_BRIDGE 5.39 +#error Must configure Ethernet bridging in Network Options 5.40 +#endif 5.41 +EXPORT_SYMBOL(br_add_bridge); 5.42 +EXPORT_SYMBOL(br_del_bridge); 5.43 +EXPORT_SYMBOL(br_add_if); 5.44 +EXPORT_SYMBOL(br_del_if); 5.45 +EXPORT_SYMBOL(br_get_bridge_ifindices); 5.46 +EXPORT_SYMBOL(br_get_port_ifindices);
6.1 --- a/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/frontend/main.c Fri Jun 11 15:26:55 2004 +0000 6.2 +++ b/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/frontend/main.c Fri Jun 11 18:31:12 2004 +0000 6.3 @@ -99,6 +99,72 @@ static struct net_device *find_dev_by_ha 6.4 return NULL; 6.5 } 6.6 6.7 +#define MULTIVIF 6.8 +//#ifdef MULTIVIF 6.9 + 6.10 +/** Network interface info. */ 6.11 +struct netif_ctrl { 6.12 + /** Number of interfaces. */ 6.13 + int interface_n; 6.14 + /** Number of connected interfaces. */ 6.15 + int connected_n; 6.16 + /** Error code. */ 6.17 + int err; 6.18 +}; 6.19 + 6.20 +static struct netif_ctrl netctrl = {}; 6.21 + 6.22 +static void netctrl_init(void){ 6.23 + netctrl = (struct netif_ctrl){}; 6.24 + netctrl.interface_n = -1; 6.25 +} 6.26 + 6.27 +/** Get or set a network interface error. 6.28 + */ 6.29 +static int netctrl_err(int err) 6.30 +{ 6.31 + if(err < 0 && !netctrl.err){ 6.32 + netctrl.err = err; 6.33 + printk(KERN_WARNING "%s> err=%d\n", __FUNCTION__, err); 6.34 + } 6.35 + return netctrl.err; 6.36 +} 6.37 + 6.38 +/** Test if all network interfaces are connected. 6.39 + * 6.40 + * @return 1 if all connected, 0 if not, negative error code otherwise 6.41 + */ 6.42 +static int netctrl_connected(void) 6.43 +{ 6.44 + int ok = 0; 6.45 + ok = (netctrl.err ? netctrl.err : (netctrl.connected_n == netctrl.interface_n)); 6.46 + return ok; 6.47 +} 6.48 + 6.49 +/** Count the connected network interfaces. 6.50 + * 6.51 + * @return connected count 6.52 + */ 6.53 +static int netctrl_connected_count(void) 6.54 +{ 6.55 + 6.56 + struct list_head *ent; 6.57 + struct net_private *np; 6.58 + unsigned int connected; 6.59 + 6.60 + connected = 0; 6.61 + 6.62 + list_for_each(ent, &dev_list) { 6.63 + np = list_entry(ent, struct net_private, list); 6.64 + if ( np->state == NETIF_STATE_CONNECTED){ 6.65 + connected++; 6.66 + } 6.67 + } 6.68 + netctrl.connected_n = connected; 6.69 + return connected; 6.70 +} 6.71 + 6.72 +//#endif 6.73 6.74 static int network_open(struct net_device *dev) 6.75 { 6.76 @@ -488,21 +554,100 @@ static struct net_device_stats *network_ 6.77 } 6.78 6.79 6.80 +static void network_reconnect(struct net_device *dev, netif_fe_interface_status_changed_t *status) 6.81 +{ 6.82 + struct net_private *np; 6.83 + int i, requeue_idx; 6.84 + netif_tx_request_t *tx; 6.85 + 6.86 + np = dev->priv; 6.87 + spin_lock_irq(&np->rx_lock); 6.88 + spin_lock(&np->tx_lock); 6.89 + 6.90 + /* Recovery procedure: */ 6.91 + 6.92 + /* Step 1: Reinitialise variables. */ 6.93 + np->rx_resp_cons = np->tx_resp_cons = np->tx_full = 0; 6.94 + np->rx->event = 1; 6.95 + 6.96 + /* Step 2: Rebuild the RX and TX ring contents. 6.97 + * NB. We could just free the queued TX packets now but we hope 6.98 + * that sending them out might do some good. We have to rebuild 6.99 + * the RX ring because some of our pages are currently flipped out 6.100 + * so we can't just free the RX skbs. 6.101 + * NB2. Freelist index entries are always going to be less than 6.102 + * __PAGE_OFFSET, whereas pointers to skbs will always be equal or 6.103 + * greater than __PAGE_OFFSET: we use this property to distinguish 6.104 + * them. 6.105 + */ 6.106 + 6.107 + /* Rebuild the TX buffer freelist and the TX ring itself. 6.108 + * NB. This reorders packets. We could keep more private state 6.109 + * to avoid this but maybe it doesn't matter so much given the 6.110 + * interface has been down. 6.111 + */ 6.112 + for( requeue_idx = 0, i = 1; i <= NETIF_TX_RING_SIZE; i++ ){ 6.113 + if( (unsigned long)np->tx_skbs[i] >= __PAGE_OFFSET ) { 6.114 + struct sk_buff *skb = np->tx_skbs[i]; 6.115 + 6.116 + tx = &np->tx->ring[requeue_idx++].req; 6.117 + 6.118 + tx->id = i; 6.119 + tx->addr = virt_to_machine(skb->data); 6.120 + tx->size = skb->len; 6.121 + 6.122 + np->stats.tx_bytes += skb->len; 6.123 + np->stats.tx_packets++; 6.124 + } 6.125 + } 6.126 + wmb(); 6.127 + np->tx->req_prod = requeue_idx; 6.128 + 6.129 + /* Rebuild the RX buffer freelist and the RX ring itself. */ 6.130 + for ( requeue_idx = 0, i = 1; i <= NETIF_RX_RING_SIZE; i++ ) 6.131 + if ( (unsigned long)np->rx_skbs[i] >= __PAGE_OFFSET ) 6.132 + np->rx->ring[requeue_idx++].req.id = i; 6.133 + wmb(); 6.134 + np->rx->req_prod = requeue_idx; 6.135 + 6.136 + /* Step 3: All public and private state should now be sane. Get 6.137 + * ready to start sending and receiving packets and give the driver 6.138 + * domain a kick because we've probably just requeued some 6.139 + * packets. 6.140 + */ 6.141 + netif_carrier_on(dev); 6.142 + netif_start_queue(dev); 6.143 + np->state = NETIF_STATE_ACTIVE; 6.144 + 6.145 + notify_via_evtchn(status->evtchn); 6.146 + 6.147 + network_tx_buf_gc(dev); 6.148 + 6.149 + printk(KERN_INFO "Recovery completed\n"); 6.150 + 6.151 + spin_unlock(&np->tx_lock); 6.152 + spin_unlock_irq(&np->rx_lock); 6.153 +} 6.154 + 6.155 static void netif_status_change(netif_fe_interface_status_changed_t *status) 6.156 { 6.157 ctrl_msg_t cmsg; 6.158 netif_fe_interface_connect_t up; 6.159 struct net_device *dev; 6.160 struct net_private *np; 6.161 - 6.162 - if ( status->handle != 0 ) 6.163 - { 6.164 - printk(KERN_WARNING "Status change on unsupported netif %d\n", 6.165 - status->handle); 6.166 + 6.167 +//#ifdef MULTIVIF 6.168 + if(netctrl.interface_n <= 0){ 6.169 + printk(KERN_WARNING "Status change: no interfaces\n"); 6.170 return; 6.171 } 6.172 - 6.173 - dev = find_dev_by_handle(0); 6.174 +//#endif 6.175 + dev = find_dev_by_handle(status->handle); 6.176 + if(!dev){ 6.177 + printk(KERN_WARNING "Status change: invalid netif handle %u\n", 6.178 + status->handle); 6.179 + return; 6.180 + } 6.181 np = dev->priv; 6.182 6.183 switch ( status->status ) 6.184 @@ -560,7 +705,7 @@ static void netif_status_change(netif_fe 6.185 cmsg.type = CMSG_NETIF_FE; 6.186 cmsg.subtype = CMSG_NETIF_FE_INTERFACE_CONNECT; 6.187 cmsg.length = sizeof(netif_fe_interface_connect_t); 6.188 - up.handle = 0; 6.189 + up.handle = status->handle; 6.190 up.tx_shmem_frame = virt_to_machine(np->tx) >> PAGE_SHIFT; 6.191 up.rx_shmem_frame = virt_to_machine(np->rx) >> PAGE_SHIFT; 6.192 memcpy(cmsg.msg, &up, sizeof(up)); 6.193 @@ -570,8 +715,7 @@ static void netif_status_change(netif_fe 6.194 break; 6.195 6.196 case NETIF_INTERFACE_STATUS_CONNECTED: 6.197 - if ( np->state == NETIF_STATE_CLOSED ) 6.198 - { 6.199 + if ( np->state == NETIF_STATE_CLOSED ){ 6.200 printk(KERN_WARNING "Unexpected netif-CONNECTED message" 6.201 " in state %d\n", np->state); 6.202 break; 6.203 @@ -579,87 +723,20 @@ static void netif_status_change(netif_fe 6.204 6.205 memcpy(dev->dev_addr, status->mac, ETH_ALEN); 6.206 6.207 - if(netif_carrier_ok(dev)) 6.208 + if(netif_carrier_ok(dev)){ 6.209 np->state = NETIF_STATE_CONNECTED; 6.210 - else 6.211 - { 6.212 - int i, requeue_idx; 6.213 - netif_tx_request_t *tx; 6.214 - 6.215 - spin_lock_irq(&np->rx_lock); 6.216 - spin_lock(&np->tx_lock); 6.217 - 6.218 - /* Recovery procedure: */ 6.219 - 6.220 - /* Step 1: Reinitialise variables. */ 6.221 - np->rx_resp_cons = np->tx_resp_cons = np->tx_full = 0; 6.222 - np->rx->event = 1; 6.223 - 6.224 - /* Step 2: Rebuild the RX and TX ring contents. 6.225 - * NB. We could just free the queued TX packets now but we hope 6.226 - * that sending them out might do some good. We have to rebuild 6.227 - * the RX ring because some of our pages are currently flipped out 6.228 - * so we can't just free the RX skbs. 6.229 - * NB2. Freelist index entries are always going to be less than 6.230 - * __PAGE_OFFSET, whereas pointers to skbs will always be equal or 6.231 - * greater than __PAGE_OFFSET: we use this property to distinguish 6.232 - * them. 6.233 - */ 6.234 - 6.235 - /* Rebuild the TX buffer freelist and the TX ring itself. 6.236 - * NB. This reorders packets. We could keep more private state 6.237 - * to avoid this but maybe it doesn't matter so much given the 6.238 - * interface has been down. 6.239 - */ 6.240 - for ( requeue_idx = 0, i = 1; i <= NETIF_TX_RING_SIZE; i++ ) 6.241 - { 6.242 - if ( (unsigned long)np->tx_skbs[i] >= __PAGE_OFFSET ) 6.243 - { 6.244 - struct sk_buff *skb = np->tx_skbs[i]; 6.245 - 6.246 - tx = &np->tx->ring[requeue_idx++].req; 6.247 - 6.248 - tx->id = i; 6.249 - tx->addr = virt_to_machine(skb->data); 6.250 - tx->size = skb->len; 6.251 - 6.252 - np->stats.tx_bytes += skb->len; 6.253 - np->stats.tx_packets++; 6.254 - } 6.255 - } 6.256 - wmb(); 6.257 - np->tx->req_prod = requeue_idx; 6.258 - 6.259 - /* Rebuild the RX buffer freelist and the RX ring itself. */ 6.260 - for ( requeue_idx = 0, i = 1; i <= NETIF_RX_RING_SIZE; i++ ) 6.261 - if ( (unsigned long)np->rx_skbs[i] >= __PAGE_OFFSET ) 6.262 - np->rx->ring[requeue_idx++].req.id = i; 6.263 - wmb(); 6.264 - np->rx->req_prod = requeue_idx; 6.265 - 6.266 - /* Step 3: All public and private state should now be sane. Get 6.267 - * ready to start sending and receiving packets and give the driver 6.268 - * domain a kick because we've probably just requeued some 6.269 - * packets. 6.270 - */ 6.271 - netif_carrier_on(dev); 6.272 - netif_start_queue(dev); 6.273 - np->state = NETIF_STATE_ACTIVE; 6.274 - 6.275 - notify_via_evtchn(status->evtchn); 6.276 - 6.277 - network_tx_buf_gc(dev); 6.278 - 6.279 - printk(KERN_INFO "Recovery completed\n"); 6.280 - 6.281 - spin_unlock(&np->tx_lock); 6.282 - spin_unlock_irq(&np->rx_lock); 6.283 + } else { 6.284 + network_reconnect(dev, status); 6.285 } 6.286 6.287 np->evtchn = status->evtchn; 6.288 np->irq = bind_evtchn_to_irq(np->evtchn); 6.289 (void)request_irq(np->irq, netif_int, SA_SAMPLE_RANDOM, 6.290 dev->name, dev); 6.291 + 6.292 +#ifdef MULTIVIF 6.293 + netctrl_connected_count(); 6.294 +#endif 6.295 break; 6.296 6.297 default: 6.298 @@ -669,27 +746,102 @@ static void netif_status_change(netif_fe 6.299 } 6.300 } 6.301 6.302 +/** Create a network devices. 6.303 + * 6.304 + * @param handle device handle 6.305 + * @param val return parameter for created device 6.306 + * @return 0 on success, error code otherwise 6.307 + */ 6.308 +static int create_netdev(int handle, struct net_device **val){ 6.309 + int err = 0; 6.310 + struct net_device *dev = NULL; 6.311 + struct net_private *np = NULL; 6.312 + 6.313 + dev = alloc_etherdev(sizeof(struct net_private)); 6.314 + if (!dev){ 6.315 + printk(KERN_WARNING "%s> alloc_etherdev failed.\n", __FUNCTION__); 6.316 + err = -ENOMEM; 6.317 + goto exit; 6.318 + } 6.319 + np = dev->priv; 6.320 + np->state = NETIF_STATE_CLOSED; 6.321 + np->handle = handle; 6.322 + 6.323 + dev->open = network_open; 6.324 + dev->hard_start_xmit = network_start_xmit; 6.325 + dev->stop = network_close; 6.326 + dev->get_stats = network_get_stats; 6.327 + dev->poll = netif_poll; 6.328 + dev->weight = 64; 6.329 + 6.330 + err = register_netdev(dev); 6.331 + if (err){ 6.332 + printk(KERN_WARNING "%s> register_netdev err=%d\n", __FUNCTION__, err); 6.333 + goto exit; 6.334 + } 6.335 + np->dev = dev; 6.336 + list_add(&np->list, &dev_list); 6.337 + exit: 6.338 + if(err){ 6.339 + if(dev) kfree(dev); 6.340 + dev = NULL; 6.341 + } 6.342 + if(val) *val = dev; 6.343 + return err; 6.344 +} 6.345 + 6.346 +//#ifdef MULTIVIF 6.347 +/** Initialize the network control interface. Set the number of network devices 6.348 + * and create them. 6.349 + */ 6.350 +static void netif_driver_status_change(netif_fe_driver_status_changed_t *status) 6.351 +{ 6.352 + int err = 0; 6.353 + int i; 6.354 + 6.355 + netctrl.interface_n = status->nr_interfaces; 6.356 + netctrl.connected_n = 0; 6.357 + 6.358 + for(i = 0; i < netctrl.interface_n; i++){ 6.359 + err = create_netdev(i, NULL); 6.360 + if(err){ 6.361 + netctrl_err(err); 6.362 + break; 6.363 + } 6.364 + } 6.365 +} 6.366 +//#endif 6.367 + 6.368 6.369 static void netif_ctrlif_rx(ctrl_msg_t *msg, unsigned long id) 6.370 { 6.371 + int respond = 1; 6.372 switch ( msg->subtype ) 6.373 { 6.374 case CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED: 6.375 if ( msg->length != sizeof(netif_fe_interface_status_changed_t) ) 6.376 - goto parse_error; 6.377 + goto error; 6.378 netif_status_change((netif_fe_interface_status_changed_t *) 6.379 &msg->msg[0]); 6.380 break; 6.381 +//#ifdef MULTIVIF 6.382 + case CMSG_NETIF_FE_DRIVER_STATUS_CHANGED: 6.383 + if ( msg->length != sizeof(netif_fe_driver_status_changed_t) ) 6.384 + goto error; 6.385 + netif_driver_status_change((netif_fe_driver_status_changed_t *) 6.386 + &msg->msg[0]); 6.387 + // Message is a response, so do not respond. 6.388 + respond = 0; 6.389 + break; 6.390 +//#endif 6.391 + error: 6.392 default: 6.393 - goto parse_error; 6.394 + msg->length = 0; 6.395 + break; 6.396 } 6.397 - 6.398 - ctrl_if_send_response(msg); 6.399 - return; 6.400 - 6.401 - parse_error: 6.402 - msg->length = 0; 6.403 - ctrl_if_send_response(msg); 6.404 + if(respond){ 6.405 + ctrl_if_send_response(msg); 6.406 + } 6.407 } 6.408 6.409 6.410 @@ -697,9 +849,11 @@ static int __init init_module(void) 6.411 { 6.412 ctrl_msg_t cmsg; 6.413 netif_fe_driver_status_changed_t st; 6.414 - int err; 6.415 - struct net_device *dev; 6.416 - struct net_private *np; 6.417 + int err = 0; 6.418 +#ifdef MULTIVIF 6.419 + int wait_n = 20; 6.420 + int wait_i; 6.421 +#endif 6.422 6.423 if ( (start_info.flags & SIF_INITDOMAIN) || 6.424 (start_info.flags & SIF_NET_BE_DOMAIN) ) 6.425 @@ -708,32 +862,9 @@ static int __init init_module(void) 6.426 printk("Initialising Xen virtual ethernet frontend driver"); 6.427 6.428 INIT_LIST_HEAD(&dev_list); 6.429 - 6.430 - if ( (dev = alloc_etherdev(sizeof(struct net_private))) == NULL ) 6.431 - { 6.432 - err = -ENOMEM; 6.433 - goto fail; 6.434 - } 6.435 - 6.436 - np = dev->priv; 6.437 - np->state = NETIF_STATE_CLOSED; 6.438 - np->handle = 0; 6.439 - 6.440 - dev->open = network_open; 6.441 - dev->hard_start_xmit = network_start_xmit; 6.442 - dev->stop = network_close; 6.443 - dev->get_stats = network_get_stats; 6.444 - dev->poll = netif_poll; 6.445 - dev->weight = 64; 6.446 - 6.447 - if ( (err = register_netdev(dev)) != 0 ) 6.448 - { 6.449 - kfree(dev); 6.450 - goto fail; 6.451 - } 6.452 - 6.453 - np->dev = dev; 6.454 - list_add(&np->list, &dev_list); 6.455 +#ifdef MULTIVIF 6.456 + netctrl_init(); 6.457 +#endif 6.458 6.459 (void)ctrl_if_register_receiver(CMSG_NETIF_FE, netif_ctrlif_rx, 6.460 CALLBACK_IN_BLOCKING_CONTEXT); 6.461 @@ -743,25 +874,30 @@ static int __init init_module(void) 6.462 cmsg.subtype = CMSG_NETIF_FE_DRIVER_STATUS_CHANGED; 6.463 cmsg.length = sizeof(netif_fe_driver_status_changed_t); 6.464 st.status = NETIF_DRIVER_STATUS_UP; 6.465 + st.nr_interfaces = 0; 6.466 memcpy(cmsg.msg, &st, sizeof(st)); 6.467 - 6.468 ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE); 6.469 - 6.470 - /* 6.471 - * We should read 'nr_interfaces' from response message and wait 6.472 - * for notifications before proceeding. For now we assume that we 6.473 - * will be notified of exactly one interface. 6.474 - */ 6.475 - while ( np->state != NETIF_STATE_CONNECTED ) 6.476 - { 6.477 + 6.478 +#ifdef MULTIVIF 6.479 + /* Wait for all interfaces to be connected. */ 6.480 + for(wait_i = 0; 1; wait_i++) { 6.481 + if(wait_i < wait_n){ 6.482 + err = netctrl_connected(); 6.483 + } else { 6.484 + err = -ENETDOWN; 6.485 + } 6.486 + if(err < 0) goto exit; 6.487 + if(err > 0){ 6.488 + err = 0; 6.489 + break; 6.490 + } 6.491 set_current_state(TASK_INTERRUPTIBLE); 6.492 schedule_timeout(1); 6.493 - } 6.494 + } 6.495 +#endif 6.496 6.497 - return 0; 6.498 - 6.499 - fail: 6.500 - cleanup_module(); 6.501 + exit: 6.502 + if(err) cleanup_module(); 6.503 return err; 6.504 } 6.505
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/linux-2.4.26-xen-sparse/drivers/scsi/aic7xxx/Makefile Fri Jun 11 18:31:12 2004 +0000 7.3 @@ -0,0 +1,97 @@ 7.4 +# 7.5 +# drivers/scsi/aic7xxx/Makefile 7.6 +# 7.7 +# Makefile for the Linux aic7xxx SCSI driver. 7.8 +# 7.9 + 7.10 +O_TARGET := aic7xxx_drv.o 7.11 + 7.12 +list-multi := aic7xxx.o aic79xx.o 7.13 + 7.14 +obj-$(CONFIG_SCSI_AIC7XXX) += aic7xxx.o 7.15 +ifeq ($(CONFIG_PCI),y) 7.16 +obj-$(CONFIG_SCSI_AIC79XX) += aic79xx.o 7.17 +endif 7.18 + 7.19 +EXTRA_CFLAGS += -I$(TOPDIR)/drivers/scsi -Werror 7.20 +#EXTRA_CFLAGS += -g 7.21 + 7.22 +# Platform Specific Files 7.23 +obj-aic7xxx = aic7xxx_osm.o aic7xxx_proc.o 7.24 + 7.25 +# Core Files 7.26 +obj-aic7xxx += aic7xxx_core.o aic7xxx_93cx6.o 7.27 +ifeq ($(CONFIG_AIC7XXX_REG_PRETTY_PRINT),y) 7.28 +obj-aic7xxx += aic7xxx_reg_print.o 7.29 +endif 7.30 + 7.31 +#EISA Specific Files 7.32 +AIC7XXX_EISA_ARCH = $(filter i386 alpha xen,$(ARCH)) 7.33 +ifneq ($(AIC7XXX_EISA_ARCH),) 7.34 +obj-aic7xxx += aic7770.o 7.35 +# Platform Specific EISA Files 7.36 +obj-aic7xxx += aic7770_osm.o 7.37 +endif 7.38 + 7.39 +#PCI Specific Files 7.40 +ifeq ($(CONFIG_PCI),y) 7.41 +obj-aic7xxx += aic7xxx_pci.o 7.42 +# Platform Specific PCI Files 7.43 +obj-aic7xxx += aic7xxx_osm_pci.o 7.44 +endif 7.45 + 7.46 +# Platform Specific U320 Files 7.47 +obj-aic79xx = aic79xx_osm.o aic79xx_proc.o aic79xx_osm_pci.o 7.48 +# Core Files 7.49 +obj-aic79xx += aic79xx_core.o aic79xx_pci.o 7.50 +ifeq ($(CONFIG_AIC79XX_REG_PRETTY_PRINT),y) 7.51 +obj-aic79xx += aic79xx_reg_print.o 7.52 +endif 7.53 + 7.54 +# Override our module desitnation 7.55 +MOD_DESTDIR = $(shell cd .. && $(CONFIG_SHELL) $(TOPDIR)/scripts/pathdown.sh) 7.56 + 7.57 +include $(TOPDIR)/Rules.make 7.58 + 7.59 +aic7xxx_core.o: aic7xxx_seq.h 7.60 +$(obj-aic7xxx): aic7xxx_reg.h 7.61 +aic7xxx.o: aic7xxx_seq.h aic7xxx_reg.h $(obj-aic7xxx) 7.62 + $(LD) $(LD_RFLAG) -r -o $@ $(obj-aic7xxx) 7.63 + 7.64 +aic79xx_core.o: aic79xx_seq.h 7.65 +$(obj-aic79xx): aic79xx_reg.h 7.66 +aic79xx.o: aic79xx_seq.h aic79xx_reg.h $(obj-aic79xx) 7.67 + $(LD) $(LD_RFLAG) -r -o $@ $(obj-aic79xx) 7.68 + 7.69 +ifeq ($(CONFIG_AIC7XXX_BUILD_FIRMWARE),y) 7.70 +aic7xxx_gen = aic7xxx_seq.h aic7xxx_reg.h 7.71 +ifeq ($(CONFIG_AIC7XXX_REG_PRETTY_PRINT),y) 7.72 +aic7xxx_gen += aic7xxx_reg_print.c 7.73 +aic7xxx_asm_cmd = aicasm/aicasm -I. -r aic7xxx_reg.h \ 7.74 + -p aic7xxx_reg_print.c -i aic7xxx_osm.h \ 7.75 + -o aic7xxx_seq.h aic7xxx.seq 7.76 +else 7.77 +aic7xxx_asm_cmd = aicasm/aicasm -I. -r aic7xxx_reg.h \ 7.78 + -o aic7xxx_seq.h aic7xxx.seq 7.79 +endif 7.80 +$(aic7xxx_gen): aic7xxx.seq aic7xxx.reg aicasm/aicasm 7.81 + $(aic7xxx_asm_cmd) 7.82 +endif 7.83 + 7.84 +ifeq ($(CONFIG_AIC79XX_BUILD_FIRMWARE),y) 7.85 +aic79xx_gen = aic79xx_seq.h aic79xx_reg.h 7.86 +ifeq ($(CONFIG_AIC79XX_REG_PRETTY_PRINT),y) 7.87 +aic79xx_gen += aic79xx_reg_print.c 7.88 +aic79xx_asm_cmd = aicasm/aicasm -I. -r aic79xx_reg.h \ 7.89 + -p aic79xx_reg_print.c -i aic79xx_osm.h \ 7.90 + -o aic79xx_seq.h aic79xx.seq 7.91 +else 7.92 +aic79xx_asm_cmd = aicasm/aicasm -I. -r aic79xx_reg.h \ 7.93 + -o aic79xx_seq.h aic79xx.seq 7.94 +endif 7.95 +$(aic79xx_gen): aic79xx.seq aic79xx.reg aicasm/aicasm 7.96 + $(aic79xx_asm_cmd) 7.97 +endif 7.98 + 7.99 +aicasm/aicasm: aicasm/*.[chyl] 7.100 + $(MAKE) -C aicasm
8.1 --- a/tools/Makefile Fri Jun 11 15:26:55 2004 +0000 8.2 +++ b/tools/Makefile Fri Jun 11 18:31:12 2004 +0000 8.3 @@ -7,6 +7,7 @@ all: 8.4 $(MAKE) -C xentrace 8.5 $(MAKE) -C xenctl 8.6 $(MAKE) -C xend 8.7 + $(MAKE) -C xenmgr 8.8 8.9 install: all 8.10 $(MAKE) -C balloon install 8.11 @@ -16,6 +17,7 @@ install: all 8.12 $(MAKE) -C xentrace install 8.13 $(MAKE) -C xenctl install 8.14 $(MAKE) -C xend install 8.15 + $(MAKE) -C xenmgr install 8.16 8.17 dist: $(TARGET) 8.18 $(MAKE) prefix=`pwd`/../../install dist=yes install 8.19 @@ -30,4 +32,5 @@ clean: 8.20 $(MAKE) -C xentrace clean 8.21 $(MAKE) -C xenctl clean 8.22 $(MAKE) -C xend clean 8.23 + $(MAKE) -C xenmgr install 8.24
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 9.2 +++ b/tools/examples/xm_dom_control.py Fri Jun 11 18:31:12 2004 +0000 9.3 @@ -0,0 +1,233 @@ 9.4 +#!/usr/bin/env python 9.5 + 9.6 +import sys 9.7 +import re 9.8 +import string 9.9 +import time 9.10 +import os 9.11 +import os.path 9.12 +import signal 9.13 + 9.14 +from xenmgr.XendClient import server 9.15 + 9.16 +# usage: xc_dom_control [command] <params> 9.17 +# 9.18 +# this script isn't very smart, but it'll do for now. 9.19 +# 9.20 + 9.21 +def usage (rc=0): 9.22 + if rc: 9.23 + out = sys.stderr 9.24 + else: 9.25 + out = sys.stdout 9.26 + print >> out, """ 9.27 +Usage: %s [command] <params> 9.28 + 9.29 + help -- print usage 9.30 + stop [dom] -- pause a domain 9.31 + start [dom] -- un-pause a domain 9.32 + shutdown [dom] [[-w]] -- request a domain to shutdown (can specify 'all') 9.33 + (optionally wait for complete shutdown) 9.34 + destroy [dom] -- immediately terminate a domain 9.35 + pincpu [dom] [cpu] -- pin a domain to the specified CPU 9.36 + suspend [dom] [file] -- write domain's memory to a file and terminate 9.37 + (resume by re-running xc_dom_create with -L option) 9.38 + unwatch [dom] -- kill the auto-restart daemon for a domain 9.39 + list -- print info about all domains 9.40 + listvbds -- print info about all virtual block devs 9.41 + cpu_bvtset [dom] [mcuadv] [warp] [warpl] [warpu] 9.42 + -- set BVT scheduling parameters for domain 9.43 + cpu_bvtslice [slice] -- set default BVT scheduler slice 9.44 + cpu_atropos_set [dom] [period] [slice] [latency] [xtratime] 9.45 + -- set Atropos scheduling parameters for domain 9.46 + cpu_rrobin_slice [slice] -- set Round Robin scheduler slice 9.47 + vif_stats [dom] [vif] -- get stats for a given network vif 9.48 + vif_addip [dom] [vif] [ip] -- add an IP address to a given vif 9.49 + vif_setsched [dom] [vif] [bytes] [usecs] -- rate limit vif bandwidth 9.50 + vif_getsched [dom] [vif] -- print vif's scheduling parameters 9.51 + vbd_add [dom] [uname] [dev] [mode] -- make disk/partition uname available to 9.52 + domain as dev e.g. 'vbd_add 2 phy:sda3 hda1 w' 9.53 + vbd_remove [dom] [dev] -- remove disk or partition attached as 'dev' 9.54 +""" % sys.argv[0] 9.55 + if rc: sys.exit(rc) 9.56 + 9.57 +if len(sys.argv) < 2: usage(1) 9.58 +cmd = sys.argv[1] 9.59 + 9.60 +#todo: replace all uses of xc with the new api. 9.61 +import Xc; xc = Xc.new() 9.62 + 9.63 +rc = '' 9.64 +dom = None 9.65 + 9.66 + 9.67 +def auto_restart_pid_file(dom): 9.68 + # The auto-restart daemon's pid file. 9.69 + return '/var/run/xendomains/%d.pid' % dom 9.70 + 9.71 +def auto_restart_pid(dom): 9.72 + watcher = auto_restart_pid_file(dom) 9.73 + if os.path.isfile(watcher): 9.74 + fd = open(watcher,'r') 9.75 + pid = int(fd.readline()) 9.76 + else: 9.77 + pid = None 9.78 + return pid 9.79 + 9.80 +def auto_restart_kill(dom): 9.81 + #todo: replace this - tell xend not to restart any more. 9.82 + # Kill a domain's auto restart daemon. 9.83 + pid = auto_restart_pid(dom) 9.84 + if pid: 9.85 + os.kill(pid, signal.SIGTERM) 9.86 + 9.87 + 9.88 +if len( sys.argv ) > 2 and re.match('\d+$', sys.argv[2]): 9.89 + dom = long(sys.argv[2]) 9.90 + 9.91 +if cmd == "help": 9.92 + usage() 9.93 + 9.94 +elif cmd == 'stop': 9.95 + rc = server.xend_domain_stop(dom) 9.96 + 9.97 +elif cmd == 'start': 9.98 + rc = server.xend_domain_start(dom) 9.99 + 9.100 +elif cmd == 'shutdown': 9.101 + doms = [] 9.102 + shutdown = [] 9.103 + if dom != None: 9.104 + doms = [ dom ] 9.105 + elif sys.argv[2] == 'all': 9.106 + doms = server.xend_domains() 9.107 + doms.remove('0') 9.108 + for d in doms: 9.109 + ret = server.xend_domain_shutdown(d) 9.110 + if ret == 0: 9.111 + shutdown.append(d) 9.112 + else: 9.113 + rc = ret 9.114 + 9.115 + wait = (len(sys.argv) == 4 and sys.argv[3] == "-w") 9.116 + if wait: 9.117 + # wait for all domains we shut down to terminate 9.118 + for dom in shutdown: 9.119 + while True: 9.120 + info = server.xend_domain(dom) 9.121 + if not info: break 9.122 + time.sleep(1) 9.123 + 9.124 +elif cmd == 'destroy': 9.125 + rc = server.xend_domain_halt(dom) 9.126 + 9.127 +elif cmd == 'pincpu': 9.128 + if len(sys.argv) < 4: usage(1) 9.129 + cpu = int(sys.argv[3]) 9.130 + rc = server.xend_domain_pincpu(dom, cpu) 9.131 + 9.132 +elif cmd == 'list': 9.133 + print 'Dom Name Mem(MB) CPU State Time(s)' 9.134 + for dom in server.xend_domains(): 9.135 + info = server.xend_domain(dom) 9.136 + d = {} 9.137 + d['dom'] = dom 9.138 + d['name'] = sxp.get_child_value(info, 'name', '??') 9.139 + d['mem'] = int(sxp.get_child_value(info, 'memory', '0')) 9.140 + d['cpu'] = int(sxp.get_child_value(info, 'cpu', '0')) 9.141 + d['state'] = sxp.get_child_value(info, 'state', '??') 9.142 + d['cpu_time'] = sxp.get_child_value(info, 'cpu_time', '0') 9.143 + print ("%(dom)-4d %(name)-16s %(mem)7d %(cpu)3d %(state)5s %(cpu_time)8d" 9.144 + % d) 9.145 + 9.146 +elif cmd == 'unwatch': 9.147 + auto_restart_kill(dom) 9.148 + 9.149 +elif cmd == 'listvbds': 9.150 + print 'Dom Dev Mode Size(MB)' 9.151 + for dom in server.xend_domains(): 9.152 + for vbd in server.xend_domain_vbds(dom): 9.153 + info = server.xend_domain_vbd(vbd) 9.154 + v['vbd'] = vbd 9.155 + v['size'] = int(sxp.get_child_value(info, 'size', '0')) 9.156 + v['mode'] = sxp.get_child_value(info, 'mode', '??') 9.157 + vbd['size_mb'] = vbd['nr_sectors'] / 2048 9.158 + print ('%(dom)-4d %(vbd)04x %(mode)-2s %(size)d' % v) 9.159 + 9.160 +elif cmd == 'suspend': 9.161 + if len(sys.argv) < 4: usage(1) 9.162 + file = os.path.abspath(sys.argv[3]) 9.163 + auto_restart_kill(dom) 9.164 + rc = server.xend_domain_save(dom, file, progress=1) 9.165 + 9.166 +elif cmd == 'cpu_bvtslice': 9.167 + if len(sys.argv) < 3: usage(1) 9.168 + slice = sys.argv[2] 9.169 + rc = server.xend_node_cpu_bvt_slice_set(slice) 9.170 + 9.171 +elif cmd == 'cpu_bvtset': 9.172 + if len(sys.argv) < 7: usage(1) 9.173 + (mcuadv, warp, warpl, warpu) = map(int, sys.argv[3:7]) 9.174 + 9.175 + rc = server.xend_domain_cpu_bvt_set(dom, mcuadv, warp, warpl, warpu) 9.176 + 9.177 +elif cmd == 'vif_stats': 9.178 + if len(sys.argv) < 4: usage(1) 9.179 + vif = int(sys.argv[3]) 9.180 + 9.181 + print server.xend_domain_vif_stats(dom, vif) 9.182 + 9.183 +elif cmd == 'vif_addip': 9.184 + if len(sys.argv) < 5: usage(1) 9.185 + vif = int(sys.argv[3]) 9.186 + ip = sys.argv[4] 9.187 + rc = server.xend_domain_vif_addip(dom, vif, ip) 9.188 + 9.189 +elif cmd == 'vif_setsched': 9.190 + if len(sys.argv) < 6: usage(1) 9.191 + (vif, bytes, usecs) = map(int, sys.argv[3:6]) 9.192 + rc = server.xend_domain_vif_scheduler_set(dom, vif, bytes, usecs) 9.193 + 9.194 +elif cmd == 'vif_getsched': 9.195 + if len(sys.argv) < 4: usage(1) 9.196 + vif = int(sys.argv[3]) 9.197 + print server.xend_domain_vif_scheduler_get(dom, vif) 9.198 + 9.199 +elif cmd == 'vbd_add': 9.200 + if len(sys.argv) < 6: usage(1) 9.201 + uname = sys.argv[3] 9.202 + dev = sys.argv[4] 9.203 + mode = sys.argv[5] 9.204 + try: 9.205 + vbd = server.xend_domain_vbd_add(dom, uname, dev, mode) 9.206 + except StandardError, ex: 9.207 + print "Error:", ex 9.208 + sys.exit(1) 9.209 + print "Added disk/partition %s to domain %d as device %s (%x)" % (uname, dom, dev, vbd) 9.210 + 9.211 +elif cmd == 'vbd_remove': 9.212 + if len(sys.argv) < 4: usage(1) 9.213 + dev = sys.argv[3] 9.214 + vbd = server.xend_domain_vbd_remove(dom, dev) 9.215 + if vbd < 0: 9.216 + print "Failed" 9.217 + sys.exit(1) 9.218 + else: 9.219 + print "Removed disk/partition attached as device %s (%x) in domain %d" % (dev, vbd, dom) 9.220 + 9.221 +elif cmd == 'cpu_atropos_set': # args: dom period slice latency xtratime 9.222 + if len(sys.argv) < 6: usage(1) 9.223 + (period, slice, latency, xtratime) = map(int, sys.argv[3:7]) 9.224 + rc = server.xend_domain_cpu_atropos_set( 9.225 + dom, period, slice, latency, xtratime) 9.226 + 9.227 +elif cmd == 'cpu_rrobin_slice': 9.228 + if len(sys.argv) < 3: usage(1) 9.229 + slice = int(sys.argv[2]) 9.230 + rc = server.xend_node_rrobin_set(slice=slice) 9.231 + 9.232 +else: 9.233 + usage(1) 9.234 + 9.235 +if rc != '': 9.236 + print "return code %d" % rc
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 10.2 +++ b/tools/examples/xm_dom_create.py Fri Jun 11 18:31:12 2004 +0000 10.3 @@ -0,0 +1,402 @@ 10.4 +#!/usr/bin/env python 10.5 + 10.6 +import string 10.7 +import sys 10.8 +import os 10.9 +import os.path 10.10 +import time 10.11 +import socket 10.12 +import getopt 10.13 +import signal 10.14 +import syslog 10.15 + 10.16 +import xenctl.console_client 10.17 + 10.18 +from xenmgr import sxp 10.19 +from xenmgr import PrettyPrint 10.20 +from xenmgr.XendClient import server 10.21 + 10.22 +config_dir = '/etc/xc/' 10.23 +config_file = xc_config_file = config_dir + 'defaults' 10.24 + 10.25 +def main_usage (): 10.26 + print >>sys.stderr,""" 10.27 +Usage: %s <args> 10.28 + 10.29 +This tool is used to create and start new domains. It reads defaults 10.30 +from a file written in Python, having allowed variables to be set and 10.31 +passed into the file. Further command line arguments allow the 10.32 +defaults to be overridden. The defaults for each parameter are listed 10.33 +in [] brackets. Arguments are as follows: 10.34 + 10.35 +Arguments to control the parsing of the defaults file: 10.36 + -f config_file -- Use the specified defaults script. 10.37 + Default: ['%s'] 10.38 + -L state_file -- Load virtual machine memory state from state_file 10.39 + -D foo=bar -- Set variable foo=bar before parsing config 10.40 + E.g. '-D vmid=3;ip=1.2.3.4' 10.41 + -h -- Print extended help message, including all arguments 10.42 + -n -- Dry run only, don't actually create domain 10.43 + Prints the config, suitable for -F. 10.44 + -q -- Quiet - write output only to the system log 10.45 + -F domain_config -- Build domain using the config in the file. 10.46 + Suitable files can be made using '-n' to output a config. 10.47 +""" % (sys.argv[0], xc_config_file) 10.48 + 10.49 +def extra_usage (): 10.50 + print >>sys.stderr,""" 10.51 +Arguments to override current config read from '%s': 10.52 + -c -- Turn into console terminal after domain is created 10.53 + -k image -- Path to kernel image ['%s'] 10.54 + -r ramdisk -- Path to ramdisk (or empty) ['%s'] 10.55 + -b builder_fn -- Function to use to build domain ['%s'] 10.56 + -m mem_size -- Initial memory allocation in MB [%dMB] 10.57 + -N domain_name -- Set textual name of domain ['%s'] 10.58 + -a auto_restart -- Restart domain on exit, yes/no ['%d'] 10.59 + -e vbd_expert -- Safety catch to avoid some disk accidents ['%s'] 10.60 + -d udisk,dev,rw -- Add disk, partition, or virtual disk to domain. E.g. to 10.61 + make partion sda4 available to the domain as hda1 with 10.62 + read-write access: '-d phy:sda4,hda1,rw' To add 10.63 + multiple disks use multiple -d flags or seperate with ';' 10.64 + Default: ['%s'] 10.65 + -i vfr_ipaddr -- Add IP address to the list which Xen will route to 10.66 + the domain. Use multiple times to add more IP addrs. 10.67 + Default: ['%s'] 10.68 + 10.69 +Args to override the kernel command line, which is concatenated from these: 10.70 + -I cmdline_ip -- Override 'ip=ipaddr:nfsserv:gateway:netmask::eth0:off' 10.71 + Default: ['%s'] 10.72 + -R cmdline_root -- Override root device parameters. 10.73 + Default: ['%s'] 10.74 + -E cmdline_extra -- Override extra kernel args and rc script env vars. 10.75 + Default: ['%s'] 10.76 + 10.77 +""" % (config_file, 10.78 + image, ramdisk, builder_fn, mem_size, domain_name, auto_restart, 10.79 + vbd_expert, 10.80 + printvbds( vbd_list ), 10.81 + reduce ( (lambda a,b: a+':'+b), vfr_ipaddr,'' )[1:], 10.82 + cmdline_ip, cmdline_root, cmdline_extra) 10.83 + 10.84 +def config_usage (): pass 10.85 + 10.86 +def answer ( s ): 10.87 + s = string.lower(s) 10.88 + if s == 'yes' or s == 'true' or s == '1': return 1 10.89 + return 0 10.90 + 10.91 +def printvbds ( v ): 10.92 + s='' 10.93 + for (a,b,c) in v: 10.94 + s = s + '; %s,%s,%s' % (a,b,c) 10.95 + return s[2:] 10.96 + 10.97 +def output(string): 10.98 + global quiet 10.99 + syslog.syslog(string) 10.100 + if not quiet: 10.101 + print string 10.102 + return 10.103 + 10.104 +bail=False; dryrun=False; extrahelp=False; quiet = False 10.105 +image=''; ramdisk=''; builder_fn='linux'; restore=0; state_file='' 10.106 +mem_size=0; domain_name=''; vfr_ipaddr=[]; 10.107 +vbd_expert='rr'; auto_restart=False; 10.108 +vbd_list = []; cmdline_ip = ''; cmdline_root=''; cmdline_extra='' 10.109 +pci_device_list = []; console_port = -1 10.110 +auto_console = False 10.111 +config_from_file = False 10.112 + 10.113 +##### Determine location of defaults file 10.114 +##### 10.115 + 10.116 +try: 10.117 + opts, args = getopt.getopt(sys.argv[1:], "h?nqcf:F:D:k:r:b:m:N:a:e:d:i:I:R:E:L:" ) 10.118 + 10.119 + for opt in opts: 10.120 + if opt[0] == '-f': config_file= opt[1] 10.121 + if opt[0] == '-h' or opt[0] == '-?' : bail=True; extrahelp=True 10.122 + if opt[0] == '-n': dryrun=True 10.123 + if opt[0] == '-D': 10.124 + for o in string.split( opt[1], ';' ): 10.125 + (l,r) = string.split( o, '=' ) 10.126 + exec "%s='%s'" % (l,r) 10.127 + if opt[0] == '-q': quiet = True 10.128 + if opt[0] == '-L': restore = True; state_file = opt[1] 10.129 + if opt[0] == '-F': config_from_file = True; domain_config = opt[1] 10.130 + 10.131 + 10.132 +except getopt.GetoptError: 10.133 + bail=True 10.134 + 10.135 +if not config_from_file: 10.136 + try: 10.137 + os.stat( config_file ) 10.138 + except: 10.139 + try: 10.140 + d = config_dir + config_file 10.141 + os.stat( d ) 10.142 + config_file = d 10.143 + except: 10.144 + print >> sys.stderr, "Unable to open config file '%s'" % config_file 10.145 + bail = True 10.146 + 10.147 + 10.148 +##### Parse the config file 10.149 +##### 10.150 + 10.151 +if not config_from_file: 10.152 + if not quiet: 10.153 + print "Parsing config file '%s'" % config_file 10.154 + 10.155 + try: 10.156 + execfile ( config_file ) 10.157 + except (AssertionError,IOError): 10.158 + print >>sys.stderr,"Exiting %s" % sys.argv[0] 10.159 + bail = True 10.160 + 10.161 +##### Print out config if necessary 10.162 +##### 10.163 + 10.164 +def bailout(): 10.165 + global extrahelp 10.166 + main_usage() 10.167 + config_usage() 10.168 + if extrahelp: extra_usage() 10.169 + sys.exit(1) 10.170 + 10.171 +if bail: 10.172 + bailout() 10.173 + 10.174 +##### Parse any command line overrides 10.175 +##### 10.176 + 10.177 +x_vbd_list = [] 10.178 +x_vfr_ipaddr = [] 10.179 + 10.180 +for opt in opts: 10.181 + if opt[0] == '-k': image = opt[1] 10.182 + if opt[0] == '-r': ramdisk = opt[1] 10.183 + if opt[0] == '-b': builder_fn = opt[1] 10.184 + if opt[0] == '-m': mem_size = int(opt[1]) 10.185 + if opt[0] == '-C': cpu = int(opt[1]) 10.186 + if opt[0] == '-N': domain_name = opt[1] 10.187 + if opt[0] == '-a': auto_restart = answer(opt[1]) 10.188 + if opt[0] == '-e': vbd_expert = opt[1] 10.189 + if opt[0] == '-I': cmdline_ip = opt[1] 10.190 + if opt[0] == '-R': cmdline_root = opt[1] 10.191 + if opt[0] == '-E': cmdline_extra = opt[1] 10.192 + if opt[0] == '-i': x_vfr_ipaddr.append(opt[1]) 10.193 + if opt[0] == '-c': auto_console = True 10.194 + if opt[0] == '-d': 10.195 + try: 10.196 + vv = string.split(opt[1],';') 10.197 + for v in vv: 10.198 + (udisk,dev,mode) = string.split(v,',') 10.199 + x_vbd_list.append( (udisk,dev,mode) ) 10.200 + except: 10.201 + print >>sys.stderr, "Invalid block device specification : %s" % opt[1] 10.202 + sys.exit(1) 10.203 + 10.204 +if x_vbd_list: vbd_list = x_vbd_list 10.205 +if x_vfr_ipaddr: vfr_ipaddr = x_vfr_ipaddr 10.206 + 10.207 +syslog.openlog('xc_dom_create.py %s' % config_file, 0, syslog.LOG_DAEMON) 10.208 + 10.209 +def strip(pre, s): 10.210 + if s.startswith(pre): 10.211 + return s[len(pre):] 10.212 + else: 10.213 + return s 10.214 + 10.215 +def make_domain_config(): 10.216 + global builder_fn, image, ramdisk, mem_size, domain_name 10.217 + global cpu 10.218 + global cmdline, cmdline_ip, cmdline_root 10.219 + global vfr_ipaddr, vbd_list, vbd_expert 10.220 + 10.221 + config = ['config', 10.222 + ['name', domain_name ], 10.223 + ['memory', mem_size ], 10.224 + ] 10.225 + if cpu: 10.226 + config.append(['cpu', cpu]) 10.227 + 10.228 + config_image = [ builder_fn ] 10.229 + config_image.append([ 'kernel', os.path.abspath(image) ]) 10.230 + if ramdisk: 10.231 + config_image.append([ 'ramdisk', os.path.abspath(ramdisk) ]) 10.232 + if cmdline_ip: 10.233 + cmdline_ip = strip("ip=", cmdline_ip) 10.234 + config_image.append(['ip', cmdline_ip]) 10.235 + if cmdline_root: 10.236 + cmdline_root = strip("root=", cmdline_root) 10.237 + config_image.append(['root', cmdline_root]) 10.238 + if cmdline_extra: 10.239 + config_image.append(['args', cmdline_extra]) 10.240 + config.append(['image', config_image ]) 10.241 + 10.242 + config_devs = [] 10.243 + for (uname, dev, mode) in vbd_list: 10.244 + config_vbd = ['vbd', 10.245 + ['uname', uname], 10.246 + ['dev', dev ], 10.247 + ['mode', mode ] ] 10.248 + if vbd_expert != 'rr': 10.249 + config_vbd.append(['sharing', vbd_expert]) 10.250 + config_devs.append(['device', config_vbd]) 10.251 + 10.252 + for (bus, dev, func) in pci_device_list: 10.253 + config_pci = ['pci', 10.254 + ['bus', bus ], 10.255 + ['dev', dev ], 10.256 + ['func', func] ] 10.257 + config_devs.append(['device', config_pci]) 10.258 + 10.259 + config += config_devs 10.260 + 10.261 + config_vfr = ['vfr'] 10.262 + idx = 0 # No way of saying which IP is for which vif? 10.263 + for ip in vfr_ipaddr: 10.264 + config_vfr.append(['vif', ['id', idx], ['ip', ip]]) 10.265 + 10.266 + config.append(config_vfr) 10.267 + return config 10.268 + 10.269 +def parse_config_file(domain_file): 10.270 + config = None 10.271 + fin = None 10.272 + try: 10.273 + fin = file(domain_file, "rb") 10.274 + config = sxp.parse(fin) 10.275 + if len(config) >= 1: 10.276 + config = config[0] 10.277 + else: 10.278 + raise StandardError("Invalid configuration") 10.279 + except StandardError, ex: 10.280 + print >> sys.stderr, "Error :", ex 10.281 + sys.exit(1) 10.282 + #finally: 10.283 + if fin: fin.close() 10.284 + return config 10.285 + 10.286 +# This function creates, builds and starts a domain, using the values 10.287 +# in the global variables, set above. It is used in the subsequent 10.288 +# code for starting the new domain and rebooting it if appropriate. 10.289 +def make_domain(config): 10.290 + """Create, build and start a domain. 10.291 + Returns: [int] the ID of the new domain. 10.292 + """ 10.293 + global restore 10.294 + 10.295 + if restore: 10.296 + dominfo = server.xend_domain_restore(state_file, config) 10.297 + else: 10.298 + dominfo = server.xend_domain_create(config) 10.299 + 10.300 + dom = int(sxp.child_value(dominfo, 'id')) 10.301 + console_info = sxp.child(dominfo, 'console') 10.302 + if console_info: 10.303 + console_port = int(sxp.child_value(console_info, 'port')) 10.304 + else: 10.305 + console_port = None 10.306 + 10.307 + if server.xend_domain_start(dom) < 0: 10.308 + print "Error starting domain" 10.309 + server.xend_domain_halt(dom) 10.310 + sys.exit() 10.311 + 10.312 + return (dom, console_port) 10.313 + 10.314 +PID_DIR = '/var/run/xendomains/' 10.315 + 10.316 +def pidfile(dom): 10.317 + return PID_DIR + '%d.pid' % dom 10.318 + 10.319 +def mkpidfile(): 10.320 + global current_id 10.321 + if not os.path.isdir(PID_DIR): 10.322 + os.mkdir(PID_DIR) 10.323 + 10.324 + fd = open(pidfile(current_id), 'w') 10.325 + print >> fd, str(os.getpid()) 10.326 + fd.close() 10.327 + return 10.328 + 10.329 +def rmpidfile(): 10.330 + global current_id 10.331 + os.unlink(pidfile(current_id)) 10.332 + 10.333 +def death_handler(dummy1,dummy2): 10.334 + global current_id 10.335 + os.unlink(pidfile(current_id)) 10.336 + output('Auto-restart daemon: daemon PID = %d for domain %d is now exiting' 10.337 + % (os.getpid(), current_id)) 10.338 + sys.exit(0) 10.339 + return 10.340 + 10.341 +#============================================================================ 10.342 +# The starting / monitoring of the domain actually happens here... 10.343 + 10.344 +if config_from_file: 10.345 + config = parse_config_file(domain_config) 10.346 +else: 10.347 + config = make_domain_config() 10.348 + 10.349 +if dryrun: 10.350 + print "# %s" % ' '.join(sys.argv) 10.351 + PrettyPrint.prettyprint(config) 10.352 + sys.exit(0) 10.353 +elif quiet: 10.354 + pass 10.355 +else: 10.356 + PrettyPrint.prettyprint(config) 10.357 + 10.358 +# start the domain and record its ID number 10.359 +(current_id, current_port) = make_domain(config) 10.360 + 10.361 +def start_msg(prefix, dom, port): 10.362 + output(prefix + "VM started in domain %d" % dom) 10.363 + if port: 10.364 + output(prefix + "Console I/O available on TCP port %d." % port) 10.365 + 10.366 +start_msg('', current_id, current_port) 10.367 + 10.368 +if current_port and auto_console: 10.369 + xenctl.console_client.connect('127.0.0.1', current_port) 10.370 + 10.371 +# if the auto_restart flag is set then keep polling to see if the domain is 10.372 +# alive - restart if it is not by calling make_domain() again (it's necessary 10.373 +# to update the id variable, since the new domain may have a new ID) 10.374 + 10.375 +#todo: Replace this - get xend to watch them. 10.376 +if auto_restart: 10.377 + ARD = "Auto-restart daemon: " 10.378 + # turn ourselves into a background daemon 10.379 + try: 10.380 + pid = os.fork() 10.381 + if pid > 0: 10.382 + sys.exit(0) 10.383 + os.setsid() 10.384 + pid = os.fork() 10.385 + if pid > 0: 10.386 + output(ARD + 'PID = %d' % pid) 10.387 + sys.exit(0) 10.388 + signal.signal(signal.SIGTERM,death_handler) 10.389 + except OSError: 10.390 + print >> sys.stderr, ARD+'Startup failed' 10.391 + sys.exit(1) 10.392 + 10.393 + mkpidfile() 10.394 + 10.395 + while True: 10.396 + time.sleep(1) 10.397 + # todo: use new interface 10.398 + info = xc.domain_getinfo(current_id, 1) 10.399 + if info == [] or info[0]['dom'] != current_id: 10.400 + output(ARD + "Domain %d terminated, restarting VM in new domain" 10.401 + % current_id) 10.402 + rmpidfile() 10.403 + (current_id, current_port) = make_domain() 10.404 + mkpidfile() 10.405 + start_msg(ARD, current_id, current_port)
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 11.2 +++ b/tools/examples/xm_vd_tool.py Fri Jun 11 18:31:12 2004 +0000 11.3 @@ -0,0 +1,157 @@ 11.4 +#!/usr/bin/env python 11.5 + 11.6 +import sys 11.7 +import re 11.8 +import string 11.9 + 11.10 +from xenctl import vdisk 11.11 + 11.12 +def usage(): 11.13 + 11.14 + print >>sys.stderr,""" 11.15 +Usage: %s command <params> 11.16 + 11.17 + initialise [dev] [[ext_size]] - init. a physcial partition to store vd's 11.18 + create [size] [[expiry]] - allocate a vd of specified size (and expiry) 11.19 + enlarge [vdid] [extra_size] - enlarge a specified vd by some amount 11.20 + delete [vdid] - delete a vd 11.21 + import [filename] [[expiry]] - create a vd and populate w/ image from file 11.22 + export [vdid] [filename] - copy vd's contents to a file 11.23 + setexpiry [vdid] [[expiry]] - update the expiry time for a vd 11.24 + list - list all the unexpired virtual disks 11.25 + undelete [vdid] [[expiry]] - attempts to recover an expired vd 11.26 + freespace - print out the amount of space in free pool 11.27 + 11.28 +notes: 11.29 + vdid - the virtual disk's identity string 11.30 + size - measured in MB 11.31 + expiry - is the expiry time of the virtual disk in seconds from now 11.32 + (0 = don't expire) 11.33 + device - physical partition to 'format' to hold vd's. e.g. hda4 11.34 + ext_size - extent size (default 64MB) 11.35 +""" % sys.argv[0] 11.36 + 11.37 +if len(sys.argv) < 2: 11.38 + usage() 11.39 + sys.exit(-1) 11.40 + 11.41 +rc='' 11.42 +src='' 11.43 +expiry_time = 0 11.44 +cmd = sys.argv[1] 11.45 + 11.46 +if cmd == 'initialise': 11.47 + 11.48 + dev = sys.argv[2] 11.49 + 11.50 + if len(sys.argv) > 3: 11.51 + extent_size = int(sys.argv[3]) 11.52 + else: 11.53 + print """No extent size specified - using default size of 64MB""" 11.54 + extent_size = 64 11.55 + 11.56 + print "Formatting for virtual disks" 11.57 + print "Device: " + dev 11.58 + print "Extent size: " + str(extent_size) + "MB" 11.59 + 11.60 + rc = vdisk.vd_format(dev, extent_size) 11.61 + 11.62 +elif cmd == 'create': 11.63 + 11.64 + size = int(sys.argv[2]) 11.65 + 11.66 + if len(sys.argv) > 3: 11.67 + expiry_time = int(sys.argv[3]) 11.68 + 11.69 + print "Creating a virtual disk" 11.70 + print "Size: %d" % size 11.71 + print "Expiry time (seconds from now): %d" % expiry_time 11.72 + 11.73 + src = vdisk.vd_create(size, expiry_time) 11.74 + 11.75 +elif cmd == 'enlarge': 11.76 + 11.77 + id = sys.argv[2] 11.78 + 11.79 + extra_size = int(sys.argv[3]) 11.80 + 11.81 + rc = vdisk.vd_enlarge(id, extra_size) 11.82 + 11.83 +elif cmd == 'delete': 11.84 + 11.85 + id = sys.argv[2] 11.86 + 11.87 + print "Deleting a virtual disk with ID: " + id 11.88 + 11.89 + rc = vdisk.vd_delete(id) 11.90 + 11.91 +elif cmd == 'import': 11.92 + 11.93 + file = sys.argv[2] 11.94 + 11.95 + if len(sys.argv) > 3: 11.96 + expiry_time = int(sys.argv[3]) 11.97 + 11.98 + print "Allocate new virtual disk and populate from file : %s" % file 11.99 + 11.100 + print vdisk.vd_read_from_file(file, expiry_time) 11.101 + 11.102 +elif cmd == 'export': 11.103 + 11.104 + id = sys.argv[2] 11.105 + file = sys.argv[3] 11.106 + 11.107 + print "Dump contents of virtual disk to file : %s" % file 11.108 + 11.109 + rc = vdisk.vd_cp_to_file(id, file ) 11.110 + 11.111 +elif cmd == 'setexpiry': 11.112 + 11.113 + id = sys.argv[2] 11.114 + 11.115 + if len(sys.argv) > 3: 11.116 + expiry_time = int(sys.argv[3]) 11.117 + 11.118 + print "Refreshing a virtual disk" 11.119 + print "Id: " + id 11.120 + print "Expiry time (seconds from now [or 0]): " + str(expiry_time) 11.121 + 11.122 + rc = vdisk.vd_refresh(id, expiry_time) 11.123 + 11.124 +elif cmd == 'list': 11.125 + print 'ID Size(MB) Expiry' 11.126 + 11.127 + for vbd in vdisk.vd_list(): 11.128 + vbd['size_mb'] = vbd['size'] / vdisk.VBD_SECTORS_PER_MB 11.129 + vbd['expiry'] = (vbd['expires'] and vbd['expiry_time']) or 'never' 11.130 + print '%(vdisk_id)-4s %(size_mb)-12d %(expiry)s' % vbd 11.131 + 11.132 +elif cmd == 'freespace': 11.133 + 11.134 + print vdisk.vd_freespace() 11.135 + 11.136 +elif cmd == 'undelete': 11.137 + 11.138 + id = sys.argv[2] 11.139 + 11.140 + if len(sys.argv) > 3: 11.141 + expiry_time = int(sys.argv[3]) 11.142 + 11.143 + if vdisk.vd_undelete(id, expiry_time): 11.144 + print "Undelete operation failed for virtual disk: " + id 11.145 + else: 11.146 + print "Undelete operation succeeded for virtual disk: " + id 11.147 + 11.148 +else: 11.149 + usage() 11.150 + sys.exit(-1) 11.151 + 11.152 + 11.153 +if src != '': 11.154 + print "Returned virtual disk id is : %s" % src 11.155 + 11.156 +if rc != '': 11.157 + print "return code %d" % rc 11.158 + 11.159 + 11.160 +
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 12.2 +++ b/tools/xenctl/lib/ip.py Fri Jun 11 18:31:12 2004 +0000 12.3 @@ -0,0 +1,95 @@ 12.4 +import os 12.5 +import re 12.6 +import socket 12.7 +import struct 12.8 + 12.9 +##### Networking-related functions 12.10 + 12.11 +def get_current_ipaddr(dev='eth0'): 12.12 + """Return a string containing the primary IP address for the given 12.13 + network interface (default 'eth0'). 12.14 + """ 12.15 + fd = os.popen( '/sbin/ifconfig ' + dev + ' 2>/dev/null' ) 12.16 + lines = readlines(fd) 12.17 + for line in lines: 12.18 + m = re.search( '^\s+inet addr:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*', 12.19 + line ) 12.20 + if m: 12.21 + return m.group(1) 12.22 + return None 12.23 + 12.24 +def get_current_ipmask(dev='eth0'): 12.25 + """Return a string containing the primary IP netmask for the given 12.26 + network interface (default 'eth0'). 12.27 + """ 12.28 + fd = os.popen( '/sbin/ifconfig ' + dev + ' 2>/dev/null' ) 12.29 + lines = readlines(fd) 12.30 + for line in lines: 12.31 + m = re.search( '^.+Mask:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*', 12.32 + line ) 12.33 + if m: 12.34 + return m.group(1) 12.35 + return None 12.36 + 12.37 +def get_current_ipgw(dev='eth0'): 12.38 + """Return a string containing the IP gateway for the given 12.39 + network interface (default 'eth0'). 12.40 + """ 12.41 + fd = os.popen( '/sbin/route -n' ) 12.42 + lines = readlines(fd) 12.43 + for line in lines: 12.44 + m = re.search( '^\S+\s+([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)' + 12.45 + '\s+\S+\s+\S*G.*' + dev + '.*', line ) 12.46 + if m: 12.47 + return m.group(1) 12.48 + return None 12.49 + 12.50 +def setup_vfr_rules_for_vif(dom,vif,addr): 12.51 + """Takes a tuple ( domain-id, vif-id, ip-addr ), where the ip-addr 12.52 + is expressed as a textual dotted quad, and set up appropriate routing 12.53 + rules in Xen. No return value. 12.54 + """ 12.55 + fd = os.open( '/proc/xen/vfr', os.O_WRONLY ) 12.56 + if ( re.search( '169\.254', addr) ): 12.57 + os.write( fd, 'ADD ACCEPT srcaddr=' + addr + 12.58 + ' srcaddrmask=255.255.255.255' + 12.59 + ' srcdom=' + str(dom) + ' srcidx=' + str(vif) + 12.60 + ' dstdom=0 dstidx=0 proto=any\n' ) 12.61 + else: 12.62 + os.write( fd, 'ADD ACCEPT srcaddr=' + addr + 12.63 + ' srcaddrmask=255.255.255.255' + 12.64 + ' srcdom=' + str(dom) + ' srcidx=' + str(vif) + 12.65 + ' dst=PHYS proto=any\n' ) 12.66 + os.write( fd, 'ADD ACCEPT dstaddr=' + addr + 12.67 + ' dstaddrmask=255.255.255.255' + 12.68 + ' src=ANY' + 12.69 + ' dstdom=' + str(dom) + ' dstidx=' + str(vif) + 12.70 + ' proto=any\n' ) 12.71 + os.close( fd ) 12.72 + return None 12.73 + 12.74 +def inet_aton(addr): 12.75 + """Convert an IP addr in IPv4 dot notation into an int. 12.76 + """ 12.77 + b = socket.inet_aton(addr) 12.78 + return struct.unpack('!I', b)[0] 12.79 + 12.80 +def inet_ntoa(n): 12.81 + """Convert an int into an IP addr in IPv4 dot notation. 12.82 + """ 12.83 + b = struct.pack('!I', n) 12.84 + return socket.inet_ntoa(b) 12.85 + 12.86 +def add_offset_to_ip(addr, offset): 12.87 + """Add a numerical offset to an IP addr in IPv4 dot notation. 12.88 + """ 12.89 + n = inet_aton(addr) 12.90 + n += offset 12.91 + return inet_ntoa(n) 12.92 + 12.93 +def check_subnet( ip, network, netmask ): 12.94 + n_ip = inet_aton(ip) 12.95 + n_net = inet_aton(network) 12.96 + n_mask = inet_aton(netmask) 12.97 + return (n_ip & n_mask) == (n_net & n_mask) 12.98 +
13.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 13.2 +++ b/tools/xenctl/lib/vdisk.py Fri Jun 11 18:31:12 2004 +0000 13.3 @@ -0,0 +1,944 @@ 13.4 +import os 13.5 +import re 13.6 +import socket 13.7 +import string 13.8 +import sys 13.9 +import tempfile 13.10 +import struct 13.11 + 13.12 +##### Module variables 13.13 + 13.14 +"""Location of the Virtual Disk management database. 13.15 + defaults to /var/db/xen_vdisks.sqlite 13.16 +""" 13.17 +VD_DB_FILE = "/var/db/xen_vdisks.sqlite" 13.18 + 13.19 +"""VBD expertise level - determines the strictness of the sanity checking. 13.20 + This mode determines the level of complaints when disk sharing occurs 13.21 + through the current VBD mappings. 13.22 + 0 - only allow shared mappings if both domains have r/o access (always OK) 13.23 + 1 - also allow sharing with one dom r/w and the other r/o 13.24 + 2 - allow sharing with both doms r/w 13.25 +""" 13.26 +VBD_SAFETY_RR = 0 13.27 +VBD_SAFETY_RW = 1 13.28 +VBD_SAFETY_WW = 2 13.29 + 13.30 +VBD_SECTORS_PER_MB = 2048 13.31 + 13.32 +##### Module initialisation 13.33 + 13.34 +try: 13.35 + # try to import sqlite (not everyone will have it installed) 13.36 + import sqlite 13.37 +except ImportError: 13.38 + # on failure, just catch the error, don't do anything 13.39 + pass 13.40 + 13.41 + 13.42 + 13.43 +##### VBD-related Functions 13.44 + 13.45 +def blkdev_name_to_number(name): 13.46 + """Take the given textual block-device name (e.g., '/dev/sda1', 13.47 + 'hda') and return the device number used by the OS. """ 13.48 + 13.49 + if not re.match( '/dev/', name ): 13.50 + name = '/dev/' + name 13.51 + 13.52 + return os.stat(name).st_rdev 13.53 + 13.54 +# lookup_blkdev_partn_info( '/dev/sda3' ) 13.55 +def lookup_raw_partn(partition): 13.56 + """Take the given block-device name (e.g., '/dev/sda1', 'hda') 13.57 + and return a dictionary { device, start_sector, 13.58 + nr_sectors, type } 13.59 + device: Device number of the given partition 13.60 + start_sector: Index of first sector of the partition 13.61 + nr_sectors: Number of sectors comprising this partition 13.62 + type: 'Disk' or identifying name for partition type 13.63 + """ 13.64 + 13.65 + if not re.match( '/dev/', partition ): 13.66 + partition = '/dev/' + partition 13.67 + 13.68 + drive = re.split( '[0-9]', partition )[0] 13.69 + 13.70 + if drive == partition: 13.71 + fd = os.popen( '/sbin/sfdisk -s ' + drive + ' 2>/dev/null' ) 13.72 + line = readline(fd) 13.73 + if line: 13.74 + return [ { 'device' : blkdev_name_to_number(drive), 13.75 + 'start_sector' : long(0), 13.76 + 'nr_sectors' : long(line) * 2, 13.77 + 'type' : 'Disk' } ] 13.78 + return None 13.79 + 13.80 + # determine position on disk 13.81 + fd = os.popen( '/sbin/sfdisk -d ' + drive + ' 2>/dev/null' ) 13.82 + 13.83 + #['/dev/sda3 : start= 16948575, size=16836120, Id=83, bootable\012'] 13.84 + lines = readlines(fd) 13.85 + for line in lines: 13.86 + m = re.search( '^' + partition + '\s*: start=\s*([0-9]+), ' + 13.87 + 'size=\s*([0-9]+), Id=\s*(\S+).*$', line) 13.88 + if m: 13.89 + return [ { 'device' : blkdev_name_to_number(drive), 13.90 + 'start_sector' : long(m.group(1)), 13.91 + 'nr_sectors' : long(m.group(2)), 13.92 + 'type' : m.group(3) } ] 13.93 + 13.94 + return None 13.95 + 13.96 +def lookup_disk_uname( uname ): 13.97 + """Lookup a list of segments for either a physical or a virtual device. 13.98 + uname [string]: name of the device in the format \'vd:id\' for a virtual 13.99 + disk, or \'phy:dev\' for a physical device 13.100 + returns [list of dicts]: list of extents that make up the named device 13.101 + """ 13.102 + ( type, d_name ) = string.split( uname, ':' ) 13.103 + 13.104 + if type == "phy": 13.105 + segments = lookup_raw_partn( d_name ) 13.106 + elif type == "vd": 13.107 + segments = vd_lookup( d_name ) 13.108 + 13.109 + return segments 13.110 + 13.111 + 13.112 +##### VD Management-related functions 13.113 + 13.114 +##### By Mark Williamson, <mark.a.williamson@intel.com> 13.115 +##### (C) Intel Research Cambridge 13.116 + 13.117 +# TODO: 13.118 +# 13.119 +# Plenty of room for enhancement to this functionality (contributions 13.120 +# welcome - and then you get to have your name in the source ;-)... 13.121 +# 13.122 +# vd_unformat() : want facilities to unallocate virtual disk 13.123 +# partitions, possibly migrating virtual disks of them, with checks to see if 13.124 +# it's safe and options to force it anyway 13.125 +# 13.126 +# vd_create() : should have an optional argument specifying a physical 13.127 +# disk preference - useful to allocate for guest doms to do RAID 13.128 +# 13.129 +# vd_undelete() : add ability to "best effort" undelete as much of a 13.130 +# vdisk as is left in the case that some of it has already been 13.131 +# reallocated. Some people might still be able to recover some of 13.132 +# their data this way, even if some of the disk has disappeared. 13.133 +# 13.134 +# It'd be nice if we could wipe virtual disks for security purposes - 13.135 +# should be easy to do this using dev if=/dev/{zero,random} on each 13.136 +# extent in turn. There could be another optional flag to vd_create 13.137 +# in order to allow this. 13.138 +# 13.139 +# Error codes could be more expressive - i.e. actually tell why the 13.140 +# error occurred rather than "it broke". Currently the code avoids 13.141 +# using exceptions to make control scripting simpler and more 13.142 +# accessible to beginners - therefore probably should just use more 13.143 +# return codes. 13.144 +# 13.145 +# Enhancements / additions to the example scripts are also welcome: 13.146 +# some people will interact with this code mostly through those 13.147 +# scripts. 13.148 +# 13.149 +# More documentation of how this stuff should be used is always nice - 13.150 +# if you have a novel configuration that you feel isn't discussed 13.151 +# enough in the HOWTO (which is currently a work in progress), feel 13.152 +# free to contribute a walkthrough, or something more substantial. 13.153 +# 13.154 + 13.155 + 13.156 +def __vd_no_database(): 13.157 + """Called when no database found - exits with an error 13.158 + """ 13.159 + print >> sys.stderr, "ERROR: Could not locate the database file at " + VD_DB_FILE 13.160 + sys.exit(1) 13.161 + 13.162 +def readlines(fd): 13.163 + """Version of readlines safe against EINTR. 13.164 + """ 13.165 + import errno 13.166 + 13.167 + lines = [] 13.168 + while 1: 13.169 + try: 13.170 + line = fd.readline() 13.171 + except IOError, ex: 13.172 + if ex.errno == errno.EINTR: 13.173 + continue 13.174 + else: 13.175 + raise 13.176 + if line == '': break 13.177 + lines.append(line) 13.178 + return lines 13.179 + 13.180 +def readline(fd): 13.181 + """Version of readline safe against EINTR. 13.182 + """ 13.183 + while 1: 13.184 + try: 13.185 + return fd.readline() 13.186 + except IOError, ex: 13.187 + if ex.errno == errno.EINTR: 13.188 + continue 13.189 + else: 13.190 + raise 13.191 + 13.192 + 13.193 +def vd_format(partition, extent_size_mb): 13.194 + """Format a partition or drive for use a virtual disk storage. 13.195 + partition [string]: device file representing the partition 13.196 + extent_size_mb [string]: extent size in megabytes to use on this disk 13.197 + """ 13.198 + 13.199 + if not os.path.isfile(VD_DB_FILE): 13.200 + vd_init_db(VD_DB_FILE) 13.201 + 13.202 + if not re.match( '/dev/', partition ): 13.203 + partition = '/dev/' + partition 13.204 + 13.205 + cx = sqlite.connect(VD_DB_FILE) 13.206 + cu = cx.cursor() 13.207 + 13.208 + cu.execute("select * from vdisk_part where partition = \'" 13.209 + + partition + "\'") 13.210 + row = cu.fetchone() 13.211 + 13.212 + extent_size = extent_size_mb * VBD_SECTORS_PER_MB # convert megabytes to sectors 13.213 + 13.214 + if not row: 13.215 + part_info = lookup_raw_partn(partition)[0] 13.216 + 13.217 + cu.execute("INSERT INTO vdisk_part(partition, part_id, extent_size) " + 13.218 + "VALUES ( \'" + partition + "\', " 13.219 + + str(blkdev_name_to_number(partition)) 13.220 + + ", " + str(extent_size) + ")") 13.221 + 13.222 + 13.223 + cu.execute("SELECT max(vdisk_extent_no) FROM vdisk_extents " 13.224 + + "WHERE vdisk_id = 0") 13.225 + 13.226 + max_id, = cu.fetchone() 13.227 + 13.228 + if max_id != None: 13.229 + new_id = max_id + 1 13.230 + else: 13.231 + new_id = 0 13.232 + 13.233 + num_extents = part_info['nr_sectors'] / extent_size 13.234 + 13.235 + for i in range(num_extents): 13.236 + sql ="""INSERT INTO vdisk_extents(vdisk_extent_no, vdisk_id, 13.237 + part_id, part_extent_no) 13.238 + VALUES ("""+ str(new_id + i) + ", 0, "\ 13.239 + + str(blkdev_name_to_number(partition))\ 13.240 + + ", " + str(num_extents - (i + 1)) + ")" 13.241 + cu.execute(sql) 13.242 + 13.243 + cx.commit() 13.244 + cx.close() 13.245 + return 0 13.246 + 13.247 + 13.248 +def vd_create(size_mb, expiry): 13.249 + """Create a new virtual disk. 13.250 + size_mb [int]: size in megabytes for the new virtual disk 13.251 + expiry [int]: expiry time in seconds from now 13.252 + """ 13.253 + 13.254 + if not os.path.isfile(VD_DB_FILE): 13.255 + __vd_no_database() 13.256 + 13.257 + cx = sqlite.connect(VD_DB_FILE) 13.258 + cu = cx.cursor() 13.259 + 13.260 + size = size_mb * VBD_SECTORS_PER_MB 13.261 + 13.262 + cu.execute("SELECT max(vdisk_id) FROM vdisks") 13.263 + max_id, = cu.fetchone() 13.264 + new_id = int(max_id) + 1 13.265 + 13.266 + # fetch a list of extents from the expired disks, along with information 13.267 + # about their size 13.268 + cu.execute("""SELECT vdisks.vdisk_id, vdisk_extent_no, part_extent_no, 13.269 + vdisk_extents.part_id, extent_size 13.270 + FROM vdisks NATURAL JOIN vdisk_extents 13.271 + NATURAL JOIN vdisk_part 13.272 + WHERE expires AND expiry_time <= datetime('now') 13.273 + ORDER BY expiry_time ASC, vdisk_extent_no DESC 13.274 + """) # aims to reuse the last extents 13.275 + # from the longest-expired disks first 13.276 + 13.277 + allocated = 0 13.278 + 13.279 + if expiry: 13.280 + expiry_ts = "datetime('now', '" + str(expiry) + " seconds')" 13.281 + expires = 1 13.282 + else: 13.283 + expiry_ts = "NULL" 13.284 + expires = 0 13.285 + 13.286 + # we'll use this to build the SQL statement we want 13.287 + building_sql = "INSERT INTO vdisks(vdisk_id, size, expires, expiry_time)" \ 13.288 + +" VALUES ("+str(new_id)+", "+str(size)+ ", " \ 13.289 + + str(expires) + ", " + expiry_ts + "); " 13.290 + 13.291 + counter = 0 13.292 + 13.293 + while allocated < size: 13.294 + row = cu.fetchone() 13.295 + if not row: 13.296 + print "ran out of space, having allocated %d meg of %d" % (allocated, size) 13.297 + cx.close() 13.298 + return -1 13.299 + 13.300 + 13.301 + (vdisk_id, vdisk_extent_no, part_extent_no, part_id, extent_size) = row 13.302 + allocated += extent_size 13.303 + building_sql += "UPDATE vdisk_extents SET vdisk_id = " + str(new_id) \ 13.304 + + ", " + "vdisk_extent_no = " + str(counter) \ 13.305 + + " WHERE vdisk_extent_no = " + str(vdisk_extent_no) \ 13.306 + + " AND vdisk_id = " + str(vdisk_id) + "; " 13.307 + 13.308 + counter += 1 13.309 + 13.310 + 13.311 + # this will execute the SQL query we build to store details of the new 13.312 + # virtual disk and allocate space to it print building_sql 13.313 + cu.execute(building_sql) 13.314 + 13.315 + cx.commit() 13.316 + cx.close() 13.317 + return str(new_id) 13.318 + 13.319 + 13.320 +def vd_lookup(id): 13.321 + """Lookup a Virtual Disk by ID. 13.322 + id [string]: a virtual disk identifier 13.323 + Returns [list of dicts]: a list of extents as dicts, containing fields: 13.324 + device : Linux device number of host disk 13.325 + start_sector : within the device 13.326 + nr_sectors : size of this extent 13.327 + type : set to \'VD Extent\' 13.328 + 13.329 + part_device : Linux device no of host partition 13.330 + part_start_sector : within the partition 13.331 + """ 13.332 + 13.333 + if not os.path.isfile(VD_DB_FILE): 13.334 + __vd_no_database() 13.335 + 13.336 + cx = sqlite.connect(VD_DB_FILE) 13.337 + cu = cx.cursor() 13.338 + 13.339 + cu.execute("-- types int") 13.340 + cu.execute("""SELECT COUNT(*) 13.341 + FROM vdisks 13.342 + WHERE (expiry_time > datetime('now') OR NOT expires) 13.343 + AND vdisk_id = """ + id) 13.344 + count, = cu.fetchone() 13.345 + 13.346 + if not count: 13.347 + cx.close() 13.348 + return None 13.349 + 13.350 + cu.execute("SELECT size from vdisks WHERE vdisk_id = " + id) 13.351 + real_size, = cu.fetchone() 13.352 + 13.353 + # This query tells PySQLite how to convert the data returned from the 13.354 + # following query - the use of the multiplication confuses it otherwise ;-) 13.355 + # This row is significant to PySQLite but is syntactically an SQL comment. 13.356 + 13.357 + cu.execute("-- types str, int, int, int") 13.358 + 13.359 + # This SQL statement is designed so that when the results are fetched they 13.360 + # will be in the right format to return immediately. 13.361 + cu.execute("""SELECT partition, vdisk_part.part_id, 13.362 + round(part_extent_no * extent_size) as start, 13.363 + extent_size 13.364 + 13.365 + FROM vdisks NATURAL JOIN vdisk_extents 13.366 + NATURAL JOIN vdisk_part 13.367 + 13.368 + WHERE vdisk_extents.vdisk_id = """ + id 13.369 + + " ORDER BY vdisk_extents.vdisk_extent_no ASC" 13.370 + ) 13.371 + 13.372 + extent_tuples = cu.fetchall() 13.373 + 13.374 + # use this function to map the results from the database into a dict 13.375 + # list of extents, for consistency with the rest of the code 13.376 + def transform ((partition, part_device, part_offset, nr_sectors)): 13.377 + return { 13.378 + # the disk device this extent is on - for passing to Xen 13.379 + 'device' : lookup_raw_partn(partition)[0]['device'], 13.380 + # the offset of this extent within the disk - for passing to Xen 13.381 + 'start_sector' : long(part_offset + lookup_raw_partn(partition)[0]['start_sector']), 13.382 + # extent size, in sectors 13.383 + 'nr_sectors' : nr_sectors, 13.384 + # partition device this extent is on (useful to know for xenctl.utils fns) 13.385 + 'part_device' : part_device, 13.386 + # start sector within this partition (useful to know for xenctl.utils fns) 13.387 + 'part_start_sector' : part_offset, 13.388 + # type of this extent - handy to know 13.389 + 'type' : 'VD Extent' } 13.390 + 13.391 + cx.commit() 13.392 + cx.close() 13.393 + 13.394 + extent_dicts = map(transform, extent_tuples) 13.395 + 13.396 + # calculate the over-allocation in sectors (happens because 13.397 + # we allocate whole extents) 13.398 + allocated_size = 0 13.399 + for i in extent_dicts: 13.400 + allocated_size += i['nr_sectors'] 13.401 + 13.402 + over_allocation = allocated_size - real_size 13.403 + 13.404 + # trim down the last extent's length so the resulting VBD will be the 13.405 + # size requested, rather than being rounded up to the nearest extent 13.406 + extent_dicts[len(extent_dicts) - 1]['nr_sectors'] -= over_allocation 13.407 + 13.408 + return extent_dicts 13.409 + 13.410 + 13.411 +def vd_enlarge(vdisk_id, extra_size_mb): 13.412 + """Create a new virtual disk. 13.413 + vdisk_id [string] : ID of the virtual disk to enlarge 13.414 + extra_size_mb [int]: size in megabytes to increase the allocation by 13.415 + returns [int] : 0 on success, otherwise non-zero 13.416 + """ 13.417 + 13.418 + if not os.path.isfile(VD_DB_FILE): 13.419 + __vd_no_database() 13.420 + 13.421 + cx = sqlite.connect(VD_DB_FILE) 13.422 + cu = cx.cursor() 13.423 + 13.424 + extra_size = extra_size_mb * VBD_SECTORS_PER_MB 13.425 + 13.426 + cu.execute("-- types int") 13.427 + cu.execute("SELECT COUNT(*) FROM vdisks WHERE vdisk_id = " + vdisk_id 13.428 + + " AND (expiry_time > datetime('now') OR NOT expires)") 13.429 + count, = cu.fetchone() 13.430 + 13.431 + if not count: # no such vdisk 13.432 + cx.close() 13.433 + return -1 13.434 + 13.435 + cu.execute("-- types int") 13.436 + cu.execute("""SELECT SUM(extent_size) 13.437 + FROM vdisks NATURAL JOIN vdisk_extents 13.438 + NATURAL JOIN vdisk_part 13.439 + WHERE vdisks.vdisk_id = """ + vdisk_id) 13.440 + 13.441 + real_size, = cu.fetchone() # get the true allocated size 13.442 + 13.443 + cu.execute("-- types int") 13.444 + cu.execute("SELECT size FROM vdisks WHERE vdisk_id = " + vdisk_id) 13.445 + 13.446 + old_size, = cu.fetchone() 13.447 + 13.448 + 13.449 + cu.execute("--- types int") 13.450 + cu.execute("""SELECT MAX(vdisk_extent_no) 13.451 + FROM vdisk_extents 13.452 + WHERE vdisk_id = """ + vdisk_id) 13.453 + 13.454 + counter = cu.fetchone()[0] + 1 # this stores the extent numbers 13.455 + 13.456 + 13.457 + # because of the extent-based allocation, the VD may already have more 13.458 + # allocated space than they asked for. Find out how much we really 13.459 + # need to add. 13.460 + add_size = extra_size + old_size - real_size 13.461 + 13.462 + # fetch a list of extents from the expired disks, along with information 13.463 + # about their size 13.464 + cu.execute("""SELECT vdisks.vdisk_id, vdisk_extent_no, part_extent_no, 13.465 + vdisk_extents.part_id, extent_size 13.466 + FROM vdisks NATURAL JOIN vdisk_extents 13.467 + NATURAL JOIN vdisk_part 13.468 + WHERE expires AND expiry_time <= datetime('now') 13.469 + ORDER BY expiry_time ASC, vdisk_extent_no DESC 13.470 + """) # aims to reuse the last extents 13.471 + # from the longest-expired disks first 13.472 + 13.473 + allocated = 0 13.474 + 13.475 + building_sql = "UPDATE vdisks SET size = " + str(old_size + extra_size)\ 13.476 + + " WHERE vdisk_id = " + vdisk_id + "; " 13.477 + 13.478 + while allocated < add_size: 13.479 + row = cu.fetchone() 13.480 + if not row: 13.481 + cx.close() 13.482 + return -1 13.483 + 13.484 + (dead_vd_id, vdisk_extent_no, part_extent_no, part_id, extent_size) = row 13.485 + allocated += extent_size 13.486 + building_sql += "UPDATE vdisk_extents SET vdisk_id = " + vdisk_id \ 13.487 + + ", " + "vdisk_extent_no = " + str(counter) \ 13.488 + + " WHERE vdisk_extent_no = " + str(vdisk_extent_no) \ 13.489 + + " AND vdisk_id = " + str(dead_vd_id) + "; " 13.490 + 13.491 + counter += 1 13.492 + 13.493 + 13.494 + # this will execute the SQL query we build to store details of the new 13.495 + # virtual disk and allocate space to it print building_sql 13.496 + cu.execute(building_sql) 13.497 + 13.498 + cx.commit() 13.499 + cx.close() 13.500 + return 0 13.501 + 13.502 + 13.503 +def vd_undelete(vdisk_id, expiry_time): 13.504 + """Create a new virtual disk. 13.505 + vdisk_id [int]: size in megabytes for the new virtual disk 13.506 + expiry_time [int]: expiry time, in seconds from now 13.507 + returns [int]: zero on success, non-zero on failure 13.508 + """ 13.509 + 13.510 + if not os.path.isfile(VD_DB_FILE): 13.511 + __vd_no_database() 13.512 + 13.513 + if vdisk_id == '0': # undeleting vdisk 0 isn't sane! 13.514 + return -1 13.515 + 13.516 + cx = sqlite.connect(VD_DB_FILE) 13.517 + cu = cx.cursor() 13.518 + 13.519 + cu.execute("-- types int") 13.520 + cu.execute("SELECT COUNT(*) FROM vdisks WHERE vdisk_id = " + vdisk_id) 13.521 + count, = cu.fetchone() 13.522 + 13.523 + if not count: 13.524 + cx.close() 13.525 + return -1 13.526 + 13.527 + cu.execute("-- types int") 13.528 + cu.execute("""SELECT SUM(extent_size) 13.529 + FROM vdisks NATURAL JOIN vdisk_extents 13.530 + NATURAL JOIN vdisk_part 13.531 + WHERE vdisks.vdisk_id = """ + vdisk_id) 13.532 + 13.533 + real_size, = cu.fetchone() # get the true allocated size 13.534 + 13.535 + 13.536 + cu.execute("-- types int") 13.537 + cu.execute("SELECT size FROM vdisks WHERE vdisk_id = " + vdisk_id) 13.538 + 13.539 + old_size, = cu.fetchone() 13.540 + 13.541 + if real_size < old_size: 13.542 + cx.close() 13.543 + return -1 13.544 + 13.545 + if expiry_time == 0: 13.546 + expires = '0' 13.547 + else: 13.548 + expires = '1' 13.549 + 13.550 + # this will execute the SQL query we build to store details of the new 13.551 + # virtual disk and allocate space to it print building_sql 13.552 + cu.execute("UPDATE vdisks SET expiry_time = datetime('now','" 13.553 + + str(expiry_time) + " seconds'), expires = " + expires 13.554 + + " WHERE vdisk_id = " + vdisk_id) 13.555 + 13.556 + cx.commit() 13.557 + cx.close() 13.558 + return 0 13.559 + 13.560 + 13.561 + 13.562 + 13.563 +def vd_list(): 13.564 + """Lists all the virtual disks registered in the system. 13.565 + returns [list of dicts] 13.566 + """ 13.567 + 13.568 + if not os.path.isfile(VD_DB_FILE): 13.569 + __vd_no_database() 13.570 + 13.571 + cx = sqlite.connect(VD_DB_FILE) 13.572 + cu = cx.cursor() 13.573 + 13.574 + cu.execute("""SELECT vdisk_id, size, expires, expiry_time 13.575 + FROM vdisks 13.576 + WHERE (NOT expires) OR expiry_time > datetime('now') 13.577 + """) 13.578 + 13.579 + ret = cu.fetchall() 13.580 + 13.581 + cx.close() 13.582 + 13.583 + def makedicts((vdisk_id, size, expires, expiry_time)): 13.584 + return { 'vdisk_id' : str(vdisk_id), 'size': size, 13.585 + 'expires' : expires, 'expiry_time' : expiry_time } 13.586 + 13.587 + return map(makedicts, ret) 13.588 + 13.589 + 13.590 +def vd_refresh(id, expiry): 13.591 + """Change the expiry time of a virtual disk. 13.592 + id [string] : a virtual disk identifier 13.593 + expiry [int] : expiry time in seconds from now (0 = never expire) 13.594 + returns [int]: zero on success, non-zero on failure 13.595 + """ 13.596 + 13.597 + if not os.path.isfile(VD_DB_FILE): 13.598 + __vd_no_database() 13.599 + 13.600 + cx = sqlite.connect(VD_DB_FILE) 13.601 + cu = cx.cursor() 13.602 + 13.603 + cu.execute("-- types int") 13.604 + cu.execute("SELECT COUNT(*) FROM vdisks WHERE vdisk_id = " + id 13.605 + + " AND (expiry_time > datetime('now') OR NOT expires)") 13.606 + count, = cu.fetchone() 13.607 + 13.608 + if not count: 13.609 + cx.close() 13.610 + return -1 13.611 + 13.612 + if expiry: 13.613 + expires = 1 13.614 + expiry_ts = "datetime('now', '" + str(expiry) + " seconds')" 13.615 + else: 13.616 + expires = 0 13.617 + expiry_ts = "NULL" 13.618 + 13.619 + cu.execute("UPDATE vdisks SET expires = " + str(expires) 13.620 + + ", expiry_time = " + expiry_ts 13.621 + + " WHERE (expiry_time > datetime('now') OR NOT expires)" 13.622 + + " AND vdisk_id = " + id) 13.623 + 13.624 + cx.commit() 13.625 + cx.close() 13.626 + 13.627 + return 0 13.628 + 13.629 + 13.630 +def vd_delete(id): 13.631 + """Deletes a Virtual Disk, making its extents available for future VDs. 13.632 + id [string] : identifier for the virtual disk to delete 13.633 + returns [int] : 0 on success, -1 on failure (VD not found 13.634 + or already deleted) 13.635 + """ 13.636 + 13.637 + if not os.path.isfile(VD_DB_FILE): 13.638 + __vd_no_database() 13.639 + 13.640 + cx = sqlite.connect(VD_DB_FILE) 13.641 + cu = cx.cursor() 13.642 + 13.643 + cu.execute("-- types int") 13.644 + cu.execute("SELECT COUNT(*) FROM vdisks WHERE vdisk_id = " + id 13.645 + + " AND (expiry_time > datetime('now') OR NOT expires)") 13.646 + count, = cu.fetchone() 13.647 + 13.648 + if not count: 13.649 + cx.close() 13.650 + return -1 13.651 + 13.652 + cu.execute("UPDATE vdisks SET expires = 1, expiry_time = datetime('now')" 13.653 + + " WHERE vdisk_id = " + id) 13.654 + 13.655 + cx.commit() 13.656 + cx.close() 13.657 + 13.658 + return 0 13.659 + 13.660 + 13.661 +def vd_freespace(): 13.662 + """Returns the amount of free space available for new virtual disks, in MB 13.663 + returns [int] : free space for VDs in MB 13.664 + """ 13.665 + 13.666 + if not os.path.isfile(VD_DB_FILE): 13.667 + __vd_no_database() 13.668 + 13.669 + cx = sqlite.connect(VD_DB_FILE) 13.670 + cu = cx.cursor() 13.671 + 13.672 + cu.execute("-- types int") 13.673 + 13.674 + cu.execute("""SELECT SUM(extent_size) 13.675 + FROM vdisks NATURAL JOIN vdisk_extents 13.676 + NATURAL JOIN vdisk_part 13.677 + WHERE expiry_time <= datetime('now') AND expires""") 13.678 + 13.679 + sum, = cu.fetchone() 13.680 + 13.681 + cx.close() 13.682 + 13.683 + return sum / VBD_SECTORS_PER_MB 13.684 + 13.685 + 13.686 +def vd_init_db(path): 13.687 + """Initialise the VD SQLite database 13.688 + path [string]: path to the SQLite database file 13.689 + """ 13.690 + 13.691 + cx = sqlite.connect(path) 13.692 + cu = cx.cursor() 13.693 + 13.694 + cu.execute( 13.695 + """CREATE TABLE vdisk_extents 13.696 + ( vdisk_extent_no INT, 13.697 + vdisk_id INT, 13.698 + part_id INT, 13.699 + part_extent_no INT ) 13.700 + """) 13.701 + 13.702 + cu.execute( 13.703 + """CREATE TABLE vdisk_part 13.704 + ( part_id INT, 13.705 + partition VARCHAR, 13.706 + extent_size INT ) 13.707 + """) 13.708 + 13.709 + cu.execute( 13.710 + """CREATE TABLE vdisks 13.711 + ( vdisk_id INT, 13.712 + size INT, 13.713 + expires BOOLEAN, 13.714 + expiry_time TIMESTAMP ) 13.715 + """) 13.716 + 13.717 + 13.718 + cu.execute( 13.719 + """INSERT INTO vdisks ( vdisk_id, size, expires, expiry_time ) 13.720 + VALUES ( 0, 0, 1, datetime('now') ) 13.721 + """) 13.722 + 13.723 + cx.commit() 13.724 + cx.close() 13.725 + 13.726 + VD_DB_FILE = path 13.727 + 13.728 + 13.729 + 13.730 +def vd_cp_to_file(vdisk_id,filename): 13.731 + """Writes the contents of a specified vdisk out into a disk file, leaving 13.732 + the original copy in the virtual disk pool.""" 13.733 + 13.734 + cx = sqlite.connect(VD_DB_FILE) 13.735 + cu = cx.cursor() 13.736 + 13.737 + extents = vd_lookup(vdisk_id) 13.738 + 13.739 + if not extents: 13.740 + return -1 13.741 + 13.742 + file_idx = 0 # index into source file, in sectors 13.743 + 13.744 + for i in extents: 13.745 + cu.execute("""SELECT partition, extent_size FROM vdisk_part 13.746 + WHERE part_id = """ + str(i['part_device'])) 13.747 + 13.748 + (partition, extent_size) = cu.fetchone() 13.749 + 13.750 + os.system("dd bs=1b if=" + partition + " of=" + filename 13.751 + + " skip=" + str(i['part_start_sector']) 13.752 + + " seek=" + str(file_idx) 13.753 + + " count=" + str(i['nr_sectors']) 13.754 + + " > /dev/null") 13.755 + 13.756 + file_idx += i['nr_sectors'] 13.757 + 13.758 + cx.close() 13.759 + 13.760 + return 0 # should return -1 if something breaks 13.761 + 13.762 + 13.763 +def vd_mv_to_file(vdisk_id,filename): 13.764 + """Writes a vdisk out into a disk file and frees the space originally 13.765 + taken within the virtual disk pool. 13.766 + vdisk_id [string]: ID of the vdisk to write out 13.767 + filename [string]: file to write vdisk contents out to 13.768 + returns [int]: zero on success, nonzero on failure 13.769 + """ 13.770 + 13.771 + if vd_cp_to_file(vdisk_id,filename): 13.772 + return -1 13.773 + 13.774 + if vd_delete(vdisk_id): 13.775 + return -1 13.776 + 13.777 + return 0 13.778 + 13.779 + 13.780 +def vd_read_from_file(filename,expiry): 13.781 + """Reads the contents of a file directly into a vdisk, which is 13.782 + automatically allocated to fit. 13.783 + filename [string]: file to read disk contents from 13.784 + returns [string] : vdisk ID for the destination vdisk 13.785 + """ 13.786 + 13.787 + size_bytes = os.stat(filename).st_size 13.788 + 13.789 + (size_mb,leftover) = divmod(size_bytes,1048580) # size in megabytes 13.790 + if leftover > 0: size_mb += 1 # round up if not an exact number of MB 13.791 + 13.792 + vdisk_id = vd_create(size_mb, expiry) 13.793 + 13.794 + if vdisk_id < 0: 13.795 + return -1 13.796 + 13.797 + cx = sqlite.connect(VD_DB_FILE) 13.798 + cu = cx.cursor() 13.799 + 13.800 + cu.execute("""SELECT partition, extent_size, part_extent_no 13.801 + FROM vdisk_part NATURAL JOIN vdisk_extents 13.802 + WHERE vdisk_id = """ + vdisk_id + """ 13.803 + ORDER BY vdisk_extent_no ASC""") 13.804 + 13.805 + extents = cu.fetchall() 13.806 + 13.807 + size_sectors = size_mb * VBD_SECTORS_PER_MB # for feeding to dd 13.808 + 13.809 + file_idx = 0 # index into source file, in sectors 13.810 + 13.811 + def write_extent_to_vd((partition, extent_size, part_extent_no), 13.812 + file_idx, filename): 13.813 + """Write an extent out to disk and update file_idx""" 13.814 + 13.815 + os.system("dd bs=512 if=" + filename + " of=" + partition 13.816 + + " skip=" + str(file_idx) 13.817 + + " seek=" + str(part_extent_no * extent_size) 13.818 + + " count=" + str(min(extent_size, size_sectors - file_idx)) 13.819 + + " > /dev/null") 13.820 + 13.821 + return extent_size 13.822 + 13.823 + for i in extents: 13.824 + file_idx += write_extent_to_vd(i, file_idx, filename) 13.825 + 13.826 + cx.close() 13.827 + 13.828 + return vdisk_id 13.829 + 13.830 + 13.831 + 13.832 + 13.833 +def vd_extents_validate(new_extents, new_writeable, safety=VBD_SAFETY_RR): 13.834 + """Validate the extents against the existing extents. 13.835 + Complains if the list supplied clashes against the extents that 13.836 + are already in use in the system. 13.837 + new_extents [list of dicts]: list of new extents, as dicts 13.838 + new_writeable [int]: 1 if they are to be writeable, 0 otherwise 13.839 + returns [int]: either the expertise level of the mapping if it doesn't 13.840 + exceed VBD_EXPERT_MODE or -1 if it does (error) 13.841 + """ 13.842 + 13.843 + import Xc # this is only needed in this function 13.844 + 13.845 + xc = Xc.new() 13.846 + 13.847 + ##### Probe for explicitly created virtual disks and build a list 13.848 + ##### of extents for comparison with the ones that are being added 13.849 + 13.850 + probe = xc.vbd_probe() 13.851 + 13.852 + old_extents = [] # this will hold a list of all existing extents and 13.853 + # their writeable status, as a list of (device, 13.854 + # start, size, writeable?) tuples 13.855 + 13.856 + for vbd in probe: 13.857 + this_vbd_extents = xc.vbd_getextents(vbd['dom'],vbd['vbd']) 13.858 + for vbd_ext in this_vbd_extents: 13.859 + vbd_ext['writeable'] = vbd['writeable'] 13.860 + old_extents.append(vbd_ext) 13.861 + 13.862 + ##### Now scan /proc/mounts for compile a list of extents corresponding to 13.863 + ##### any devices mounted in DOM0. This list is added on to old_extents 13.864 + 13.865 + regexp = re.compile("/dev/(\S*) \S* \S* (..).*") 13.866 + fd = open('/proc/mounts', "r") 13.867 + 13.868 + while True: 13.869 + line = readline(fd) 13.870 + if not line: # if we've run out of lines then stop reading 13.871 + break 13.872 + 13.873 + m = regexp.match(line) 13.874 + 13.875 + # if the regexp didn't match then it's probably a line we don't 13.876 + # care about - skip to next line 13.877 + if not m: 13.878 + continue 13.879 + 13.880 + # lookup the device 13.881 + ext_list = lookup_raw_partn(m.group(1)) 13.882 + 13.883 + # if lookup failed, skip to next mounted device 13.884 + if not ext_list: 13.885 + continue 13.886 + 13.887 + # set a writeable flag as appropriate 13.888 + for ext in ext_list: 13.889 + ext['writeable'] = m.group(2) == 'rw' 13.890 + 13.891 + # now we've got here, the contents of ext_list are in a 13.892 + # suitable format to be added onto the old_extents list, ready 13.893 + # for checking against the new extents 13.894 + 13.895 + old_extents.extend(ext_list) 13.896 + 13.897 + fd.close() # close /proc/mounts 13.898 + 13.899 + ##### By this point, old_extents contains a list of extents, in 13.900 + ##### dictionary format corresponding to every extent of physical 13.901 + ##### disk that's either part of an explicitly created VBD, or is 13.902 + ##### mounted under DOM0. We now check these extents against the 13.903 + ##### proposed additions in new_extents, to see if a conflict will 13.904 + ##### happen if they are added with write status new_writeable 13.905 + 13.906 + level = 0 # this'll accumulate the max warning level 13.907 + 13.908 + # Search for clashes between the new extents and the old ones 13.909 + # Takes time O(len(new_extents) * len(old_extents)) 13.910 + for new_ext in new_extents: 13.911 + for old_ext in old_extents: 13.912 + if(new_ext['device'] == old_ext['device']): 13.913 + 13.914 + new_ext_start = new_ext['start_sector'] 13.915 + new_ext_end = new_ext_start + new_ext['nr_sectors'] - 1 13.916 + 13.917 + old_ext_start = old_ext['start_sector'] 13.918 + old_ext_end = old_ext_start + old_ext['nr_sectors'] - 1 13.919 + 13.920 + if((old_ext_start <= new_ext_start <= old_ext_end) or 13.921 + (old_ext_start <= new_ext_end <= old_ext_end)): 13.922 + if (not old_ext['writeable']) and new_writeable: 13.923 + level = max(1,level) 13.924 + elif old_ext['writeable'] and (not new_writeable): 13.925 + level = max(1,level) 13.926 + elif old_ext['writeable'] and new_writeable: 13.927 + level = max(2,level) 13.928 + 13.929 + 13.930 + ##### level now holds the warning level incurred by the current 13.931 + ##### VBD setup and we complain appropriately to the user 13.932 + 13.933 + 13.934 + if level == 1: 13.935 + print >> sys.stderr, """Warning: one or more hard disk extents 13.936 + writeable by one domain are also readable by another.""" 13.937 + elif level == 2: 13.938 + print >> sys.stderr, """Warning: one or more hard disk extents are 13.939 + writeable by two or more domains simultaneously.""" 13.940 + 13.941 + if level > safety: 13.942 + print >> sys.stderr, """ERROR: This kind of disk sharing is not allowed 13.943 + at the current safety level (%d).""" % safety 13.944 + level = -1 13.945 + 13.946 + return level 13.947 +
14.1 --- a/tools/xenctl/setup.py Fri Jun 11 15:26:55 2004 +0000 14.2 +++ b/tools/xenctl/setup.py Fri Jun 11 18:31:12 2004 +0000 14.3 @@ -2,7 +2,7 @@ 14.4 from distutils.core import setup, Extension 14.5 import sys 14.6 14.7 -modules = [ 'xenctl.console_client', 'xenctl.utils' ] 14.8 +modules = [ 'xenctl.console_client', 'xenctl.utils', 'xenctl.ip' , 'xenctl.vdisk' ] 14.9 14.10 # We need the 'tempfile' module from Python 2.3. We install this ourselves 14.11 # if the installed Python is older than 2.3.
15.1 --- a/tools/xend/lib/utils.c Fri Jun 11 15:26:55 2004 +0000 15.2 +++ b/tools/xend/lib/utils.c Fri Jun 11 18:31:12 2004 +0000 15.3 @@ -412,7 +412,8 @@ static PyObject *xu_message_get_payload( 15.4 C2P(netif_fe_interface_status_changed_t, evtchn, Int, Long); 15.5 return dict; 15.6 case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_DRIVER_STATUS_CHANGED): 15.7 - C2P(netif_fe_driver_status_changed_t, status, Int, Long); 15.8 + C2P(netif_fe_driver_status_changed_t, status, Int, Long); 15.9 + C2P(netif_fe_driver_status_changed_t, nr_interfaces, Int, Long); 15.10 return dict; 15.11 case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_CONNECT): 15.12 C2P(netif_fe_interface_connect_t, handle, Int, Long); 15.13 @@ -603,6 +604,9 @@ static PyObject *xu_message_new(PyObject 15.14 P2C(netif_be_disconnect_t, domid, u32); 15.15 P2C(netif_be_disconnect_t, netif_handle, u32); 15.16 break; 15.17 + case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_DRIVER_STATUS_CHANGED): 15.18 + P2C(netif_fe_driver_status_changed_t, status, u32); 15.19 + P2C(netif_fe_driver_status_changed_t, nr_interfaces, u32); 15.20 } 15.21 15.22 if ( dict_items_parsed != PyDict_Size(payload) )
16.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 16.2 +++ b/tools/xenmgr/Makefile Fri Jun 11 18:31:12 2004 +0000 16.3 @@ -0,0 +1,19 @@ 16.4 + 16.5 +all: 16.6 + python setup.py build 16.7 + 16.8 +install: all 16.9 + if [ "$(prefix)" = "" ]; then \ 16.10 + python setup.py install; \ 16.11 + elif [ "$(dist)" = "yes" ]; then \ 16.12 + python setup.py install --home="$(prefix)"; \ 16.13 + else \ 16.14 + python setup.py install --root="$(prefix)"; \ 16.15 + fi 16.16 + mkdir -p $(prefix)/usr/sbin 16.17 + install -m0755 xenmgrd $(prefix)/usr/sbin 16.18 + install -m0755 xend $(prefix)/usr/sbin 16.19 + install -m0755 netfix $(prefix)/usr/sbin 16.20 + 16.21 +clean: 16.22 + rm -rf build *.pyc *.pyo *.o *.a *~
17.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 17.2 +++ b/tools/xenmgr/lib/Args.py Fri Jun 11 18:31:12 2004 +0000 17.3 @@ -0,0 +1,126 @@ 17.4 +import sxp 17.5 + 17.6 +class ArgError(StandardError): 17.7 + pass 17.8 + 17.9 +class Args: 17.10 + """Argument encoding support for HTTP. 17.11 + """ 17.12 + 17.13 + def __init__(self, paramspec, keyspec): 17.14 + self.arg_ord = [] 17.15 + self.arg_dict = {} 17.16 + self.key_ord = [] 17.17 + self.key_dict = {} 17.18 + for (name, type) in paramspec: 17.19 + self.arg_ord.append(name) 17.20 + self.arg_dict[name] = type 17.21 + for (name, type) in keyspec: 17.22 + self.key_ord.append(name) 17.23 + self.key_dict[name] = type 17.24 + 17.25 + def get_args(self, d, xargs=None): 17.26 + args = {} 17.27 + keys = {} 17.28 + params = [] 17.29 + if xargs: 17.30 + self.split_args(xargs, args, keys) 17.31 + self.split_args(d, args, keys) 17.32 + for a in self.arg_ord: 17.33 + if a in args: 17.34 + params.append(args[a]) 17.35 + else: 17.36 + raise ArgError('Missing parameter: %s' % a) 17.37 + return (params, keys) 17.38 + 17.39 + def split_args(self, d, args, keys): 17.40 + for (k, v) in d.items(): 17.41 + if k in self.arg_dict: 17.42 + type = self.arg_dict[k] 17.43 + val = self.coerce(type, v) 17.44 + args[k] = val 17.45 + elif k in self.key_dict: 17.46 + type = self.key_dict[k] 17.47 + val = self.coerce(type, v) 17.48 + keys[k] = val 17.49 + else: 17.50 + raise ArgError('Invalid parameter: %s' % k) 17.51 + 17.52 + def get_form_args(self, f, xargs=None): 17.53 + d = {} 17.54 + for (k, v) in f.items(): 17.55 + n = len(v) 17.56 + if ((k not in self.arg_dict) and 17.57 + (k not in self.key_dict)): 17.58 + continue 17.59 + if n == 0: 17.60 + continue 17.61 + elif n == 1: 17.62 + d[k] = v[0] 17.63 + else: 17.64 + raise ArgError('Too many values for %s' % k) 17.65 + return self.get_args(d, xargs=xargs) 17.66 + 17.67 + def coerce(self, type, v): 17.68 + try: 17.69 + if type == 'int': 17.70 + return int(v) 17.71 + if type == 'str': 17.72 + return str(v) 17.73 + if type == 'sxpr': 17.74 + return self.sxpr(v) 17.75 + except ArgError: 17.76 + raise 17.77 + except StandardError, ex: 17.78 + raise ArgError(str(ex)) 17.79 + 17.80 + def sxpr(self, v): 17.81 + if instanceof(v, types.ListType): 17.82 + return v 17.83 + if instanceof(v, types.File) or hasattr(v, 'readline'): 17.84 + return sxpr_file(v) 17.85 + if instanceof(v, types.StringType): 17.86 + return sxpr_file(StringIO(v)) 17.87 + return str(v) 17.88 + 17.89 + def sxpr_file(self, fin): 17.90 + try: 17.91 + vals = sxp.parse(fin) 17.92 + except: 17.93 + raise ArgError('Coercion to sxpr failed') 17.94 + if len(vals) == 1: 17.95 + return vals[0] 17.96 + else: 17.97 + raise ArgError('Too many sxprs') 17.98 + 17.99 + def call_with_args(self, fn, args, xargs=None): 17.100 + (params, keys) = self.get_args(args, xargs=xargs) 17.101 + fn(*params, **keys) 17.102 + 17.103 + def call_with_form_args(self, fn, fargs, xargs=None): 17.104 + (params, keys) = self.get_form_args(fargs, xargs=xargs) 17.105 + fn(*params, **keys) 17.106 + 17.107 +class ArgFn(Args): 17.108 + """Represent a remote HTTP operation as a function. 17.109 + Used on the client. 17.110 + """ 17.111 + 17.112 + def __init__(self, fn, paramspec, keyspec={}): 17.113 + Args.__init__(self, paramspec, keyspec) 17.114 + self.fn = fn 17.115 + 17.116 + def __call__(self, fargs, xargs=None): 17.117 + return self.call_with_args(self.fn, fargs, xargs=xargs) 17.118 + 17.119 +class FormFn(Args): 17.120 + """Represent an operation as a function over a form. 17.121 + Used in the HTTP server. 17.122 + """ 17.123 + 17.124 + def __init__(self, fn, paramspec, keyspec={}): 17.125 + Args.__init__(self, paramspec, keyspec) 17.126 + self.fn = fn 17.127 + 17.128 + def __call__(self, fargs, xargs=None): 17.129 + return self.call_with_form_args(self.fn, fargs, xargs=xargs)
18.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 18.2 +++ b/tools/xenmgr/lib/EventServer.py Fri Jun 11 18:31:12 2004 +0000 18.3 @@ -0,0 +1,204 @@ 18.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com> 18.5 +"""Simple publish/subscribe event server. 18.6 + 18.7 +""" 18.8 +import string 18.9 + 18.10 +# subscribe a.b.c h: map a.b.c -> h 18.11 +# subscribe a.b.* h: map a.b.* -> h 18.12 +# subscribe a.b.? h: map a.b.? -> h 18.13 +# 18.14 +# for event a.b.c.d: 18.15 +# 18.16 +# lookup a.b.c.d, call handlers 18.17 +# 18.18 +# lookup a.b.c.?, call handlers 18.19 +# 18.20 +# lookup a.b.c.d.*, call handlers 18.21 +# lookup a.b.c.*, call handlers 18.22 +# lookup a.b.*, call handlers 18.23 +# lookup a.*, call handlers 18.24 +# lookup *, call handlers 18.25 + 18.26 +# a.b.c.d = (a b c d) 18.27 +# a.b.c.? = (a b c _) 18.28 +# a.b.c.* = (a b c . _) 18.29 + 18.30 +class EventServer: 18.31 + 18.32 + DOT = '.' 18.33 + QUERY = '?' 18.34 + DOT_QUERY = DOT + QUERY 18.35 + STAR = '*' 18.36 + DOT_STAR = DOT + STAR 18.37 + 18.38 + def __init__(self, run=0): 18.39 + self.handlers = {} 18.40 + self.run = run 18.41 + self.queue = [] 18.42 + 18.43 + def start(self): 18.44 + """Enable event handling. Sends any queued events. 18.45 + """ 18.46 + self.run = 1 18.47 + for (e,v) in self.queue: 18.48 + self.inject(e, v) 18.49 + self.queue = [] 18.50 + 18.51 + def stop(self): 18.52 + """Suspend event handling. Events injected while suspended 18.53 + are queued until we are started again. 18.54 + """ 18.55 + self.run = 0 18.56 + 18.57 + def subscribe(self, event, handler): 18.58 + """Subscribe to an event. For example 'a.b.c.d'. 18.59 + A subcription like 'a.b.c.?' ending in '?' matches any value 18.60 + for the '?'. A subscription like 'a.b.c.*' ending in '*' matches 18.61 + any event type with the same prefix, 'a.b.c' in this case. 18.62 + 18.63 + event event name 18.64 + handler event handler fn(event, val) 18.65 + """ 18.66 + hl = self.handlers.get(event) 18.67 + if hl is None: 18.68 + self.handlers[event] = [handler] 18.69 + else: 18.70 + hl.append(handler) 18.71 + 18.72 + def unsubscribe_all(self, event=None): 18.73 + """Unsubscribe all handlers for a given event, or all handlers. 18.74 + 18.75 + event event (optional) 18.76 + """ 18.77 + if event == None: 18.78 + self.handlers.clear() 18.79 + else: 18.80 + del self.handlers[event] 18.81 + 18.82 + def unsubscribe(self, event, handler): 18.83 + """Unsubscribe a given event and handler. 18.84 + 18.85 + event event 18.86 + handler handler 18.87 + """ 18.88 + hl = self.handlers.get(event) 18.89 + if hl is None: 18.90 + return 18.91 + hl.remove(handler) 18.92 + 18.93 + def inject(self, event, val): 18.94 + """Inject an event. Handlers for it are called if runing, otherwise 18.95 + it is queued. 18.96 + 18.97 + event event type 18.98 + val event value 18.99 + """ 18.100 + if self.run: 18.101 + #print ">event", event, val 18.102 + self.call_event_handlers(event, event, val) 18.103 + self.call_query_handlers(event, val) 18.104 + self.call_star_handlers(event, val) 18.105 + else: 18.106 + self.queue.append( (event, val) ) 18.107 + 18.108 + def call_event_handlers(self, key, event, val): 18.109 + """Call the handlers for an event. 18.110 + It is safe for handlers to subscribe or unsubscribe. 18.111 + 18.112 + key key for handler list 18.113 + event event type 18.114 + val event value 18.115 + """ 18.116 + hl = self.handlers.get(key) 18.117 + if hl is None: 18.118 + return 18.119 + # Copy the handler list so that handlers can call 18.120 + # subscribe/unsubscribe safely - python list iteration 18.121 + # is not safe against list modification. 18.122 + for h in hl[:]: 18.123 + try: 18.124 + h(event, val) 18.125 + except: 18.126 + pass 18.127 + 18.128 + def call_query_handlers(self, event, val): 18.129 + """Call regex handlers for events matching 'event' that end in '?'. 18.130 + 18.131 + event event type 18.132 + val event value 18.133 + """ 18.134 + dot_idx = event.rfind(self.DOT) 18.135 + if dot_idx == -1: 18.136 + self.call_event_handlers(self.QUERY, event, val) 18.137 + else: 18.138 + event_query = event[0:dot_idx] + self.DOT_QUERY 18.139 + self.call_event_handlers(event_query, event, val) 18.140 + 18.141 + def call_star_handlers(self, event, val): 18.142 + """Call regex handlers for events matching 'event' that end in '*'. 18.143 + 18.144 + event event type 18.145 + val event value 18.146 + """ 18.147 + etype = string.split(event, self.DOT) 18.148 + for i in range(len(etype), 0, -1): 18.149 + event_star = self.DOT.join(etype[0:i]) + self.DOT_STAR 18.150 + self.call_event_handlers(event_star, event, val) 18.151 + self.call_event_handlers(self.STAR, event, val) 18.152 + 18.153 +def instance(): 18.154 + global inst 18.155 + try: 18.156 + inst 18.157 + except: 18.158 + inst = EventServer() 18.159 + inst.start() 18.160 + return inst 18.161 + 18.162 +def main(): 18.163 + def sys_star(event, val): 18.164 + print 'sys_star', event, val 18.165 + 18.166 + def sys_foo(event, val): 18.167 + print 'sys_foo', event, val 18.168 + s.unsubscribe('sys.foo', sys_foo) 18.169 + 18.170 + def sys_foo2(event, val): 18.171 + print 'sys_foo2', event, val 18.172 + 18.173 + def sys_bar(event, val): 18.174 + print 'sys_bar', event, val 18.175 + 18.176 + def sys_foo_bar(event, val): 18.177 + print 'sys_foo_bar', event, val 18.178 + 18.179 + def foo_bar(event, val): 18.180 + print 'foo_bar', event, val 18.181 + 18.182 + s = EventServer() 18.183 + s.start() 18.184 + s.subscribe('sys.*', sys_star) 18.185 + s.subscribe('sys.foo', sys_foo) 18.186 + s.subscribe('sys.foo', sys_foo2) 18.187 + s.subscribe('sys.bar', sys_bar) 18.188 + s.subscribe('sys.foo.bar', sys_foo_bar) 18.189 + s.subscribe('foo.bar', foo_bar) 18.190 + s.inject('sys.foo', 'hello') 18.191 + print 18.192 + s.inject('sys.bar', 'hello again') 18.193 + print 18.194 + s.inject('sys.foo.bar', 'hello again') 18.195 + print 18.196 + s.inject('foo.bar', 'hello again') 18.197 + print 18.198 + s.inject('foo', 'hello again') 18.199 + print 18.200 + s.start() 18.201 + s.unsubscribe('sys.*', sys_star) 18.202 + s.unsubscribe_all('sys.*') 18.203 + s.inject('sys.foo', 'hello') 18.204 + 18.205 +if __name__ == "__main__": 18.206 + main() 18.207 +
19.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 19.2 +++ b/tools/xenmgr/lib/EventTypes.py Fri Jun 11 18:31:12 2004 +0000 19.3 @@ -0,0 +1,34 @@ 19.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com> 19.5 + 19.6 +## XEND_DOMAIN_CREATE = "xend.domain.create": dom 19.7 +## create: 19.8 +## xend.domain.destroy: dom, reason:died/crashed 19.9 +## xend.domain.up ? 19.10 + 19.11 +## xend.domain.start: dom 19.12 +## xend.domain.stop: dom 19.13 +## xend.domain.shutdown: dom 19.14 +## xend.domain.halt: dom 19.15 + 19.16 +## xend.domain.migrate.begin: dom, to 19.17 +## Begin tells: src host, src domain uri, dst host. Dst id known? 19.18 +## err: src host, src domain uri, dst host, dst id if known, status (of domain: ok, dead,...), reason 19.19 +## end: src host, src domain uri, dst host, dst uri 19.20 + 19.21 +## Events for both ends of migrate: for exporter and importer? 19.22 +## Include migrate id so can tie together. 19.23 +## Have uri /xend/migrate/<id> for migrate info (migrations in progress). 19.24 + 19.25 +## (xend.domain.migrate.begin (src <host>) (src.domain <id>) 19.26 +## (dst <host>) (id <migrate id>)) 19.27 + 19.28 +## xend.domain.migrate.end: 19.29 +## (xend.domain.migrate.end (domain <id>) (to <host>) 19.30 + 19.31 +## xend.node.up: xend uri 19.32 +## xend.node.down: xend uri 19.33 + 19.34 +## xend.error ? 19.35 + 19.36 +## format: 19.37 +
20.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 20.2 +++ b/tools/xenmgr/lib/PrettyPrint.py Fri Jun 11 18:31:12 2004 +0000 20.3 @@ -0,0 +1,299 @@ 20.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com> 20.5 + 20.6 +"""General pretty-printer, including support for SXP. 20.7 + 20.8 +""" 20.9 +import sys 20.10 +import types 20.11 +import StringIO 20.12 +import sxp 20.13 + 20.14 +class PrettyItem: 20.15 + 20.16 + def __init__(self, width): 20.17 + self.width = width 20.18 + 20.19 + def insert(self, block): 20.20 + block.addtoline(self) 20.21 + 20.22 + def get_width(self): 20.23 + return self.width 20.24 + 20.25 + def output(self, out): 20.26 + print '***PrettyItem>output>', self 20.27 + pass 20.28 + 20.29 + def prettyprint(self, out, width): 20.30 + print '***PrettyItem>prettyprint>', self 20.31 + return width 20.32 + 20.33 +class PrettyString(PrettyItem): 20.34 + 20.35 + def __init__(self, x): 20.36 + PrettyItem.__init__(self, len(x)) 20.37 + self.value = x 20.38 + 20.39 + def output(self, out): 20.40 + out.write(self.value) 20.41 + 20.42 + def prettyprint(self, line): 20.43 + line.output(self) 20.44 + 20.45 + def show(self, out): 20.46 + print >> out, ("(string (width %d) '%s')" % (self.width, self.value)) 20.47 + 20.48 +class PrettySpace(PrettyItem): 20.49 + 20.50 + def output(self, out): 20.51 + out.write(' ' * self.width) 20.52 + 20.53 + def prettyprint(self, line): 20.54 + line.output(self) 20.55 + 20.56 + def show(self, out): 20.57 + print >> out, ("(space (width %d))" % self.width) 20.58 + 20.59 +class PrettyBreak(PrettyItem): 20.60 + 20.61 + def __init__(self, width, indent): 20.62 + PrettyItem.__init__(self, width) 20.63 + self.indent = indent 20.64 + self.space = 0 20.65 + self.active = 0 20.66 + 20.67 + def output(self, out): 20.68 + out.write(' ' * self.width) 20.69 + 20.70 + def prettyprint(self, line): 20.71 + if line.breaks(self.space): 20.72 + self.active = 1 20.73 + line.newline(self.indent) 20.74 + else: 20.75 + line.output(self) 20.76 + 20.77 + def show(self, out): 20.78 + print >> out, ("(break (width %d) (indent %d) (space %d) (active %d))" 20.79 + % (self.width, self.indent, self.space, self.lspace, self.active)) 20.80 + 20.81 +class PrettyNewline(PrettySpace): 20.82 + 20.83 + def __init__(self, indent): 20.84 + PrettySpace.__init__(self, indent) 20.85 + 20.86 + def insert(self, block): 20.87 + block.newline() 20.88 + block.addtoline(self) 20.89 + 20.90 + def output(self, out): 20.91 + out.write(' ' * self.width) 20.92 + 20.93 + def prettyprint(self, line): 20.94 + line.newline(0) 20.95 + line.output(self) 20.96 + 20.97 + def show(self, out): 20.98 + print >> out, ("(nl (indent %d))" % self.indent) 20.99 + 20.100 +class PrettyLine(PrettyItem): 20.101 + def __init__(self): 20.102 + PrettyItem.__init__(self, 0) 20.103 + self.content = [] 20.104 + 20.105 + def write(self, x): 20.106 + self.content.append(x) 20.107 + 20.108 + def end(self): 20.109 + width = 0 20.110 + lastwidth = 0 20.111 + lastbreak = None 20.112 + for x in self.content: 20.113 + if isinstance(x, PrettyBreak): 20.114 + if lastbreak: 20.115 + lastbreak.space = (width - lastwidth) 20.116 + lastbreak = x 20.117 + lastwidth = width 20.118 + width += x.get_width() 20.119 + if lastbreak: 20.120 + lastbreak.space = (width - lastwidth) 20.121 + self.width = width 20.122 + 20.123 + def prettyprint(self, line): 20.124 + for x in self.content: 20.125 + x.prettyprint(line) 20.126 + 20.127 + def show(self, out): 20.128 + print >> out, '(LINE (width %d)' % self.width 20.129 + for x in self.content: 20.130 + x.show(out) 20.131 + print >> out, ')' 20.132 + 20.133 +class PrettyBlock(PrettyItem): 20.134 + 20.135 + def __init__(self, all=0, parent=None): 20.136 + self.width = 0 20.137 + self.lines = [] 20.138 + self.parent = parent 20.139 + self.indent = 0 20.140 + self.all = all 20.141 + self.broken = 0 20.142 + self.newline() 20.143 + 20.144 + def add(self, item): 20.145 + item.insert(self) 20.146 + 20.147 + def end(self): 20.148 + self.width = 0 20.149 + for l in self.lines: 20.150 + l.end() 20.151 + if self.width < l.width: 20.152 + self.width = l.width 20.153 + 20.154 + def breaks(self, n): 20.155 + return self.all and self.broken 20.156 + 20.157 + def newline(self): 20.158 + self.lines.append(PrettyLine()) 20.159 + 20.160 + def addtoline(self, x): 20.161 + self.lines[-1].write(x) 20.162 + 20.163 + def prettyprint(self, line): 20.164 + self.indent = line.used 20.165 + line.block = self 20.166 + if not line.fits(self.width): 20.167 + self.broken = 1 20.168 + for l in self.lines: 20.169 + l.prettyprint(line) 20.170 + line.block = self.parent 20.171 + 20.172 + def show(self, out): 20.173 + print >> out, ('(BLOCK (width %d) (indent %d) (all %d) (broken %d)' % 20.174 + (self.width, self.indent, self.all, self.broken)) 20.175 + for l in self.lines: 20.176 + l.show(out) 20.177 + print >> out, ')' 20.178 + 20.179 +class Line: 20.180 + 20.181 + def __init__(self, out, width): 20.182 + self.out = out 20.183 + self.width = width 20.184 + self.used = 0 20.185 + self.space = self.width 20.186 + 20.187 + def newline(self, indent): 20.188 + indent += self.block.indent 20.189 + self.out.write('\n') 20.190 + self.out.write(' ' * indent) 20.191 + self.used = indent 20.192 + self.space = self.width - self.used 20.193 + 20.194 + def fits(self, n): 20.195 + return self.space - n >= 0 20.196 + 20.197 + def breaks(self, n): 20.198 + return self.block.breaks(n) or not self.fits(n) 20.199 + 20.200 + def output(self, x): 20.201 + n = x.get_width() 20.202 + self.space -= n 20.203 + self.used += n 20.204 + if self.space < 0: 20.205 + self.space = 0 20.206 + x.output(self.out) 20.207 + 20.208 +class PrettyPrinter: 20.209 + """A prettyprinter based on what I remember of Derek Oppen's 20.210 + prettyprint algorithm from TOPLAS way back. 20.211 + """ 20.212 + 20.213 + def __init__(self, width=40): 20.214 + self.width = width 20.215 + self.block = None 20.216 + self.top = None 20.217 + 20.218 + def write(self, x): 20.219 + self.block.add(PrettyString(x)) 20.220 + 20.221 + def add(self, item): 20.222 + self.block.add(item) 20.223 + 20.224 + def addbreak(self, width=1, indent=4): 20.225 + self.add(PrettyBreak(width, indent)) 20.226 + 20.227 + def addspace(self, width=1): 20.228 + self.add(PrettySpace(width)) 20.229 + 20.230 + def addnl(self, indent=0): 20.231 + self.add(PrettyNewline(indent)) 20.232 + 20.233 + def begin(self, all=0): 20.234 + block = PrettyBlock(all=all, parent=self.block) 20.235 + self.block = block 20.236 + 20.237 + def end(self): 20.238 + self.block.end() 20.239 + if self.block.parent: 20.240 + self.block.parent.add(self.block) 20.241 + else: 20.242 + self.top = self.block 20.243 + self.block = self.block.parent 20.244 + 20.245 + def prettyprint(self, out=sys.stdout): 20.246 + line = Line(out, self.width) 20.247 + self.top.prettyprint(line) 20.248 + 20.249 +class SXPPrettyPrinter(PrettyPrinter): 20.250 + """An SXP prettyprinter. 20.251 + """ 20.252 + 20.253 + def pstring(self, x): 20.254 + io = StringIO.StringIO() 20.255 + sxp.show(x, out=io) 20.256 + io.seek(0) 20.257 + val = io.getvalue() 20.258 + io.close() 20.259 + return val 20.260 + 20.261 + def pprint(self, l): 20.262 + if isinstance(l, types.ListType): 20.263 + self.begin(all=1) 20.264 + self.write('(') 20.265 + i = 0 20.266 + for x in l: 20.267 + if(i): self.addbreak() 20.268 + self.pprint(x) 20.269 + i += 1 20.270 + self.addbreak(width=0, indent=0) 20.271 + self.write(')') 20.272 + self.end() 20.273 + else: 20.274 + self.write(self.pstring(l)) 20.275 + 20.276 +def prettyprint(sxpr, out=sys.stdout, width=80): 20.277 + """Prettyprint an SXP form. 20.278 + 20.279 + sxpr s-expression 20.280 + out destination 20.281 + width maximum output width 20.282 + """ 20.283 + if isinstance(sxpr, types.ListType): 20.284 + pp = SXPPrettyPrinter(width=width) 20.285 + pp.pprint(sxpr) 20.286 + pp.prettyprint(out=out) 20.287 + else: 20.288 + sxp.show(sxpr, out=out) 20.289 + print >> out 20.290 + 20.291 +def main(): 20.292 + pin = sxp.Parser() 20.293 + while 1: 20.294 + buf = sys.stdin.read(100) 20.295 + pin.input(buf) 20.296 + if buf == '': break 20.297 + l = pin.get_val() 20.298 + prettyprint(l, width=80) 20.299 + 20.300 +if __name__ == "__main__": 20.301 + main() 20.302 +
21.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 21.2 +++ b/tools/xenmgr/lib/XendClient.py Fri Jun 11 18:31:12 2004 +0000 21.3 @@ -0,0 +1,368 @@ 21.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com> 21.5 +"""Client API for the HTTP interface on xend. 21.6 +Callable as a script - see main(). 21.7 +""" 21.8 +import sys 21.9 +import httplib 21.10 +import types 21.11 +from StringIO import StringIO 21.12 +import urlparse 21.13 + 21.14 +from encode import * 21.15 +import sxp 21.16 +import PrettyPrint 21.17 + 21.18 +DEBUG = 1 21.19 + 21.20 +class Foo(httplib.HTTPResponse): 21.21 + 21.22 + def begin(self): 21.23 + fin = self.fp 21.24 + while(1): 21.25 + buf = fin.readline() 21.26 + print "***", buf 21.27 + if buf == '': 21.28 + print 21.29 + sys.exit() 21.30 + 21.31 + 21.32 +def sxprio(sxpr): 21.33 + io = StringIO() 21.34 + sxp.show(sxpr, out=io) 21.35 + print >> io 21.36 + io.seek(0) 21.37 + return io 21.38 + 21.39 +def fileof(val): 21.40 + """Converter for passing configs. 21.41 + Handles lists, files directly. 21.42 + Assumes a string is a file name and passes its contents. 21.43 + """ 21.44 + if isinstance(val, types.ListType): 21.45 + return sxprio(val) 21.46 + if isinstance(val, types.StringType): 21.47 + return file(val) 21.48 + if hasattr(val, 'readlines'): 21.49 + return val 21.50 + 21.51 +# todo: need to sort of what urls/paths are using for objects. 21.52 +# e.g. for domains at the moment return '0'. 21.53 +# should probably return abs path w.r.t. server, e.g. /xend/domain/0. 21.54 +# As an arg, assume abs path is obj uri, otherwise just id. 21.55 + 21.56 +# Function to convert to full url: Xend.uri(path), e.g. 21.57 +# maps /xend/domain/0 to http://wray-m-3.hpl.hp.com:8000/xend/domain/0 21.58 +# And should accept urls for ids? 21.59 + 21.60 +def urljoin(location, root, prefix='', rest=''): 21.61 + base = 'http://' + location + root + prefix 21.62 + url = urlparse.urljoin(base, rest) 21.63 + return url 21.64 + 21.65 +def nodeurl(location, root, id=''): 21.66 + return urljoin(location, root, 'node/', id) 21.67 + 21.68 +def domainurl(location, root, id=''): 21.69 + return urljoin(location, root, 'domain/', id) 21.70 + 21.71 +def consoleurl(location, root, id=''): 21.72 + return urljoin(location, root, 'console/', id) 21.73 + 21.74 +def vbdurl(location, root, id=''): 21.75 + return urljoin(location, root, 'vbd/', id) 21.76 + 21.77 +def deviceurl(location, root, id=''): 21.78 + return urljoin(location, root, 'device/', id) 21.79 + 21.80 +def vneturl(location, root, id=''): 21.81 + return urljoin(location, root, 'vnet/', id) 21.82 + 21.83 +def eventurl(location, root, id=''): 21.84 + return urljoin(location, root, 'event/', id) 21.85 + 21.86 +def xend_request(url, method, data=None): 21.87 + urlinfo = urlparse.urlparse(url) 21.88 + (uproto, ulocation, upath, uparam, uquery, ufrag) = urlinfo 21.89 + if DEBUG: print url, urlinfo 21.90 + if uproto != 'http': 21.91 + raise StandardError('Invalid protocol: ' + uproto) 21.92 + if DEBUG: print '>xend_request', ulocation, upath, method, data 21.93 + (hdr, args) = encode_data(data) 21.94 + if data and method == 'GET': 21.95 + upath += '?' + args 21.96 + args = None 21.97 + if method == "POST" and upath.endswith('/'): 21.98 + upath = upath[:-1] 21.99 + if DEBUG: print "ulocation=", ulocation, "upath=", upath, "args=", args 21.100 + #hdr['User-Agent'] = 'Mozilla' 21.101 + #hdr['Accept'] = 'text/html,text/plain' 21.102 + conn = httplib.HTTPConnection(ulocation) 21.103 + #conn.response_class = Foo 21.104 + conn.set_debuglevel(1) 21.105 + conn.request(method, upath, args, hdr) 21.106 + resp = conn.getresponse() 21.107 + if DEBUG: print resp.status, resp.reason 21.108 + if DEBUG: print resp.msg.headers 21.109 + if resp.status in [204, 404]: 21.110 + return None 21.111 + if resp.status not in [200, 201, 202, 203]: 21.112 + raise RuntimeError(resp.reason) 21.113 + pin = sxp.Parser() 21.114 + data = resp.read() 21.115 + if DEBUG: print "***data" , data 21.116 + if DEBUG: print "***" 21.117 + pin.input(data); 21.118 + pin.input_eof() 21.119 + conn.close() 21.120 + val = pin.get_val() 21.121 + #if isinstance(val, types.ListType) and sxp.name(val) == 'val': 21.122 + # val = val[1] 21.123 + if isinstance(val, types.ListType) and sxp.name(val) == 'err': 21.124 + raise RuntimeError(val[1]) 21.125 + if DEBUG: print '**val=' 21.126 + #sxp.show(val); print 21.127 + PrettyPrint.prettyprint(val) 21.128 + if DEBUG: print '**' 21.129 + return val 21.130 + 21.131 +def xend_get(url, args=None): 21.132 + return xend_request(url, "GET", args) 21.133 + 21.134 +def xend_call(url, data): 21.135 + return xend_request(url, "POST", data) 21.136 + 21.137 +class Xend: 21.138 + 21.139 + SRV_DEFAULT = "localhost:8000" 21.140 + ROOT_DEFAULT = "/xend/" 21.141 + 21.142 + def __init__(self, srv=None, root=None): 21.143 + self.bind(srv, root) 21.144 + 21.145 + def bind(self, srv=None, root=None): 21.146 + if srv is None: srv = self.SRV_DEFAULT 21.147 + if root is None: root = self.ROOT_DEFAULT 21.148 + if not root.endswith('/'): root += '/' 21.149 + self.location = srv 21.150 + self.root = root 21.151 + 21.152 + def nodeurl(self, id=''): 21.153 + return nodeurl(self.location, self.root, id) 21.154 + 21.155 + def domainurl(self, id=''): 21.156 + return domainurl(self.location, self.root, id) 21.157 + 21.158 + def consoleurl(self, id=''): 21.159 + return consoleurl(self.location, self.root, id) 21.160 + 21.161 + def vbdurl(self, id=''): 21.162 + return vbdurl(self.location, self.root, id) 21.163 + 21.164 + def deviceurl(self, id=''): 21.165 + return deviceurl(self.location, self.root, id) 21.166 + 21.167 + def vneturl(self, id=''): 21.168 + return vneturl(self.location, self.root, id) 21.169 + 21.170 + def eventurl(self, id=''): 21.171 + return eventurl(self.location, self.root, id) 21.172 + 21.173 + def xend(self): 21.174 + return xend_get(urljoin(self.location, self.root)) 21.175 + 21.176 + def xend_node(self): 21.177 + return xend_get(self.nodeurl()) 21.178 + 21.179 + def xend_node_cpu_rrobin_slice_set(self, slice): 21.180 + return xend_call(self.nodeurl(), 21.181 + {'op' : 'cpu_rrobin_slice_set', 21.182 + 'slice' : slice }) 21.183 + 21.184 + def xend_node_cpu_bvt_slice_set(self, slice): 21.185 + return xend_call(self.nodeurl(), 21.186 + {'op' : 'cpu_bvt_slice_set', 21.187 + 'slice' : slice }) 21.188 + 21.189 + def xend_domains(self): 21.190 + return xend_get(self.domainurl()) 21.191 + 21.192 + def xend_domain_create(self, conf): 21.193 + return xend_call(self.domainurl(), 21.194 + {'op' : 'create', 21.195 + 'config' : fileof(conf) }) 21.196 + 21.197 + def xend_domain(self, id): 21.198 + return xend_get(self.domainurl(id)) 21.199 + 21.200 + def xend_domain_start(self, id): 21.201 + return xend_call(self.domainurl(id), 21.202 + {'op' : 'start'}) 21.203 + 21.204 + def xend_domain_stop(self, id): 21.205 + return xend_call(self.domainurl(id), 21.206 + {'op' : 'stop'}) 21.207 + 21.208 + def xend_domain_shutdown(self, id): 21.209 + return xend_call(self.domainurl(id), 21.210 + {'op' : 'shutdown'}) 21.211 + 21.212 + def xend_domain_halt(self, id): 21.213 + return xend_call(self.domainurl(id), 21.214 + {'op' : 'halt'}) 21.215 + 21.216 + def xend_domain_save(self, id, filename): 21.217 + return xend_call(self.domainurl(id), 21.218 + {'op' : 'save', 21.219 + 'file' : filename}) 21.220 + 21.221 + def xend_domain_restore(self, id, filename, conf): 21.222 + return xend_call(self.domainurl(id), 21.223 + {'op' : 'restore', 21.224 + 'file' : filename, 21.225 + 'config' : fileof(conf) }) 21.226 + 21.227 + def xend_domain_migrate(self, id, dst): 21.228 + return xend_call(self.domainurl(id), 21.229 + {'op' : 'migrate', 21.230 + 'dst' : dst}) 21.231 + 21.232 + def xend_domain_pincpu(self, id, cpu): 21.233 + return xend_call(self.domainurl(id), 21.234 + {'op' : 'pincpu', 21.235 + 'cpu' : cpu}) 21.236 + 21.237 + def xend_domain_cpu_bvt_set(self, id, mcuadv, warp, warpl, warpu): 21.238 + return xend_call(self.domainurl(id), 21.239 + {'op' : 'cpu_bvt_set', 21.240 + 'mcuadv' : mvuadv, 21.241 + 'warp' : warp, 21.242 + 'warpl' : warpl, 21.243 + 'warpu' : warpu }) 21.244 + 21.245 + def xend_domain_cpu_atropos_set(self, id, period, slice, latency, xtratime): 21.246 + return xend_call(self.domainurl(id), 21.247 + {'op' : 'cpu_atropos_set', 21.248 + 'period' : period, 21.249 + 'slice' : slice, 21.250 + 'latency' : latency, 21.251 + 'xtratime': xtratime }) 21.252 + 21.253 + def xend_domain_vifs(self, id): 21.254 + return xend_get(self.domainurl(id), 21.255 + { 'op' : 'vifs' }) 21.256 + 21.257 + def xend_domain_vif_stats(self, id, vif): 21.258 + return xend_get(self.domainurl(id), 21.259 + { 'op' : 'vif_stats', 21.260 + 'vif' : vif}) 21.261 + 21.262 + def xend_domain_vif_ip_add(self, id, vif, ipaddr): 21.263 + return xend_call(self.domainurl(id), 21.264 + {'op' : 'vif_ip_add', 21.265 + 'vif' : vif, 21.266 + 'ip' : ipaddr }) 21.267 + 21.268 + def xend_domain_vif_scheduler_set(id, vif, bytes, usecs): 21.269 + return xend_call(self.domainurl(id), 21.270 + {'op' : 'vif_scheduler_set', 21.271 + 'vif' : vif, 21.272 + 'bytes' : bytes, 21.273 + 'usecs' : usecs }) 21.274 + 21.275 + def xend_domain_vif_scheduler_get(id, vif): 21.276 + return xend_get(self.domainurl(id), 21.277 + {'op' : 'vif_scheduler_get', 21.278 + 'vif' : vif}) 21.279 + 21.280 + def xend_domain_vbds(self, id): 21.281 + return xend_get(self.domainurl(id), 21.282 + {'op' : 'vbds'}) 21.283 + 21.284 + def xend_domain_vbd(self, id, vbd): 21.285 + return xend_get(self.domainurl(id), 21.286 + {'op' : 'vbd', 21.287 + 'vbd' : vbd}) 21.288 + 21.289 + def xend_domain_vbd_add(self, id, uname, dev, mode): 21.290 + return xend_call(self.domainurl(id), 21.291 + {'op' : 'vbd_add', 21.292 + 'uname' : uname, 21.293 + 'dev' : dev, 21.294 + 'mode' : mode}) 21.295 + 21.296 + def xend_domain_vbd_remove(self, id, dev): 21.297 + return xend_call(self.domainurl(id), 21.298 + {'op' : 'vbd_remove', 21.299 + 'dev' : dev}) 21.300 + 21.301 + def xend_consoles(self): 21.302 + return xend_get(self.consoleurl()) 21.303 + 21.304 + def xend_console(self, id): 21.305 + return xend_get(self.consoleurl(id)) 21.306 + 21.307 + def xend_vbds(self): 21.308 + return xend_get(self.vbdurl()) 21.309 + 21.310 + def xend_vbd_create(self, conf): 21.311 + return xend_call(self.vbdurl(), 21.312 + {'op': 'create', 'config': fileof(conf) }) 21.313 + 21.314 + def xend_vbd(self, id): 21.315 + return xend_get(self.vbdurl(id)) 21.316 + 21.317 + def xend_vbd_delete(self, id): 21.318 + return xend_call(self.vbdurl(id), 21.319 + {'op': 'delete'}) 21.320 + 21.321 + def xend_vbd_refresh(self, id, expiry): 21.322 + return xend_call(self.vbdurl(id), 21.323 + {'op': 'refresh', 'expiry': expiry }) 21.324 + 21.325 + def xend_vbd_expand(self, id, size): 21.326 + return xend_call(self.vbdurl(id), 21.327 + {'op': 'expand', 'size': size}) 21.328 + 21.329 + def xend_vnets(self): 21.330 + return xend_get(self.vneturl()) 21.331 + 21.332 + def xend_vnet_create(self, conf): 21.333 + return xend_call(self.vneturl(), 21.334 + {'op': 'create', 'config': fileof(conf) }) 21.335 + 21.336 + def xend_vnet(self, id): 21.337 + return xend_get(self.vneturl(id)) 21.338 + 21.339 + def xend_vnet_delete(self, id): 21.340 + return xend_call(self.vneturl(id), 21.341 + {'op': 'delete'}) 21.342 + 21.343 + def xend_event_inject(self, sxpr): 21.344 + val = xend_call(self.eventurl(), 21.345 + {'op': 'inject', 'event': fileof(sxpr) }) 21.346 + 21.347 + 21.348 +def main(argv): 21.349 + """Call an API function: 21.350 + 21.351 + python XendClient.py fn args... 21.352 + 21.353 + The leading 'xend_' on the function can be omitted. 21.354 + Example: 21.355 + 21.356 + > python XendClient.py domains 21.357 + (domain 0 8) 21.358 + > python XendClient.py domain 0 21.359 + (domain (id 0) (name Domain-0) (memory 128)) 21.360 + """ 21.361 + server = Xend() 21.362 + fn = argv[1] 21.363 + if not fn.startswith('xend'): 21.364 + fn = 'xend_' + fn 21.365 + args = argv[2:] 21.366 + getattr(server, fn)(*args) 21.367 + 21.368 +if __name__ == "__main__": 21.369 + main(sys.argv) 21.370 +else: 21.371 + server = Xend()
22.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 22.2 +++ b/tools/xenmgr/lib/XendConsole.py Fri Jun 11 18:31:12 2004 +0000 22.3 @@ -0,0 +1,172 @@ 22.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com> 22.5 + 22.6 +import socket 22.7 +import Xc 22.8 +xc = Xc.new() 22.9 + 22.10 +import sxp 22.11 +import XendRoot 22.12 +xroot = XendRoot.instance() 22.13 +import XendDB 22.14 + 22.15 +import EventServer 22.16 +eserver = EventServer.instance() 22.17 + 22.18 +from xenmgr.server import SrvConsoleServer 22.19 +xcd = SrvConsoleServer.instance() 22.20 + 22.21 +class XendConsoleInfo: 22.22 + """Console information record. 22.23 + """ 22.24 + 22.25 + def __init__(self, console, dom1, port1, dom2, port2, conn=None): 22.26 + self.console = console 22.27 + self.dom1 = dom1 22.28 + self.port1 = port1 22.29 + self.dom2 = dom2 22.30 + self.port2 = port2 22.31 + self.conn = conn 22.32 + #self.id = "%d.%d-%d.%d" % (self.dom1, self.port1, self.dom2, self.port2) 22.33 + self.id = str(port1) 22.34 + 22.35 + def __str__(self): 22.36 + s = "console" 22.37 + s += " id=%s" % self.id 22.38 + s += " src=%d.%d" % (self.dom1, self.port1) 22.39 + s += " dst=%d.%d" % (self.dom2, self.port2) 22.40 + s += " port=%s" % self.console 22.41 + if self.conn: 22.42 + s += " conn=%s:%s" % (self.conn[0], self.conn[1]) 22.43 + return s 22.44 + 22.45 + def sxpr(self): 22.46 + sxpr = ['console', 22.47 + ['id', self.id], 22.48 + ['src', self.dom1, self.port1], 22.49 + ['dst', self.dom2, self.port2], 22.50 + ['port', self.console], 22.51 + ] 22.52 + if self.conn: 22.53 + sxpr.append(['connected', self.conn[0], self.conn[1]]) 22.54 + return sxpr 22.55 + 22.56 + def connection(self): 22.57 + return self.conn 22.58 + 22.59 + def update(self, consinfo): 22.60 + conn = sxp.child(consinfo, 'connected') 22.61 + if conn: 22.62 + self.conn = conn[1:] 22.63 + else: 22.64 + self.conn = None 22.65 + 22.66 + def uri(self): 22.67 + """Get the uri to use to connect to the console. 22.68 + This will be a telnet: uri. 22.69 + 22.70 + return uri 22.71 + """ 22.72 + host = socket.gethostname() 22.73 + return "telnet://%s:%s" % (host, self.console) 22.74 + 22.75 +class XendConsole: 22.76 + 22.77 + dbpath = "console" 22.78 + 22.79 + def __init__(self): 22.80 + self.db = XendDB.XendDB(self.dbpath) 22.81 + self.console = {} 22.82 + self.console_db = self.db.fetchall("") 22.83 + if xroot.get_rebooted(): 22.84 + print 'XendConsole> rebooted: removing all console info' 22.85 + self.rm_all() 22.86 + eserver.subscribe('xend.domain.died', self.onDomainDied) 22.87 + 22.88 + def rm_all(self): 22.89 + """Remove all console info. Used after reboot. 22.90 + """ 22.91 + for (k, v) in self.console_db.items(): 22.92 + self._delete_console(k) 22.93 + 22.94 + def refresh(self): 22.95 + consoles = xcd.consoles() 22.96 + cons = {} 22.97 + for consinfo in consoles: 22.98 + id = str(sxp.child_value(consinfo, 'id')) 22.99 + cons[id] = consinfo 22.100 + if id not in self.console: 22.101 + self._new_console(consinfo) 22.102 + for c in self.console.values(): 22.103 + consinfo = cons.get(c.id) 22.104 + if consinfo: 22.105 + c.update(consinfo) 22.106 + else: 22.107 + self._delete_console(c.id) 22.108 + 22.109 + def onDomainDied(self, event, val): 22.110 + dom = int(val) 22.111 + for c in self.consoles(): 22.112 + if (c.dom1 == dom) or (c.dom2 == dom): 22.113 + self._delete_console(c.id) 22.114 + 22.115 + def sync(self): 22.116 + self.db.saveall("", self.console_db) 22.117 + 22.118 + def sync_console(self, id): 22.119 + self.db.save(id, self.console_db[id]) 22.120 + 22.121 + def _new_console(self, consinfo): 22.122 + # todo: xen needs a call to get current domain id. 22.123 + dom1 = 0 22.124 + port1 = sxp.child_value(consinfo, 'local_port') 22.125 + dom2 = sxp.child_value(consinfo, 'domain') 22.126 + port2 = sxp.child_value(consinfo, 'remote_port') 22.127 + console = sxp.child_value(consinfo, 'console_port') 22.128 + info = XendConsoleInfo(console, dom1, int(port1), int(dom2), int(port2)) 22.129 + info.update(consinfo) 22.130 + self._add_console(info.id, info) 22.131 + return info 22.132 + 22.133 + def _add_console(self, id, info): 22.134 + self.console[id] = info 22.135 + self.console_db[id] = info.sxpr() 22.136 + self.sync_console(id) 22.137 + 22.138 + def _delete_console(self, id): 22.139 + if id in self.console: 22.140 + del self.console[id] 22.141 + if id in self.console_db: 22.142 + del self.console_db[id] 22.143 + self.db.delete(id) 22.144 + 22.145 + def console_ls(self): 22.146 + self.refresh() 22.147 + return self.console.keys() 22.148 + 22.149 + def consoles(self): 22.150 + self.refresh() 22.151 + return self.console.values() 22.152 + 22.153 + def console_create(self, dom): 22.154 + consinfo = xcd.console_create(dom) 22.155 + info = self._new_console(consinfo) 22.156 + return info 22.157 + 22.158 + def console_get(self, id): 22.159 + self.refresh() 22.160 + return self.console.get(id) 22.161 + 22.162 + def console_delete(self, id): 22.163 + self._delete_console(id) 22.164 + 22.165 + def console_disconnect(self, id): 22.166 + id = int(id) 22.167 + xcd.console_disconnect(id) 22.168 + 22.169 +def instance(): 22.170 + global inst 22.171 + try: 22.172 + inst 22.173 + except: 22.174 + inst = XendConsole() 22.175 + return inst
23.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 23.2 +++ b/tools/xenmgr/lib/XendDB.py Fri Jun 11 18:31:12 2004 +0000 23.3 @@ -0,0 +1,91 @@ 23.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com> 23.5 + 23.6 +import os 23.7 +import os.path 23.8 +import errno 23.9 +import dircache 23.10 +import time 23.11 + 23.12 +import sxp 23.13 +import XendRoot 23.14 +xroot = XendRoot.instance() 23.15 + 23.16 +class XendDB: 23.17 + """Persistence for Xend. Stores data in files and directories. 23.18 + """ 23.19 + 23.20 + def __init__(self, path=None): 23.21 + self.dbpath = xroot.get_dbroot() 23.22 + if path: 23.23 + self.dbpath = os.path.join(self.dbpath, path) 23.24 + pass 23.25 + 23.26 + def filepath(self, path): 23.27 + return os.path.join(self.dbpath, path) 23.28 + 23.29 + def fetch(self, path): 23.30 + fpath = self.filepath(path) 23.31 + return self.fetchfile(fpath) 23.32 + 23.33 + def fetchfile(self, fpath): 23.34 + pin = sxp.Parser() 23.35 + fin = file(fpath, "rb") 23.36 + try: 23.37 + while 1: 23.38 + try: 23.39 + buf = fin.read(1024) 23.40 + except IOError, ex: 23.41 + if ex.errno == errno.EINTR: 23.42 + continue 23.43 + else: 23.44 + raise 23.45 + pin.input(buf) 23.46 + if buf == '': 23.47 + pin.input_eof() 23.48 + break 23.49 + finally: 23.50 + fin.close() 23.51 + return pin.get_val() 23.52 + 23.53 + def save(self, path, sxpr): 23.54 + fpath = self.filepath(path) 23.55 + return self.savefile(fpath, sxpr) 23.56 + 23.57 + def savefile(self, fpath, sxpr): 23.58 + fdir = os.path.dirname(fpath) 23.59 + if not os.path.isdir(fdir): 23.60 + os.makedirs(fdir) 23.61 + fout = file(fpath, "wb+") 23.62 + try: 23.63 + t = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) 23.64 + fout.write("# %s %s\n" % (fpath, t)) 23.65 + sxp.show(sxpr, out=fout) 23.66 + finally: 23.67 + fout.close() 23.68 + 23.69 + def fetchall(self, path): 23.70 + dpath = self.filepath(path) 23.71 + d = {} 23.72 + for k in dircache.listdir(dpath): 23.73 + try: 23.74 + v = self.fetchfile(os.path.join(dpath, k)) 23.75 + d[k] = v 23.76 + except: 23.77 + pass 23.78 + return d 23.79 + 23.80 + def saveall(self, path, d): 23.81 + for (k, v) in d.items(): 23.82 + self.save(os.path.join(path, k), v) 23.83 + 23.84 + def delete(self, path): 23.85 + dpath = self.filepath(path) 23.86 + os.unlink(dpath) 23.87 + 23.88 + def ls(self, path): 23.89 + dpath = self.filepath(path) 23.90 + return dircache.listdir(dpath) 23.91 + 23.92 + 23.93 + 23.94 +
24.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 24.2 +++ b/tools/xenmgr/lib/XendDomain.py Fri Jun 11 18:31:12 2004 +0000 24.3 @@ -0,0 +1,347 @@ 24.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com> 24.5 + 24.6 +"""Handler for domain operations. 24.7 + Nothing here is persistent (across reboots). 24.8 + Needs to be persistent for one uptime. 24.9 +""" 24.10 +import sys 24.11 + 24.12 +import Xc; xc = Xc.new() 24.13 +import xenctl.ip 24.14 +import xenctl.vdisk 24.15 + 24.16 +import sxp 24.17 +import XendRoot 24.18 +xroot = XendRoot.instance() 24.19 +import XendDB 24.20 +import XendDomainInfo 24.21 +import XendConsole 24.22 +import EventServer 24.23 + 24.24 +eserver = EventServer.instance() 24.25 + 24.26 +__all__ = [ "XendDomain" ] 24.27 + 24.28 +class XendDomain: 24.29 + """Index of all domains. Singleton. 24.30 + """ 24.31 + 24.32 + dbpath = "domain" 24.33 + domain = {} 24.34 + 24.35 + def __init__(self): 24.36 + self.xconsole = XendConsole.instance() 24.37 + # Table of domain info indexed by domain id. 24.38 + self.db = XendDB.XendDB(self.dbpath) 24.39 + #self.domain = {} 24.40 + self.domain_db = self.db.fetchall("") 24.41 + if xroot.get_rebooted(): 24.42 + print 'XendDomain> rebooted: removing all domain info' 24.43 + self.rm_all() 24.44 + self.initial_refresh() 24.45 + 24.46 + def rm_all(self): 24.47 + """Remove all domain info. Used after reboot. 24.48 + """ 24.49 + for (k, v) in self.domain_db.items(): 24.50 + self._delete_domain(k, notify=0) 24.51 + 24.52 + def initial_refresh(self): 24.53 + """Refresh initial domain info from domain_db. 24.54 + """ 24.55 + domlist = xc.domain_getinfo() 24.56 + doms = {} 24.57 + for d in domlist: 24.58 + domid = str(d['dom']) 24.59 + doms[domid] = d 24.60 + for config in self.domain_db.values(): 24.61 + domid = int(sxp.child_value(config, 'id')) 24.62 + if domid in doms: 24.63 + self._new_domain(config) 24.64 + else: 24.65 + self._delete_domain(domid) 24.66 + self.refresh() 24.67 + 24.68 + def sync(self): 24.69 + """Sync domain db to disk. 24.70 + """ 24.71 + self.db.saveall("", self.domain_db) 24.72 + 24.73 + def sync_domain(self, dom): 24.74 + """Sync info for a domain to disk. 24.75 + 24.76 + dom domain id (string) 24.77 + """ 24.78 + self.db.save(dom, self.domain_db[dom]) 24.79 + 24.80 + def close(self): 24.81 + pass 24.82 + 24.83 + def _new_domain(self, info): 24.84 + """Create a domain entry from saved info. 24.85 + """ 24.86 + console = None 24.87 + kernel = None 24.88 + id = sxp.child_value(info, 'id') 24.89 + dom = int(id) 24.90 + name = sxp.child_value(info, 'name') 24.91 + memory = int(sxp.child_value(info, 'memory')) 24.92 + consoleinfo = sxp.child(info, 'console') 24.93 + if consoleinfo: 24.94 + consoleid = sxp.child_value(consoleinfo, 'id') 24.95 + console = self.xconsole.console_get(consoleid) 24.96 + if dom and console is None: 24.97 + # Try to connect a console. 24.98 + console = self.xconsole.console_create(dom) 24.99 + config = sxp.child(info, 'config') 24.100 + if config: 24.101 + image = sxp.child(info, 'image') 24.102 + if image: 24.103 + image = sxp.child0(image) 24.104 + kernel = sxp.child_value(image, 'kernel') 24.105 + dominfo = XendDomainInfo.XendDomainInfo( 24.106 + config, dom, name, memory, kernel, console) 24.107 + self.domain[id] = dominfo 24.108 + 24.109 + def _add_domain(self, id, info, notify=1): 24.110 + self.domain[id] = info 24.111 + self.domain_db[id] = info.sxpr() 24.112 + self.sync_domain(id) 24.113 + if notify: eserver.inject('xend.domain.created', id) 24.114 + 24.115 + def _delete_domain(self, id, notify=1): 24.116 + if id in self.domain: 24.117 + if notify: eserver.inject('xend.domain.died', id) 24.118 + del self.domain[id] 24.119 + if id in self.domain_db: 24.120 + del self.domain_db[id] 24.121 + self.db.delete(id) 24.122 + 24.123 + def refresh(self): 24.124 + """Refresh domain list from Xen. 24.125 + """ 24.126 + domlist = xc.domain_getinfo() 24.127 + # Index the domlist by id. 24.128 + # Add entries for any domains we don't know about. 24.129 + doms = {} 24.130 + for d in domlist: 24.131 + id = str(d['dom']) 24.132 + doms[id] = d 24.133 + if id not in self.domain: 24.134 + config = None 24.135 + image = None 24.136 + newinfo = XendDomainInfo.XendDomainInfo( 24.137 + config, d['dom'], d['name'], d['mem_kb']/1024, image) 24.138 + self._add_domain(id, newinfo) 24.139 + # Remove entries for domains that no longer exist. 24.140 + for d in self.domain.values(): 24.141 + dominfo = doms.get(d.id) 24.142 + if dominfo: 24.143 + d.update(dominfo) 24.144 + else: 24.145 + self._delete_domain(d.id) 24.146 + 24.147 + def refresh_domain(self, id): 24.148 + dom = int(id) 24.149 + dominfo = xc.domain_getinfo(dom, 1) 24.150 + if dominfo == [] or dominfo[0]['dom'] != dom: 24.151 + try: 24.152 + self._delete_domain(id) 24.153 + except: 24.154 + pass 24.155 + else: 24.156 + d = self.domain.get(id) 24.157 + if d: 24.158 + d.update(dominfo) 24.159 + 24.160 + def domain_ls(self): 24.161 + # List domains. 24.162 + # Update info from kernel first. 24.163 + self.refresh() 24.164 + return self.domain.keys() 24.165 + 24.166 + def domains(self): 24.167 + self.refresh() 24.168 + return self.domain.values() 24.169 + 24.170 + def domain_create(self, config): 24.171 + # Create domain, log it. 24.172 + deferred = XendDomainInfo.vm_create(config) 24.173 + def fn(dominfo): 24.174 + self._add_domain(dominfo.id, dominfo) 24.175 + return dominfo 24.176 + deferred.addCallback(fn) 24.177 + return deferred 24.178 + 24.179 + def domain_get(self, id): 24.180 + id = str(id) 24.181 + self.refresh_domain(id) 24.182 + return self.domain[id] 24.183 + 24.184 + def domain_start(self, id): 24.185 + """Start domain running. 24.186 + """ 24.187 + dom = int(id) 24.188 + eserver.inject('xend.domain.start', id) 24.189 + return xc.domain_start(dom=dom) 24.190 + 24.191 + def domain_stop(self, id): 24.192 + """Stop domain running. 24.193 + """ 24.194 + dom = int(id) 24.195 + return xc.domain_stop(dom=dom) 24.196 + 24.197 + def domain_shutdown(self, id): 24.198 + """Shutdown domain (nicely). 24.199 + """ 24.200 + dom = int(id) 24.201 + if dom <= 0: 24.202 + return 0 24.203 + eserver.inject('xend.domain.shutdown', id) 24.204 + val = xc.domain_destroy(dom=dom, force=0) 24.205 + self.refresh() 24.206 + return val 24.207 + 24.208 + def domain_halt(self, id): 24.209 + """Shutdown domain immediately. 24.210 + """ 24.211 + dom = int(id) 24.212 + if dom <= 0: 24.213 + return 0 24.214 + eserver.inject('xend.domain.halt', id) 24.215 + val = xc.domain_destroy(dom=dom, force=1) 24.216 + self.refresh() 24.217 + return val 24.218 + 24.219 + def domain_migrate(self, id, dst): 24.220 + """Start domain migration. 24.221 + """ 24.222 + # Need a cancel too? 24.223 + pass 24.224 + 24.225 + def domain_save(self, id, dst, progress=0): 24.226 + """Save domain state to file, halt domain. 24.227 + """ 24.228 + dom = int(id) 24.229 + self.domain_stop(id) 24.230 + eserver.inject('xend.domain.save', id) 24.231 + rc = xc.linux_save(dom=dom, state_file=dst, progress=progress) 24.232 + if rc == 0: 24.233 + self.domain_halt(id) 24.234 + return rc 24.235 + 24.236 + def domain_restore(self, src, config, progress=0): 24.237 + """Restore domain from file. 24.238 + """ 24.239 + dominfo = XendDomainInfo.dom_restore(dom, config) 24.240 + self._add_domain(dominfo.id, dominfo) 24.241 + return dominfo 24.242 + 24.243 + def domain_device_add(self, id, info): 24.244 + """Add a device to a domain. 24.245 + """ 24.246 + pass 24.247 + 24.248 + def domain_device_remove(self, id, dev): 24.249 + """Delete a device from a domain. 24.250 + """ 24.251 + pass 24.252 + 24.253 + def domain_device_configure(self, id, dev, info): 24.254 + """Configure a domain device. 24.255 + """ 24.256 + pass 24.257 + 24.258 + #============================================================================ 24.259 + # Backward compatibility stuff from here on. 24.260 + 24.261 + def domain_pincpu(self, dom, cpu): 24.262 + dom = int(dom) 24.263 + return xc.domain_pincpu(dom, cpu) 24.264 + 24.265 + def domain_cpu_bvt_set(self, dom, mcuadv, warp, warpl, warpu): 24.266 + dom = int(dom) 24.267 + return xc.bvtsched_domain_set(dom=dom, mcuadv=mcuadv, 24.268 + warp=warp, warpl=warpl, warpu=warpu) 24.269 + 24.270 + def domain_cpu_bvt_get(self, dom): 24.271 + dom = int(dom) 24.272 + return xc.bvtsched_domain_get(dom) 24.273 + 24.274 + def domain_cpu_atropos_set(self, dom, period, slice, latency, xtratime): 24.275 + dom = int(dom) 24.276 + return xc.atropos_domain_set(dom, period, slice, latency, xtratime) 24.277 + 24.278 + def domain_cpu_atropos_get(self, dom): 24.279 + dom = int(dom) 24.280 + return xc.atropos_domain_get(dom) 24.281 + 24.282 + def domain_vif_ls(self, dom): 24.283 + dominfo = self.domain_get(dom) 24.284 + if not dominfo: return None 24.285 + devs = dominfo.get_devices('vif') 24.286 + return range(0, len(devs)) 24.287 + 24.288 + def domain_vif_get(self, dom, vif): 24.289 + dominfo = self.domain_get(dom) 24.290 + if not dominfo: return None 24.291 + return dominfo.get_device_by_index(vif) 24.292 + 24.293 + def domain_vif_stats(self, dom, vif): 24.294 + dom = int(dom) 24.295 + return xc.vif_stats_get(dom=dom, vif=vif) 24.296 + 24.297 + def domain_vif_ip_add(self, dom, vif, ip): 24.298 + dom = int(dom) 24.299 + return xenctl.ip.setup_vfr_rules_for_vif(dom, vif, ip) 24.300 + 24.301 + def domain_vif_scheduler_set(self, dom, vif, bytes, usecs): 24.302 + dom = int(dom) 24.303 + return xc.xc_vif_scheduler_set(dom=dom, vif=vif, 24.304 + credit_bytes=bytes, credit_usecs=usecs) 24.305 + 24.306 + def domain_vif_scheduler_get(self, dom, vif): 24.307 + dom = int(dom) 24.308 + return xc.vif_scheduler_get(dom=dom, vif=vif) 24.309 + 24.310 + def domain_vbd_ls(self, dom): 24.311 + dominfo = self.domain_get(dom) 24.312 + if not dominfo: return [] 24.313 + devs = dominfo.get_devices('vbd') 24.314 + return [ sxp.child_value(v, 'dev') for v in devs ] 24.315 + 24.316 + def domain_vbd_get(self, dom, vbd): 24.317 + dominfo = self.domain_get(dom) 24.318 + if not dominfo: return None 24.319 + devs = dominfo.get_devices('vbd') 24.320 + for v in devs: 24.321 + if sxp.child_value(v, 'dev') == vbd: 24.322 + return v 24.323 + return None 24.324 + 24.325 + def domain_vbd_add(self, dom, uname, dev, mode): 24.326 + dom = int(dom) 24.327 + vbd = vm.make_disk(dom, uname, dev, mode) 24.328 + return vbd 24.329 + 24.330 + def domain_vbd_remove(self, dom, dev): 24.331 + dom = int(dom) 24.332 + vbd = xenctl.vdisk.blkdev_name_to_number(dev) 24.333 + if vbd < 0: return vbd 24.334 + err = xc.vbd_destroy(dom, vbd) 24.335 + if err < 0: return err 24.336 + return vbd 24.337 + 24.338 + def domain_shadow_control(self, dom, op): 24.339 + dom = int(dom) 24.340 + return xc.shadow_control(dom, op) 24.341 + 24.342 + #============================================================================ 24.343 + 24.344 +def instance(): 24.345 + global inst 24.346 + try: 24.347 + inst 24.348 + except: 24.349 + inst = XendDomain() 24.350 + return inst
25.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 25.2 +++ b/tools/xenmgr/lib/XendDomainConfig.py Fri Jun 11 18:31:12 2004 +0000 25.3 @@ -0,0 +1,44 @@ 25.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com> 25.5 + 25.6 +"""Handler for persistent domain configs. 25.7 + 25.8 +""" 25.9 + 25.10 +import sxp 25.11 +import XendDB 25.12 +import XendDomain 25.13 + 25.14 +__all__ = [ "XendDomainConfig" ] 25.15 + 25.16 +class XendDomainConfig: 25.17 + 25.18 + dbpath = 'config' 25.19 + 25.20 + def __init__(self): 25.21 + self.db = XendDB.XendDB(self.dbpath) 25.22 + 25.23 + def domain_config_ls(self, path): 25.24 + return self.db.ls(path) 25.25 + 25.26 + def domain_config_create(self, path, sxpr): 25.27 + self.db.save(path, sxpr) 25.28 + pass 25.29 + 25.30 + def domain_config_delete(self, path): 25.31 + self.db.delete(path) 25.32 + 25.33 + def domain_config_instance(self, path): 25.34 + """Create a domain from a config. 25.35 + """ 25.36 + config = self.db.fetch(path) 25.37 + xd = XendDomain.instance() 25.38 + newdom = xd.domain_create(config) 25.39 + return newdom 25.40 + 25.41 +def instance(): 25.42 + global inst 25.43 + try: 25.44 + inst 25.45 + except: 25.46 + inst = XendDomainConfig() 25.47 + return inst
26.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 26.2 +++ b/tools/xenmgr/lib/XendDomainInfo.py Fri Jun 11 18:31:12 2004 +0000 26.3 @@ -0,0 +1,697 @@ 26.4 +#!/usr/bin/python 26.5 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com> 26.6 + 26.7 +"""Representation of a single domain. 26.8 +Includes support for domain construction, using 26.9 +open-ended configurations. 26.10 + 26.11 +Author: Mike Wray <mike.wray@hpl.hp.com> 26.12 + 26.13 +""" 26.14 + 26.15 +import sys 26.16 +import os 26.17 + 26.18 +from twisted.internet import defer 26.19 + 26.20 +import Xc; xc = Xc.new() 26.21 + 26.22 +import xenctl.ip 26.23 +import xenctl.vdisk 26.24 + 26.25 +import sxp 26.26 + 26.27 +import XendConsole 26.28 +xendConsole = XendConsole.instance() 26.29 + 26.30 +import server.SrvConsoleServer 26.31 +xend = server.SrvConsoleServer.instance() 26.32 + 26.33 +class VmError(ValueError): 26.34 + """Vm construction error.""" 26.35 + 26.36 + def __init__(self, value): 26.37 + self.value = value 26.38 + 26.39 + def __str__(self): 26.40 + return self.value 26.41 + 26.42 + 26.43 +class XendDomainInfo: 26.44 + """Virtual machine object.""" 26.45 + 26.46 + def __init__(self, config, dom, name, memory, image=None, console=None): 26.47 + """Construct a virtual machine object. 26.48 + 26.49 + config configuration 26.50 + dom domain id 26.51 + name name 26.52 + memory memory size (in MB) 26.53 + image image object 26.54 + """ 26.55 + #todo: add info: runtime, state, ... 26.56 + self.config = config 26.57 + self.id = str(dom) 26.58 + self.dom = dom 26.59 + self.name = name 26.60 + self.memory = memory 26.61 + self.image = image 26.62 + self.console = console 26.63 + self.devices = {} 26.64 + self.configs = [] 26.65 + self.info = None 26.66 + 26.67 + #todo: state: running, suspended 26.68 + self.state = 'running' 26.69 + #todo: set to migrate info if migrating 26.70 + self.migrate = None 26.71 + 26.72 + def update(self, info): 26.73 + """Update with info from xc.domain_getinfo(). 26.74 + """ 26.75 + self.info = info 26.76 + 26.77 + def __str__(self): 26.78 + s = "domain" 26.79 + s += " id=" + self.id 26.80 + s += " name=" + self.name 26.81 + s += " memory=" + str(self.memory) 26.82 + if self.console: 26.83 + s += " console=" + self.console.id 26.84 + if self.image: 26.85 + s += " image=" + self.image 26.86 + s += "" 26.87 + return s 26.88 + 26.89 + __repr__ = __str__ 26.90 + 26.91 + def sxpr(self): 26.92 + sxpr = ['domain', 26.93 + ['id', self.id], 26.94 + ['name', self.name], 26.95 + ['memory', self.memory] ] 26.96 + if self.info: 26.97 + run = (self.info['running'] and 'r') or '-' 26.98 + stop = (self.info['stopped'] and 's') or '-' 26.99 + state = run + state 26.100 + sxpr.append(['cpu', self.info['cpu']]) 26.101 + sxpr.append(['state', state]) 26.102 + sxpr.append(['cpu_time', self.info['cpu_time']/1e8]) 26.103 + if self.console: 26.104 + sxpr.append(self.console.sxpr()) 26.105 + if self.config: 26.106 + sxpr.append(['config', self.config]) 26.107 + return sxpr 26.108 + 26.109 + def add_device(self, type, dev): 26.110 + """Add a device to a virtual machine. 26.111 + 26.112 + dev device to add 26.113 + """ 26.114 + dl = self.devices.get(type, []) 26.115 + dl.append(dev) 26.116 + self.devices[type] = dl 26.117 + 26.118 + def get_devices(self, type): 26.119 + val = self.devices.get(type, []) 26.120 + print 'get_devices', type; sxp.show(val); print 26.121 + return val 26.122 + 26.123 + def get_device_by_id(self, type, id): 26.124 + """Get the device with the given id. 26.125 + 26.126 + id device id 26.127 + 26.128 + returns device or None 26.129 + """ 26.130 + return sxp.child_with_id(self.get_devices(type), id) 26.131 + 26.132 + def get_device_by_index(self, type, idx): 26.133 + dl = self.get_devices(type) 26.134 + if 0 <= idx < len(dl): 26.135 + return dl[idx] 26.136 + else: 26.137 + return None 26.138 + 26.139 + def add_config(self, val): 26.140 + """Add configuration data to a virtual machine. 26.141 + 26.142 + val data to add 26.143 + """ 26.144 + self.configs.append(val) 26.145 + 26.146 + def destroy(self): 26.147 + if self.dom <= 0: 26.148 + return 0 26.149 + return xc.domain_destroy(dom=self.dom, force=1) 26.150 + 26.151 + def show(self): 26.152 + """Print virtual machine info. 26.153 + """ 26.154 + print "[VM dom=%d name=%s memory=%d" % (self.dom, self.name, self.memory) 26.155 + print "image:" 26.156 + sxp.show(self.image) 26.157 + print 26.158 + for dl in self.devices: 26.159 + for dev in dl: 26.160 + print "device:" 26.161 + sxp.show(dev) 26.162 + print 26.163 + for val in self.configs: 26.164 + print "config:" 26.165 + sxp.show(val) 26.166 + print 26.167 + print "]" 26.168 + 26.169 +def safety_level(sharing): 26.170 + if sharing == 'rw': 26.171 + return xenctl.vdisk.VBD_SAFETY_RW 26.172 + if sharing == 'ww': 26.173 + return xenctl.vdisk.VBD_SAFETY_WW 26.174 + return xenctl.vdisk.VBD_SAFETY_RR 26.175 + 26.176 + 26.177 +def make_disk_old(dom, uname, dev, mode, sharing): 26.178 + writeable = ('w' in mode) 26.179 + safety = safety_level(sharing) 26.180 + vbd = xenctl.vdisk.blkdev_name_to_number(dev) 26.181 + extents = xenctl.vdisk.lookup_disk_uname(uname) 26.182 + if not extents: 26.183 + raise VmError("vbd: Extents not found: uname=%s" % uname) 26.184 + 26.185 + # check that setting up this VBD won't violate the sharing 26.186 + # allowed by the current VBD expertise level 26.187 + if xenctl.vdisk.vd_extents_validate(extents, writeable, safety=safety) < 0: 26.188 + raise VmError("vbd: Extents invalid: uname=%s" % uname) 26.189 + 26.190 + if xc.vbd_create(dom=dom, vbd=vbd, writeable=writeable): 26.191 + raise VmError("vbd: Creating device failed: dom=%d uname=%s vbd=%d mode=%s" 26.192 + % (dom, uname, vbdmode)) 26.193 + 26.194 + if xc.vbd_setextents(dom=dom, vbd=vbd, extents=extents): 26.195 + raise VMError("vbd: Setting extents failed: dom=%d uname=%s vbd=%d" 26.196 + % (dom, uname, vbd)) 26.197 + return vbd 26.198 + 26.199 +def make_disk(dom, uname, dev, mode, sharing): 26.200 + """Create a virtual disk device for a domain. 26.201 + 26.202 + @returns Deferred 26.203 + """ 26.204 + segments = xenctl.vdisk.lookup_disk_uname(uname) 26.205 + if not segments: 26.206 + raise VmError("vbd: Segments not found: uname=%s" % uname) 26.207 + if len(segments) > 1: 26.208 + raise VmError("vbd: Multi-segment vdisk: uname=%s" % uname) 26.209 + segment = segments[0] 26.210 + vdev = xenctl.vdisk.blkdev_name_to_number(dev) 26.211 + ctrl = xend.blkif_create(dom) 26.212 + 26.213 + def fn(ctrl): 26.214 + return xend.blkif_dev_create(dom, vdev, mode, segment) 26.215 + ctrl.addCallback(fn) 26.216 + return ctrl 26.217 + 26.218 +def make_vif_old(dom, vif, vmac, vnet): 26.219 + return # todo: Not supported yet. 26.220 + err = xc.vif_setinfo(dom=dom, vif=vif, vmac=vmac, vnet=vnet) 26.221 + if err < 0: 26.222 + raise VmError('vnet: Error %d setting vif mac dom=%d vif=%d vmac=%s vnet=%d' % 26.223 + (err, dom, vif, vmac, vnet)) 26.224 + 26.225 +def make_vif(dom, vif, vmac): 26.226 + """Create a virtual network device for a domain. 26.227 + 26.228 + 26.229 + @returns Deferred 26.230 + """ 26.231 + xend.netif_create(dom) 26.232 + d = xend.netif_dev_create(dom, vif, vmac) 26.233 + return d 26.234 + 26.235 +def vif_up(iplist): 26.236 + #todo: Need a better way. 26.237 + # send an unsolicited ARP reply for all non link-local IPs 26.238 + 26.239 + IP_NONLOCAL_BIND = '/proc/sys/net/ipv4/ip_nonlocal_bind' 26.240 + 26.241 + def get_ip_nonlocal_bind(): 26.242 + return int(open(IP_NONLOCAL_BIND, 'r').read()[0]) 26.243 + 26.244 + def set_ip_nonlocal_bind(v): 26.245 + print >> open(IP_NONLOCAL_BIND, 'w'), str(v) 26.246 + 26.247 + def link_local(ip): 26.248 + return xenctl.ip.check_subnet(ip, '169.254.0.0', '255.255.0.0') 26.249 + 26.250 + def arping(ip, gw): 26.251 + cmd = '/usr/sbin/arping -A -b -I eth0 -c 1 -s %s %s' % (ip, gw) 26.252 + print cmd 26.253 + os.system(cmd) 26.254 + 26.255 + gateway = xenctl.ip.get_current_ipgw() or '255.255.255.255' 26.256 + nlb = get_ip_nonlocal_bind() 26.257 + if not nlb: set_ip_nonlocal_bind(1) 26.258 + try: 26.259 + for ip in iplist: 26.260 + if not link_local(ip): 26.261 + arping(ip, gateway) 26.262 + finally: 26.263 + if not nlb: set_ip_nonlocal_bind(0) 26.264 + 26.265 +def xen_domain_create(config, ostype, name, memory, kernel, ramdisk, cmdline, vifs_n): 26.266 + if not os.path.isfile(kernel): 26.267 + raise VmError('Kernel image does not exist: %s' % kernel) 26.268 + if ramdisk and not os.path.isfile(ramdisk): 26.269 + raise VMError('Kernel ramdisk does not exist: %s' % ramdisk) 26.270 + 26.271 + cpu = int(sxp.child_value(config, 'cpu', '-1')) 26.272 + dom = xc.domain_create(mem_kb= memory * 1024, name= name, cpu= cpu) 26.273 + if dom <= 0: 26.274 + raise VmError('Creating domain failed: name=%s memory=%d kernel=%s' 26.275 + % (name, memory, kernel)) 26.276 + console = xendConsole.console_create(dom) 26.277 + buildfn = getattr(xc, '%s_build' % ostype) 26.278 + err = buildfn(dom = dom, 26.279 + image = kernel, 26.280 + control_evtchn = console.port2, 26.281 + cmdline = cmdline, 26.282 + ramdisk = ramdisk) 26.283 + if err != 0: 26.284 + raise VmError('Building domain failed: type=%s dom=%d err=%d' 26.285 + % (ostype, dom, err)) 26.286 + vm = XendDomainInfo(config, dom, name, memory, kernel, console) 26.287 + return vm 26.288 + 26.289 +config_handlers = {} 26.290 + 26.291 +def add_config_handler(name, h): 26.292 + """Add a handler for a config field. 26.293 + 26.294 + name field name 26.295 + h handler: fn(vm, config, field, index) 26.296 + """ 26.297 + config_handlers[name] = h 26.298 + 26.299 +def get_config_handler(name): 26.300 + """Get a handler for a config field. 26.301 + 26.302 + returns handler or None 26.303 + """ 26.304 + return config_handlers.get(name) 26.305 + 26.306 +"""Table of handlers for virtual machine images. 26.307 +Indexed by image type. 26.308 +""" 26.309 +image_handlers = {} 26.310 + 26.311 +def add_image_handler(name, h): 26.312 + """Add a handler for an image type 26.313 + name image type 26.314 + h handler: fn(config, name, memory, image) 26.315 + """ 26.316 + image_handlers[name] = h 26.317 + 26.318 +def get_image_handler(name): 26.319 + """Get the handler for an image type. 26.320 + name image type 26.321 + 26.322 + returns handler or None 26.323 + """ 26.324 + return image_handlers.get(name) 26.325 + 26.326 +"""Table of handlers for devices. 26.327 +Indexed by device type. 26.328 +""" 26.329 +device_handlers = {} 26.330 + 26.331 +def add_device_handler(name, h): 26.332 + """Add a handler for a device type. 26.333 + 26.334 + name device type 26.335 + h handler: fn(vm, dev) 26.336 + """ 26.337 + device_handlers[name] = h 26.338 + 26.339 +def get_device_handler(name): 26.340 + """Get the handler for a device type. 26.341 + 26.342 + name device type 26.343 + 26.344 + returns handler or None 26.345 + """ 26.346 + return device_handlers.get(name) 26.347 + 26.348 +def vm_create(config): 26.349 + """Create a VM from a configuration. 26.350 + If a vm has been partially created and there is an error it 26.351 + is destroyed. 26.352 + 26.353 + config configuration 26.354 + 26.355 + returns Deferred 26.356 + raises VmError for invalid configuration 26.357 + """ 26.358 + # todo - add support for scheduling params? 26.359 + print 'vm_create>' 26.360 + xenctl.vdisk.VBD_EXPERT_MODE = 0 26.361 + vm = None 26.362 + try: 26.363 + name = sxp.child_value(config, 'name') 26.364 + memory = int(sxp.child_value(config, 'memory', '128')) 26.365 + image = sxp.child_value(config, 'image') 26.366 + 26.367 + image_name = sxp.name(image) 26.368 + image_handler = get_image_handler(image_name) 26.369 + if image_handler is None: 26.370 + raise VmError('unknown image type: ' + image_name) 26.371 + vm = image_handler(config, name, memory, image) 26.372 + deferred = vm_configure(vm, config) 26.373 + except StandardError, ex: 26.374 + # Catch errors, cleanup and re-raise. 26.375 + if vm: 26.376 + vm.destroy() 26.377 + raise 26.378 + def cbok(x): 26.379 + print 'vm_create> cbok', x 26.380 + return x 26.381 + deferred.addCallback(cbok) 26.382 + print 'vm_create<' 26.383 + return deferred 26.384 + 26.385 +def vm_restore(src, config, progress=0): 26.386 + ostype = "linux" #todo set from config 26.387 + restorefn = getattr(xc, "%s_restore" % ostype) 26.388 + dom = restorefn(state_file=src, progress=progress) 26.389 + if dom < 0: return dom 26.390 + deferred = dom_configure(dom, config) 26.391 + return deferred 26.392 + 26.393 +def dom_get(dom): 26.394 + domlist = xc.domain_getinfo(dom=dom) 26.395 + if domlist and dom == domlist[0]['dom']: 26.396 + return domlist[0] 26.397 + return None 26.398 + 26.399 +def dom_configure(dom, config): 26.400 + d = dom_get(dom) 26.401 + if not d: 26.402 + raise VMError("Domain not found: %d" % dom) 26.403 + try: 26.404 + name = d['name'] 26.405 + memory = d['memory']/1024 26.406 + image = None 26.407 + vm = VM(config, dom, name, memory, image) 26.408 + deferred = vm_configure(vm, config) 26.409 + except StandardError, ex: 26.410 + if vm: 26.411 + vm.destroy() 26.412 + raise 26.413 + return deferred 26.414 + 26.415 +def append_deferred(dlist, v): 26.416 + if isinstance(v, defer.Deferred): 26.417 + dlist.append(v) 26.418 + 26.419 +def vm_create_devices(vm, config): 26.420 + """Create the devices for a vm. 26.421 + 26.422 + vm virtual machine 26.423 + config configuration 26.424 + 26.425 + returns Deferred 26.426 + raises VmError for invalid devices 26.427 + """ 26.428 + print '>vm_create_devices' 26.429 + dlist = [] 26.430 + devices = sxp.children(config, 'device') 26.431 + index = {} 26.432 + for d in devices: 26.433 + dev = sxp.child0(d) 26.434 + if dev is None: 26.435 + raise VmError('invalid device') 26.436 + dev_name = sxp.name(dev) 26.437 + dev_index = index.get(dev_name, 0) 26.438 + dev_handler = get_device_handler(dev_name) 26.439 + if dev_handler is None: 26.440 + raise VmError('unknown device type: ' + dev_name) 26.441 + v = dev_handler(vm, dev, dev_index) 26.442 + append_deferred(dlist, v) 26.443 + index[dev_name] = dev_index + 1 26.444 + deferred = defer.DeferredList(dlist, fireOnOneErrback=1) 26.445 + print '<vm_create_devices' 26.446 + return deferred 26.447 + 26.448 +def vm_configure(vm, config): 26.449 + """Configure a vm. 26.450 + 26.451 + vm virtual machine 26.452 + config configuration 26.453 + 26.454 + returns Deferred - calls callback with vm 26.455 + """ 26.456 + d = xend.blkif_create(vm.dom) 26.457 + d.addCallback(_vm_configure1, vm, config) 26.458 + return d 26.459 + 26.460 +def _vm_configure1(val, vm, config): 26.461 + d = vm_create_devices(vm, config) 26.462 + print '_vm_configure1> made devices...' 26.463 + def cbok(x): 26.464 + print '_vm_configure1> cbok', x 26.465 + return x 26.466 + d.addCallback(cbok) 26.467 + d.addCallback(_vm_configure2, vm, config) 26.468 + print '_vm_configure1<' 26.469 + return d 26.470 + 26.471 +def _vm_configure2(val, vm, config): 26.472 + print '>callback _vm_configure2...' 26.473 + dlist = [] 26.474 + index = {} 26.475 + for field in sxp.children(config): 26.476 + field_name = sxp.name(field) 26.477 + field_index = index.get(field_name, 0) 26.478 + field_handler = get_config_handler(field_name) 26.479 + # Ignore unknown fields. Warn? 26.480 + if field_handler: 26.481 + v = field_handler(vm, config, field, field_index) 26.482 + append_deferred(dlist, v) 26.483 + index[field_name] = field_index + 1 26.484 + d = defer.DeferredList(dlist, fireOnOneErrback=1) 26.485 + def cbok(results): 26.486 + print '_vm_configure2> cbok', results 26.487 + return vm 26.488 + def cberr(err): 26.489 + print '_vm_configure2> cberr', err 26.490 + vm.destroy() 26.491 + return err 26.492 + d.addCallback(cbok) 26.493 + d.addErrback(cberr) 26.494 + print '<_vm_configure2' 26.495 + return d 26.496 + 26.497 +def config_devices(config, name): 26.498 + """Get a list of the 'device' nodes of a given type from a config. 26.499 + 26.500 + config configuration 26.501 + name device type 26.502 + return list of device configs 26.503 + """ 26.504 + devices = [] 26.505 + for d in sxp.children(config, 'device'): 26.506 + dev = sxp.child0(d) 26.507 + if dev is None: continue 26.508 + if name == sxp.name(dev): 26.509 + devices.append(dev) 26.510 + return devices 26.511 + 26.512 +def vm_image_linux(config, name, memory, image): 26.513 + """Create a VM for a linux image. 26.514 + 26.515 + name vm name 26.516 + memory vm memory 26.517 + image image config 26.518 + 26.519 + returns vm 26.520 + """ 26.521 + kernel = sxp.child_value(image, "kernel") 26.522 + cmdline = "" 26.523 + ip = sxp.child_value(image, "ip", "dhcp") 26.524 + if ip: 26.525 + cmdline += " ip=" + ip 26.526 + root = sxp.child_value(image, "root") 26.527 + if root: 26.528 + cmdline += " root=" + root 26.529 + args = sxp.child_value(image, "args") 26.530 + if args: 26.531 + cmdline += " " + args 26.532 + ramdisk = sxp.child_value(image, "ramdisk", '') 26.533 + vifs = config_devices(config, "vif") 26.534 + vm = xen_domain_create(config, "linux", name, memory, kernel, 26.535 + ramdisk, cmdline, len(vifs)) 26.536 + return vm 26.537 + 26.538 +def vm_image_netbsd(config, name, memory, image): 26.539 + """Create a VM for a bsd image. 26.540 + 26.541 + name vm name 26.542 + memory vm memory 26.543 + image image config 26.544 + 26.545 + returns vm 26.546 + """ 26.547 + #todo: Same as for linux. Is that right? If so can unify them. 26.548 + kernel = sxp.child_value(image, "kernel") 26.549 + cmdline = "" 26.550 + ip = sxp.child_value(image, "ip", "dhcp") 26.551 + if ip: 26.552 + cmdline += "ip=" + ip 26.553 + root = sxp.child_value(image, "root") 26.554 + if root: 26.555 + cmdline += "root=" + root 26.556 + args = sxp.child_value(image, "args") 26.557 + if args: 26.558 + cmdline += " " + args 26.559 + ramdisk = sxp.child_value(image, "ramdisk") 26.560 + vifs = config_devices(config, "vif") 26.561 + vm = xen_domain_create(config, "netbsd", name, memory, kernel, 26.562 + ramdisk, cmdline, len(vifs)) 26.563 + return vm 26.564 + 26.565 + 26.566 +def vm_dev_vif(vm, val, index): 26.567 + """Create a virtual network interface (vif). 26.568 + 26.569 + vm virtual machine 26.570 + val vif config 26.571 + index vif index 26.572 + """ 26.573 + vif = index #todo 26.574 + vmac = sxp.child_value(val, "mac") 26.575 + defer = make_vif(vm.dom, vif, vmac) 26.576 + def fn(id): 26.577 + dev = val + ['vif', vif] 26.578 + vm.add_device('vif', dev) 26.579 + print 'vm_dev_vif> created', dev 26.580 + return id 26.581 + defer.addCallback(fn) 26.582 + return defer 26.583 + 26.584 +def vm_dev_vbd(vm, val, index): 26.585 + """Create a virtual block device (vbd). 26.586 + 26.587 + vm virtual machine 26.588 + val vbd config 26.589 + index vbd index 26.590 + """ 26.591 + uname = sxp.child_value(val, 'uname') 26.592 + if not uname: 26.593 + raise VMError('vbd: Missing uname') 26.594 + dev = sxp.child_value(val, 'dev') 26.595 + if not dev: 26.596 + raise VMError('vbd: Missing dev') 26.597 + mode = sxp.child_value(val, 'mode', 'r') 26.598 + sharing = sxp.child_value(val, 'sharing', 'rr') 26.599 + defer = make_disk(vm.dom, uname, dev, mode, sharing) 26.600 + def fn(vbd): 26.601 + vm.add_device('vbd', val) 26.602 + return vbd 26.603 + defer.addCallback(fn) 26.604 + return defer 26.605 + 26.606 +def vm_dev_pci(vm, val, index): 26.607 + bus = sxp.child_value(val, 'bus') 26.608 + if not bus: 26.609 + raise VMError('pci: Missing bus') 26.610 + dev = sxp.child_value(val, 'dev') 26.611 + if not dev: 26.612 + raise VMError('pci: Missing dev') 26.613 + func = sxp.child_value(val, 'func') 26.614 + if not func: 26.615 + raise VMError('pci: Missing func') 26.616 + rc = xc.physdev_pci_access_modify(dom=vm.dom, bus=bus, dev=dev, func=func, enable=1) 26.617 + if rc < 0: 26.618 + #todo non-fatal 26.619 + raise VMError('pci: Failed to configure device: bus=%s dev=%s func=%s' % 26.620 + (bus, dev, func)) 26.621 + return rc 26.622 + 26.623 + 26.624 +def vm_field_vfr(vm, config, val, index): 26.625 + """Handle a vfr field in a config. 26.626 + 26.627 + vm virtual machine 26.628 + config vm config 26.629 + val vfr field 26.630 + """ 26.631 + # Get the rules and add them. 26.632 + # (vfr (vif (id foo) (ip x.x.x.x)) ... ) 26.633 + list = sxp.children(val, 'vif') 26.634 + for v in list: 26.635 + id = sxp.child_value(v, 'id') 26.636 + if id is None: 26.637 + raise VmError('vfr: missing vif id') 26.638 + id = int(id) 26.639 + dev = vm.get_device_by_index('vif', id) 26.640 + if not dev: 26.641 + raise VmError('vfr: invalid vif id %d' % id) 26.642 + vif = sxp.child_value(dev, 'vif') 26.643 + ip = sxp.child_value(v, 'ip') 26.644 + if not ip: 26.645 + raise VmError('vfr: missing ip address') 26.646 + #Don't do this in new i/o model. 26.647 + #print 'vm_field_vfr> add rule', 'dom=', vm.dom, 'vif=', vif, 'ip=', ip 26.648 + #xenctl.ip.setup_vfr_rules_for_vif(vm.dom, vif, ip) 26.649 + 26.650 +def vnet_bridge(vnet, vmac, dom, idx): 26.651 + """Add the device for the vif to the bridge for its vnet. 26.652 + """ 26.653 + vif = "vif%d.%d" % (dom, idx) 26.654 + try: 26.655 + cmd = "(vif.conn (vif %s) (vnet %s) (vmac %s))" % (vif, vnet, vmac) 26.656 + print "*** vnet_bridge>", cmd 26.657 + out = file("/proc/vnet/policy", "wb") 26.658 + out.write(cmd) 26.659 + err = out.close() 26.660 + print "vnet_bridge>", "err=", err 26.661 + except IOError, ex: 26.662 + print "vnet_bridge>", ex 26.663 + 26.664 +def vm_field_vnet(vm, config, val, index): 26.665 + """Handle a vnet field in a config. 26.666 + 26.667 + vm virtual machine 26.668 + config vm config 26.669 + val vnet field 26.670 + index index 26.671 + """ 26.672 + # Get the vif children. For each vif look up the vif device 26.673 + # with the given id and configure its vnet. 26.674 + # (vnet (vif (id foo) (vnet 2) (mac x:x:x:x:x:x)) ... ) 26.675 + vif_vnets = sxp.children(val, 'vif') 26.676 + for v in vif_vnets: 26.677 + id = sxp.child_value(v, 'id') 26.678 + if id is None: 26.679 + raise VmError('vnet: missing vif id') 26.680 + dev = vm.get_device_by_id('vif', id) 26.681 + if not sxp.elementp(dev, 'vif'): 26.682 + raise VmError('vnet: invalid vif id %s' % id) 26.683 + vnet = sxp.child_value(v, 'vnet', 1) 26.684 + mac = sxp.child_value(dev, 'mac') 26.685 + vif = sxp.child_value(dev, 'vif') 26.686 + vnet_bridge(vnet, mac, vm.dom, 0) 26.687 + vm.add_config([ 'vif.vnet', ['id', id], ['vnet', vnet], ['mac', mac]]) 26.688 + 26.689 +# Register image handlers for linux and bsd. 26.690 +add_image_handler('linux', vm_image_linux) 26.691 +add_image_handler('netbsd', vm_image_netbsd) 26.692 + 26.693 +# Register device handlers for vifs and vbds. 26.694 +add_device_handler('vif', vm_dev_vif) 26.695 +add_device_handler('vbd', vm_dev_vbd) 26.696 +add_device_handler('pci', vm_dev_pci) 26.697 + 26.698 +# Register config handlers for vfr and vnet. 26.699 +add_config_handler('vfr', vm_field_vfr) 26.700 +add_config_handler('vnet', vm_field_vnet)
27.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 27.2 +++ b/tools/xenmgr/lib/XendMigrate.py Fri Jun 11 18:31:12 2004 +0000 27.3 @@ -0,0 +1,103 @@ 27.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com> 27.5 + 27.6 +import sys 27.7 +import socket 27.8 + 27.9 +import sxp 27.10 +import XendDB 27.11 +import EventServer; eserver = EventServer.instance() 27.12 + 27.13 +class XendMigrateInfo: 27.14 + 27.15 + # states: begin, active, failed, succeeded? 27.16 + 27.17 + def __init__(self, id, dom, dst): 27.18 + self.id = id 27.19 + self.state = 'begin' 27.20 + self.src_host = socket.gethostname() 27.21 + self.src_dom = dom 27.22 + self.dst_host = dst 27.23 + self.dst_dom = None 27.24 + 27.25 + def set_state(self, state): 27.26 + self.state = state 27.27 + 27.28 + def get_state(self): 27.29 + return self.state 27.30 + 27.31 + def sxpr(self): 27.32 + sxpr = ['migrate', ['id', self.id], ['state', self.state] ] 27.33 + sxpr_src = ['src', ['host', self.src_host], ['domain', self.src_dom] ] 27.34 + sxpr.append(sxpr_src) 27.35 + sxpr_dst = ['dst', ['host', self.dst] ] 27.36 + if self.dst_dom: 27.37 + sxpr_dst.append(['domain', self.dst_dom]) 27.38 + sxpr.append(sxpr_dst) 27.39 + return sxpr 27.40 + 27.41 + 27.42 +class XendMigrate: 27.43 + # Represents migration in progress. 27.44 + # Use log for indications of begin/end/errors? 27.45 + # Need logging of: domain create/halt, migrate begin/end/fail 27.46 + # Log via event server? 27.47 + 27.48 + dbpath = "migrate" 27.49 + 27.50 + def __init__(self): 27.51 + self.db = XendDB.XendDB(self.dbpath) 27.52 + self.migrate = {} 27.53 + self.migrate_db = self.db.fetchall("") 27.54 + self.id = 0 27.55 + 27.56 + def nextid(self): 27.57 + self.id += 1 27.58 + return "%d" % self.id 27.59 + 27.60 + def sync(self): 27.61 + self.db.saveall("", self.migrate_db) 27.62 + 27.63 + def sync_migrate(self, id): 27.64 + self.db.save(id, self.migrate_db[id]) 27.65 + 27.66 + def close(self): 27.67 + pass 27.68 + 27.69 + def _add_migrate(self, id, info): 27.70 + self.migrate[id] = info 27.71 + self.migrate_db[id] = info.sxpr() 27.72 + self.sync_migrate(id) 27.73 + #eserver.inject('xend.migrate.begin', info.sxpr()) 27.74 + 27.75 + def _delete_migrate(self, id): 27.76 + #eserver.inject('xend.migrate.end', id) 27.77 + del self.migrate[id] 27.78 + del self.migrate_db[id] 27.79 + self.db.delete(id) 27.80 + 27.81 + def migrate_ls(self): 27.82 + return self.migrate.keys() 27.83 + 27.84 + def migrates(self): 27.85 + return self.migrate.values() 27.86 + 27.87 + def migrate_get(self, id): 27.88 + return self.migrate.get(id) 27.89 + 27.90 + def migrate_begin(self, dom, dst): 27.91 + # Check dom for existence, not migrating already. 27.92 + # Create migrate info, tell xend to migrate it? 27.93 + # - or fork migrate command ourselves? 27.94 + # Subscribe to migrate notifications (for updating). 27.95 + id = self.nextid() 27.96 + info = XenMigrateInfo(id, dom, dst) 27.97 + self._add_migrate(id, info) 27.98 + return id 27.99 + 27.100 +def instance(): 27.101 + global inst 27.102 + try: 27.103 + inst 27.104 + except: 27.105 + inst = XendMigrate() 27.106 + return inst
28.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 28.2 +++ b/tools/xenmgr/lib/XendNode.py Fri Jun 11 18:31:12 2004 +0000 28.3 @@ -0,0 +1,55 @@ 28.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com> 28.5 + 28.6 +"""Handler for node operations. 28.7 + Has some persistent state: 28.8 + - logs 28.9 + - notification urls 28.10 + 28.11 +""" 28.12 + 28.13 +import Xc 28.14 + 28.15 +class XendNodeInfo: 28.16 + """Node information record. 28.17 + """ 28.18 + 28.19 + def __init__(self): 28.20 + pass 28.21 + 28.22 +class XendNode: 28.23 + 28.24 + def __init__(self): 28.25 + self.xc = Xc.new() 28.26 + 28.27 + def shutdown(self): 28.28 + return 0 28.29 + 28.30 + def reboot(self): 28.31 + return 0 28.32 + 28.33 + def notify(self, uri): 28.34 + return 0 28.35 + 28.36 + def cpu_bvt_slice_set(self, slice): 28.37 + ret = 0 28.38 + #ret = self.xc.bvtsched_global_set(ctx_allow=slice) 28.39 + return ret 28.40 + 28.41 + def cpu_bvt_slice_get(self, slice): 28.42 + ret = 0 28.43 + #ret = self.xc.bvtsched_global_get() 28.44 + return ret 28.45 + 28.46 + def cpu_rrobin_slice_set(self, slice): 28.47 + ret = 0 28.48 + #ret = self.xc.rrobin_global_set(slice) 28.49 + return ret 28.50 + 28.51 +def instance(): 28.52 + global inst 28.53 + try: 28.54 + inst 28.55 + except: 28.56 + inst = XendNode() 28.57 + return inst 28.58 +
29.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 29.2 +++ b/tools/xenmgr/lib/XendRoot.py Fri Jun 11 18:31:12 2004 +0000 29.3 @@ -0,0 +1,156 @@ 29.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com> 29.5 + 29.6 +"""Xend root class. 29.7 +Creates the event server and handles configuration. 29.8 +""" 29.9 + 29.10 +import os 29.11 +import os.path 29.12 +import sys 29.13 +import EventServer 29.14 + 29.15 +# Initial create of the event server. 29.16 +eserver = EventServer.instance() 29.17 + 29.18 +import sxp 29.19 + 29.20 +def reboots(): 29.21 + """Get a list of system reboots from wtmp. 29.22 + """ 29.23 + out = os.popen('/usr/bin/last reboot', 'r') 29.24 + list = [ x.strip() for x in out if x.startswith('reboot') ] 29.25 + return list 29.26 + 29.27 +def last_reboot(): 29.28 + """Get the last known system reboot. 29.29 + """ 29.30 + l = reboots() 29.31 + return (l and l[-1]) or None 29.32 + 29.33 +class XendRoot: 29.34 + """Root of the management classes.""" 29.35 + 29.36 + lastboot_default = "/etc/xen/xend/lastboot" 29.37 + 29.38 + """Default path to the root of the database.""" 29.39 + dbroot_default = "/etc/xen/xend/xenmgr-db" 29.40 + 29.41 + """Default path to the config file.""" 29.42 + config_default = "/etc/xen/xenmgr-config.sxp" 29.43 + 29.44 + """Environment variable used to override config_default.""" 29.45 + config_var = "XEND_CONFIG" 29.46 + 29.47 + def __init__(self): 29.48 + self.rebooted = 0 29.49 + self.last_reboot = None 29.50 + self.dbroot = None 29.51 + self.config_path = None 29.52 + self.config = None 29.53 + self.configure() 29.54 + self.check_lastboot() 29.55 + eserver.subscribe('xend.*', self.event_handler) 29.56 + #eserver.subscribe('xend.domain.created', self.event_handler) 29.57 + #eserver.subscribe('xend.domain.died', self.event_handler) 29.58 + 29.59 + def start(self): 29.60 + eserver.inject('xend.start', self.rebooted) 29.61 + 29.62 + def event_handler(self, event, val): 29.63 + print >> sys.stderr, "EVENT>", event, val 29.64 + 29.65 + def read_lastboot(self): 29.66 + try: 29.67 + val = file(self.lastboot, 'rb').readlines()[0] 29.68 + except StandardError, ex: 29.69 + print 'warning: Error reading', self.lastboot, ex 29.70 + val = None 29.71 + return val 29.72 + 29.73 + def write_lastboot(self, val): 29.74 + if not val: return 29.75 + try: 29.76 + fdir = os.path.dirname(self.lastboot) 29.77 + if not os.path.isdir(fdir): 29.78 + os.makedirs(fdir) 29.79 + out = file(self.lastboot, 'wb+') 29.80 + out.write(val) 29.81 + out.close() 29.82 + except IOError, ex: 29.83 + print 'warning: Error writing', self.lastboot, ex 29.84 + pass 29.85 + 29.86 + def check_lastboot(self): 29.87 + """Check if there has been a system reboot since we saved lastboot. 29.88 + """ 29.89 + last_val = self.read_lastboot() 29.90 + this_val = last_reboot() 29.91 + if this_val == last_val: 29.92 + self.rebooted = 0 29.93 + else: 29.94 + self.rebooted = 1 29.95 + self.write_lastboot(this_val) 29.96 + self.last_reboot = this_val 29.97 + 29.98 + def get_last_reboot(self): 29.99 + return self.last_reboot 29.100 + 29.101 + def get_rebooted(self): 29.102 + return self.rebooted 29.103 + 29.104 + def configure(self): 29.105 + self.set_config() 29.106 + self.dbroot = self.get_config_value("dbroot", self.dbroot_default) 29.107 + self.lastboot = self.get_config_value("lastboot", self.lastboot_default) 29.108 + 29.109 + def get_dbroot(self): 29.110 + """Get the path to the database root. 29.111 + """ 29.112 + return self.dbroot 29.113 + 29.114 + def set_config(self): 29.115 + """If the config file exists, read it. If not, ignore it. 29.116 + 29.117 + The config file is a sequence of sxp forms. 29.118 + """ 29.119 + self.config_path = os.getenv(self.config_var, self.config_default) 29.120 + if os.path.exists(self.config_path): 29.121 + fin = file(self.config_path, 'rb') 29.122 + try: 29.123 + config = sxp.parse(fin) 29.124 + config.insert(0, 'config') 29.125 + self.config = config 29.126 + finally: 29.127 + fin.close() 29.128 + else: 29.129 + self.config = ['config'] 29.130 + 29.131 + def get_config(self, name=None): 29.132 + """Get the configuration element with the given name, or 29.133 + the whole configuration if no name is given. 29.134 + 29.135 + name element name (optional) 29.136 + returns config or none 29.137 + """ 29.138 + if name is None: 29.139 + val = self.config 29.140 + else: 29.141 + val = sxp.child(self.config, name) 29.142 + return val 29.143 + 29.144 + def get_config_value(self, name, val=None): 29.145 + """Get the value of an atomic configuration element. 29.146 + 29.147 + name element name 29.148 + val default value (optional, defaults to None) 29.149 + returns value 29.150 + """ 29.151 + return sxp.child_value(self.config, name, val=val) 29.152 + 29.153 +def instance(): 29.154 + global inst 29.155 + try: 29.156 + inst 29.157 + except: 29.158 + inst = XendRoot() 29.159 + return inst
30.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 30.2 +++ b/tools/xenmgr/lib/XendVdisk.py Fri Jun 11 18:31:12 2004 +0000 30.3 @@ -0,0 +1,111 @@ 30.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com> 30.5 + 30.6 +"""Handler for vdisk operations. 30.7 + 30.8 +""" 30.9 + 30.10 +import os 30.11 +import os.path 30.12 + 30.13 +from xenctl import vdisk 30.14 + 30.15 +import sxp 30.16 + 30.17 +class XendVdiskInfo: 30.18 + 30.19 + def __init__(self, info): 30.20 + self.info = info 30.21 + self.id = info['vdisk_id'] 30.22 + 30.23 + def __str__(self): 30.24 + return ("vdisk id=%(vdisk_id)s size=%(size)d expires=%(expires)d expiry_time=%(expiry_time)d" 30.25 + % self.info) 30.26 + 30.27 + def sxpr(self): 30.28 + val = ['vdisk'] 30.29 + for (k,v) in self.info.items(): 30.30 + val.append([k, str(v)]) 30.31 + return val 30.32 + 30.33 +class XendVdisk: 30.34 + """Index of all vdisks. Singleton. 30.35 + """ 30.36 + 30.37 + dbpath = "vdisk" 30.38 + 30.39 + def __init__(self): 30.40 + # Table of vdisk info indexed by vdisk id. 30.41 + self.vdisk = {} 30.42 + if not os.path.isfile(vdisk.VD_DB_FILE): 30.43 + vdisk.vd_init_db(vdisk.VD_DB_FILE) 30.44 + self.vdisk_refresh() 30.45 + 30.46 + def vdisk_refresh(self): 30.47 + # vdisk = {vdisk_id, size, expires, expiry_time} 30.48 + try: 30.49 + vdisks = vdisk.vd_list() 30.50 + except: 30.51 + vdisks = [] 30.52 + for vdisk in vdisks: 30.53 + vdiskinfo = XendVdiskInfo(vdisk) 30.54 + self.vdisk[vdiskinfo.id] = vdiskinfo 30.55 + 30.56 + def vdisk_ls(self): 30.57 + """List all vdisk ids. 30.58 + """ 30.59 + return self.vdisk.keys() 30.60 + 30.61 + def vdisks(self): 30.62 + return self.vdisk.values() 30.63 + 30.64 + def vdisk_get(self, id): 30.65 + """Get a vdisk. 30.66 + 30.67 + id vdisk id 30.68 + """ 30.69 + return self.vdisk.get(id) 30.70 + 30.71 + def vdisk_create(self, info): 30.72 + """Create a vdisk. 30.73 + 30.74 + info config 30.75 + """ 30.76 + # Need to configure for real. 30.77 + # vdisk.vd_create(size, expiry) 30.78 + 30.79 + def vdisk_configure(self, info): 30.80 + """Configure a vdisk. 30.81 + id vdisk id 30.82 + info config 30.83 + """ 30.84 + # Need to configure for real. 30.85 + # Make bigger: vdisk.vd_enlarge(id, extra_size) 30.86 + # Update expiry time: vdisk.vd_refresh(id, expiry) 30.87 + # Try to recover an expired vdisk : vdisk.vd_undelete(id, expiry) 30.88 + 30.89 + 30.90 + def vdisk_delete(self, id): 30.91 + """Delete a vdisk. 30.92 + 30.93 + id vdisk id 30.94 + """ 30.95 + # Need to delete vdisk for real. What if fails? 30.96 + del self.vdisk[id] 30.97 + vdisk.vd_delete(id) 30.98 + 30.99 + # def vdisk_copy: copy contents to file, vdisk still exists 30.100 + # def vdisk_export: copy contents to file then delete the vdisk 30.101 + # def vdisk_import: create a vdisk from a file 30.102 + # def vdisk_space: space left for new vdisks 30.103 + 30.104 + # def vdisk_recover: recover an expired vdisk 30.105 + 30.106 + # def vdisk_init_partition: setup a physical partition for vdisks 30.107 + 30.108 +def instance(): 30.109 + global inst 30.110 + try: 30.111 + inst 30.112 + except: 30.113 + inst = XendVdisk() 30.114 + return inst
31.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 31.2 +++ b/tools/xenmgr/lib/XendVnet.py Fri Jun 11 18:31:12 2004 +0000 31.3 @@ -0,0 +1,69 @@ 31.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com> 31.5 + 31.6 +"""Handler for vnet operations. 31.7 +""" 31.8 + 31.9 +import sxp 31.10 +import XendDB 31.11 + 31.12 +class XendVnet: 31.13 + """Index of all vnets. Singleton. 31.14 + """ 31.15 + 31.16 + dbpath = "vnet" 31.17 + 31.18 + def __init__(self): 31.19 + # Table of vnet info indexed by vnet id. 31.20 + self.vnet = {} 31.21 + self.db = XendDB.XendDB(self.dbpath) 31.22 + self.vnet = self.db.fetchall("") 31.23 + 31.24 + def vnet_ls(self): 31.25 + """List all vnets. 31.26 + """ 31.27 + return self.vnet.keys() 31.28 + 31.29 + def vnets(self): 31.30 + return self.vnet.values() 31.31 + 31.32 + def vnet_get(self, id): 31.33 + """Get a vnet. 31.34 + 31.35 + id vnet id 31.36 + """ 31.37 + return self.vnet.get(id) 31.38 + 31.39 + def vnet_create(self, info): 31.40 + """Create a vnet. 31.41 + 31.42 + info config 31.43 + """ 31.44 + self.vnet_configure(info) 31.45 + 31.46 + def vnet_configure(self, info): 31.47 + """Configure a vnet. 31.48 + id vnet id 31.49 + info config 31.50 + """ 31.51 + # Need to configure for real. 31.52 + # Only sync if succeeded - otherwise need to back out. 31.53 + self.vnet[info.id] = info 31.54 + self.db.save(info.id, info) 31.55 + 31.56 + def vnet_delete(self, id): 31.57 + """Delete a vnet. 31.58 + 31.59 + id vnet id 31.60 + """ 31.61 + # Need to delete for real. What if fails? 31.62 + if id in self.vnet: 31.63 + del self.vnet[id] 31.64 + self.db.delete(id) 31.65 + 31.66 +def instance(): 31.67 + global inst 31.68 + try: 31.69 + inst 31.70 + except: 31.71 + inst = XendVnet() 31.72 + return inst
32.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 32.2 +++ b/tools/xenmgr/lib/__init__.py Fri Jun 11 18:31:12 2004 +0000 32.3 @@ -0,0 +1,1 @@ 32.4 +
33.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 33.2 +++ b/tools/xenmgr/lib/encode.py Fri Jun 11 18:31:12 2004 +0000 33.3 @@ -0,0 +1,165 @@ 33.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com> 33.5 +"""Encoding for arguments to HTTP calls. 33.6 + Uses the url-encoding with MIME type 'application/x-www-form-urlencoded' 33.7 + if the data does not include files. Otherwise it uses the encoding with 33.8 + MIME type 'multipart/form-data'. See the HTML4 spec for details. 33.9 + 33.10 + """ 33.11 +import sys 33.12 +import types 33.13 +from StringIO import StringIO 33.14 + 33.15 +import urllib 33.16 +import httplib 33.17 +import random 33.18 +import md5 33.19 + 33.20 +# Extract from HTML4 spec. 33.21 +## The following example illustrates "multipart/form-data" 33.22 +## encoding. Suppose we have the following form: 33.23 + 33.24 +## <FORM action="http://server.com/cgi/handle" 33.25 +## enctype="multipart/form-data" 33.26 +## method="post"> 33.27 +## <P> 33.28 +## What is your name? <INPUT type="text" name="submit-name"><BR> 33.29 +## What files are you sending? <INPUT type="file" name="files"><BR> 33.30 +## <INPUT type="submit" value="Send"> <INPUT type="reset"> 33.31 +## </FORM> 33.32 + 33.33 +## If the user enters "Larry" in the text input, and selects the text 33.34 +## file "file1.txt", the user agent might send back the following data: 33.35 + 33.36 +## Content-Type: multipart/form-data; boundary=AaB03x 33.37 + 33.38 +## --AaB03x 33.39 +## Content-Disposition: form-data; name="submit-name" 33.40 + 33.41 +## Larry 33.42 +## --AaB03x 33.43 +## Content-Disposition: form-data; name="files"; filename="file1.txt" 33.44 +## Content-Type: text/plain 33.45 + 33.46 +## ... contents of file1.txt ... 33.47 +## --AaB03x-- 33.48 + 33.49 +## If the user selected a second (image) file "file2.gif", the user agent 33.50 +## might construct the parts as follows: 33.51 + 33.52 +## Content-Type: multipart/form-data; boundary=AaB03x 33.53 + 33.54 +## --AaB03x 33.55 +## Content-Disposition: form-data; name="submit-name" 33.56 + 33.57 +## Larry 33.58 +## --AaB03x 33.59 +## Content-Disposition: form-data; name="files" 33.60 +## Content-Type: multipart/mixed; boundary=BbC04y 33.61 + 33.62 +## --BbC04y 33.63 +## Content-Disposition: file; filename="file1.txt" 33.64 +## Content-Type: text/plain 33.65 + 33.66 +## ... contents of file1.txt ... 33.67 +## --BbC04y 33.68 +## Content-Disposition: file; filename="file2.gif" 33.69 +## Content-Type: image/gif 33.70 +## Content-Transfer-Encoding: binary 33.71 + 33.72 +## ...contents of file2.gif... 33.73 +## --BbC04y-- 33.74 +## --AaB03x-- 33.75 + 33.76 +__all__ = ['encode_data', 'encode_multipart', 'encode_form', 'mime_boundary' ] 33.77 + 33.78 +def data_values(d): 33.79 + if isinstance(d, types.DictType): 33.80 + return d.items() 33.81 + else: 33.82 + return d 33.83 + 33.84 +def encode_data(d): 33.85 + """Encode some data for HTTP transport. 33.86 + The encoding used is stored in 'Content-Type' in the headers. 33.87 + 33.88 + d data - sequence of tuples or dictionary 33.89 + returns a 2-tuple of the headers and the encoded data 33.90 + """ 33.91 + val = ({}, None) 33.92 + if d is None: return val 33.93 + multipart = 0 33.94 + for (k, v) in data_values(d): 33.95 + if encode_isfile(v): 33.96 + multipart = 1 33.97 + break 33.98 + if multipart: 33.99 + val = encode_multipart(d) 33.100 + else: 33.101 + val = encode_form(d) 33.102 + return val 33.103 + 33.104 +def encode_isfile(v): 33.105 + if isinstance(v, types.FileType): 33.106 + return 1 33.107 + if hasattr(v, 'readlines'): 33.108 + return 1 33.109 + return 0 33.110 + 33.111 +def encode_multipart(d): 33.112 + boundary = mime_boundary() 33.113 + hdr = { 'Content-Type': 'multipart/form-data; boundary=' + boundary } 33.114 + out = StringIO() 33.115 + for (k,v) in data_values(d): 33.116 + out.write('--') 33.117 + out.write(boundary) 33.118 + out.write('\r\n') 33.119 + if encode_isfile(v): 33.120 + out.write('Content-Disposition: form-data; name="') 33.121 + out.write(k) 33.122 + if hasattr(v, 'name'): 33.123 + out.write('"; filename="') 33.124 + out.write(v.name) 33.125 + out.write('"\r\n') 33.126 + out.write('Content-Type: application/octet-stream\r\n') 33.127 + out.write('\r\n') 33.128 + for l in v.readlines(): 33.129 + out.write(l) 33.130 + else: 33.131 + out.write('Content-Disposition: form-data; name="') 33.132 + out.write(k) 33.133 + out.write('"\r\n') 33.134 + out.write('\r\n') 33.135 + out.write(str(v)) 33.136 + out.write('\r\n') 33.137 + out.write('--') 33.138 + out.write(boundary) 33.139 + out.write('--') 33.140 + out.write('\r\n') 33.141 + return (hdr, out.getvalue()) 33.142 + 33.143 +def mime_boundary(): 33.144 + random.seed() 33.145 + m = md5.new() 33.146 + for i in range(0, 10): 33.147 + c = chr(random.randint(1, 255)) 33.148 + m.update(c) 33.149 + b = m.hexdigest() 33.150 + return b[0:16] 33.151 + 33.152 +def encode_form(d): 33.153 + hdr = { 'Content-Type': 'application/x-www-form-urlencoded' } 33.154 + val = urllib.urlencode(d) 33.155 + return (hdr, val) 33.156 + 33.157 +def main(): 33.158 + #d = {'a': 1, 'b': 'x y', 'c': file('conf.sxp') } 33.159 + #d = {'a': 1, 'b': 'x y' } 33.160 + d = [ ('a', 1), ('b', 'x y'), ('c', file('conf.sxp')) ] 33.161 + #d = [ ('a', 1), ('b', 'x y')] 33.162 + v = encode_data(d) 33.163 + print v[0] 33.164 + sys.stdout.write(v[1]) 33.165 + print 33.166 + 33.167 +if __name__ == "__main__": 33.168 + main()
34.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 34.2 +++ b/tools/xenmgr/lib/server/SrvBase.py Fri Jun 11 18:31:12 2004 +0000 34.3 @@ -0,0 +1,137 @@ 34.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com> 34.5 + 34.6 +import cgi 34.7 + 34.8 +import os 34.9 +import sys 34.10 +import types 34.11 +import StringIO 34.12 + 34.13 +from twisted.internet import defer 34.14 +from twisted.internet import reactor 34.15 +from twisted.web import error 34.16 +from twisted.web import resource 34.17 +from twisted.web import server 34.18 + 34.19 +from xenmgr import sxp 34.20 +from xenmgr import PrettyPrint 34.21 + 34.22 +def uri_pathlist(p): 34.23 + """Split a path into a list. 34.24 + p path 34.25 + return list of path elements 34.26 + """ 34.27 + l = [] 34.28 + for x in p.split('/'): 34.29 + if x == '': continue 34.30 + l.append(x) 34.31 + return l 34.32 + 34.33 +class SrvBase(resource.Resource): 34.34 + """Base class for services. 34.35 + """ 34.36 + 34.37 + def parse_form(self, req, method): 34.38 + """Parse the data for a request, GET using the URL, POST using encoded data. 34.39 + Posts should use enctype='multipart/form-data' in the <form> tag, 34.40 + rather than 'application/x-www-form-urlencoded'. Only 'multipart/form-data' 34.41 + handles file upload. 34.42 + 34.43 + req request 34.44 + returns a cgi.FieldStorage instance 34.45 + """ 34.46 + env = {} 34.47 + env['REQUEST_METHOD'] = method 34.48 + if self.query: 34.49 + env['QUERY_STRING'] = self.query 34.50 + val = cgi.FieldStorage(fp=req.rfile, headers=req.headers, environ=env) 34.51 + return val 34.52 + 34.53 + def use_sxp(self, req): 34.54 + """Determine whether to send an SXP response to a request. 34.55 + Uses SXP if there is no User-Agent, no Accept, or application/sxp is in Accept. 34.56 + 34.57 + req request 34.58 + returns 1 for SXP, 0 otherwise 34.59 + """ 34.60 + ok = 0 34.61 + user_agent = req.getHeader('User-Agent') 34.62 + accept = req.getHeader('Accept') 34.63 + if (not user_agent) or (not accept) or (accept.find(sxp.mime_type) >= 0): 34.64 + ok = 1 34.65 + return ok 34.66 + 34.67 + def get_op_method(self, op): 34.68 + """Get the method for an operation. 34.69 + For operation 'foo' looks for 'op_foo'. 34.70 + 34.71 + op operation name 34.72 + returns method or None 34.73 + """ 34.74 + op_method_name = 'op_' + op 34.75 + return getattr(self, op_method_name, None) 34.76 + 34.77 + def perform(self, req): 34.78 + """General operation handler for posted operations. 34.79 + For operation 'foo' looks for a method op_foo and calls 34.80 + it with op_foo(op, req). Replies with code 500 if op_foo 34.81 + is not found. 34.82 + 34.83 + The method must return a list when req.use_sxp is true 34.84 + and an HTML string otherwise (or list). 34.85 + Methods may also return a Deferred (for incomplete processing). 34.86 + 34.87 + req request 34.88 + """ 34.89 + op = req.args.get('op') 34.90 + if op is None or len(op) != 1: 34.91 + req.setResponseCode(404, "Invalid") 34.92 + return '' 34.93 + op = op[0] 34.94 + op_method = self.get_op_method(op) 34.95 + if op_method is None: 34.96 + req.setResponseCode(501, "Not implemented") 34.97 + req.setHeader("Content-Type", "text/plain") 34.98 + req.write("Not implemented: " + op) 34.99 + return '' 34.100 + else: 34.101 + val = op_method(op, req) 34.102 + if isinstance(val, defer.Deferred): 34.103 + val.addCallback(self._cb_perform, req, 1) 34.104 + return server.NOT_DONE_YET 34.105 + else: 34.106 + self._cb_perform(val, req, 0) 34.107 + return '' 34.108 + 34.109 + def _cb_perform(self, val, req, dfr): 34.110 + """Callback to complete the request. 34.111 + May be called from a Deferred. 34.112 + """ 34.113 + if isinstance(val, error.ErrorPage): 34.114 + req.write(val.render(req)) 34.115 + elif self.use_sxp(req): 34.116 + req.setHeader("Content-Type", sxp.mime_type) 34.117 + sxp.show(val, req) 34.118 + else: 34.119 + req.write('<html><head></head><body>') 34.120 + self.print_path(req) 34.121 + if isinstance(val, types.ListType): 34.122 + req.write('<code><pre>') 34.123 + PrettyPrint.prettyprint(val, out=req) 34.124 + req.write('</pre></code>') 34.125 + else: 34.126 + req.write(str(val)) 34.127 + req.write('</body></html>') 34.128 + if dfr: 34.129 + req.finish() 34.130 + 34.131 + def print_path(self, req): 34.132 + """Print the path with hyperlinks. 34.133 + """ 34.134 + pathlist = [x for x in req.prepath if x != '' ] 34.135 + s = "/" 34.136 + req.write('<h1><a href="/">/</a>') 34.137 + for x in pathlist: 34.138 + s += x + "/" 34.139 + req.write(' <a href="%s">%s</a>/' % (s, x)) 34.140 + req.write("</h1>")
35.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 35.2 +++ b/tools/xenmgr/lib/server/SrvConsole.py Fri Jun 11 18:31:12 2004 +0000 35.3 @@ -0,0 +1,42 @@ 35.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com> 35.5 + 35.6 +from xenmgr import sxp 35.7 +from xenmgr import XendConsole 35.8 +from SrvDir import SrvDir 35.9 + 35.10 +class SrvConsole(SrvDir): 35.11 + """An individual console. 35.12 + """ 35.13 + 35.14 + def __init__(self, info): 35.15 + SrvDir.__init__(self) 35.16 + self.info = info 35.17 + self.xc = XendConsole.instance() 35.18 + 35.19 + def op_disconnect(self, op, req): 35.20 + val = self.xc.console_disconnect(self.info.id) 35.21 + return val 35.22 + 35.23 + def render_POST(self, req): 35.24 + return self.perform(req) 35.25 + 35.26 + def render_GET(self, req): 35.27 + if self.use_sxp(req): 35.28 + req.setHeader("Content-Type", sxp.mime_type) 35.29 + sxp.show(self.info.sxpr(), out=req) 35.30 + else: 35.31 + req.write('<html><head></head><body>') 35.32 + self.print_path(req) 35.33 + #self.ls() 35.34 + req.write('<p>%s</p>' % self.info) 35.35 + req.write('<p><a href="%s">Connect to domain %d</a></p>' 35.36 + % (self.info.uri(), self.info.dom2)) 35.37 + self.form(req) 35.38 + req.write('</body></html>') 35.39 + return '' 35.40 + 35.41 + def form(self, req): 35.42 + req.write('<form method="post" action="%s">' % req.prePathURL()) 35.43 + if self.info.connection(): 35.44 + req.write('<input type="submit" name="op" value="disconnect">') 35.45 + req.write('</form>')
36.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 36.2 +++ b/tools/xenmgr/lib/server/SrvConsoleDir.py Fri Jun 11 18:31:12 2004 +0000 36.3 @@ -0,0 +1,58 @@ 36.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com> 36.5 + 36.6 +from SrvDir import SrvDir 36.7 +from SrvConsole import SrvConsole 36.8 +from xenmgr import XendConsole 36.9 +from xenmgr import sxp 36.10 + 36.11 +class SrvConsoleDir(SrvDir): 36.12 + """Console directory. 36.13 + """ 36.14 + 36.15 + def __init__(self): 36.16 + SrvDir.__init__(self) 36.17 + self.xconsole = XendConsole.instance() 36.18 + 36.19 + def console(self, x): 36.20 + val = None 36.21 + try: 36.22 + info = self.xconsole.console_get(x) 36.23 + val = SrvConsole(info) 36.24 + except KeyError: 36.25 + pass 36.26 + return val 36.27 + 36.28 + def get(self, x): 36.29 + v = SrvDir.get(self, x) 36.30 + if v is not None: 36.31 + return v 36.32 + v = self.console(x) 36.33 + return v 36.34 + 36.35 + def render_GET(self, req): 36.36 + if self.use_sxp(req): 36.37 + req.setHeader("Content-Type", sxp.mime_type) 36.38 + self.ls_console(req, 1) 36.39 + else: 36.40 + req.write("<html><head></head><body>") 36.41 + self.print_path(req) 36.42 + self.ls(req) 36.43 + self.ls_console(req) 36.44 + #self.form(req.wfile) 36.45 + req.write("</body></html>") 36.46 + return '' 36.47 + 36.48 + def ls_console(self, req, use_sxp=0): 36.49 + url = req.prePathURL() 36.50 + if not url.endswith('/'): 36.51 + url += '/' 36.52 + if use_sxp: 36.53 + consoles = self.xconsole.console_ls() 36.54 + sxp.show(consoles, out=req) 36.55 + else: 36.56 + consoles = self.xconsole.consoles() 36.57 + consoles.sort(lambda x, y: cmp(x.id, y.id)) 36.58 + req.write('<ul>') 36.59 + for c in consoles: 36.60 + req.write('<li><a href="%s%s"> %s</a></li>' % (url, c.id, c)) 36.61 + req.write('</ul>')
37.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 37.2 +++ b/tools/xenmgr/lib/server/SrvConsoleServer.py Fri Jun 11 18:31:12 2004 +0000 37.3 @@ -0,0 +1,631 @@ 37.4 +########################################################### 37.5 +## Xen controller daemon 37.6 +## Copyright (c) 2004, K A Fraser (University of Cambridge) 37.7 +## Copyright (C) 2004, Mike Wray <mike.wray@hp.com> 37.8 +########################################################### 37.9 + 37.10 +import os 37.11 +import os.path 37.12 +import signal 37.13 +import sys 37.14 +import socket 37.15 +import pwd 37.16 +import re 37.17 +import StringIO 37.18 + 37.19 +from twisted.internet import pollreactor 37.20 +pollreactor.install() 37.21 + 37.22 +from twisted.internet import reactor 37.23 +from twisted.internet import protocol 37.24 +from twisted.internet import abstract 37.25 +from twisted.internet import defer 37.26 + 37.27 +import xend.utils 37.28 + 37.29 +from xenmgr import sxp 37.30 +from xenmgr import PrettyPrint 37.31 +from xenmgr import EventServer 37.32 +eserver = EventServer.instance() 37.33 + 37.34 +from xenmgr.server import SrvServer 37.35 + 37.36 +import channel 37.37 +import blkif 37.38 +import netif 37.39 +import console 37.40 +from params import * 37.41 + 37.42 +DEBUG = 1 37.43 + 37.44 +class MgmtProtocol(protocol.DatagramProtocol): 37.45 + """Handler for the management socket (unix-domain). 37.46 + """ 37.47 + 37.48 + def __init__(self, daemon): 37.49 + #protocol.DatagramProtocol.__init__(self) 37.50 + self.daemon = daemon 37.51 + 37.52 + def write(self, data, addr): 37.53 + return self.transport.write(data, addr) 37.54 + 37.55 + def datagramReceived(self, data, addr): 37.56 + if DEBUG: print 'datagramReceived> addr=', addr, 'data=', data 37.57 + io = StringIO.StringIO(data) 37.58 + try: 37.59 + vals = sxp.parse(io) 37.60 + res = self.dispatch(vals[0]) 37.61 + self.send_result(addr, res) 37.62 + except SystemExit: 37.63 + raise 37.64 + except: 37.65 + if DEBUG: 37.66 + raise 37.67 + else: 37.68 + self.send_error(addr) 37.69 + 37.70 + def send_reply(self, addr, sxpr): 37.71 + io = StringIO.StringIO() 37.72 + sxp.show(sxpr, out=io) 37.73 + io.seek(0) 37.74 + self.write(io.getvalue(), addr) 37.75 + 37.76 + def send_result(self, addr, res): 37.77 + 37.78 + def fn(res, self=self, addr=addr): 37.79 + self.send_reply(addr, ['ok', res]) 37.80 + 37.81 + if isinstance(res, defer.Deferred): 37.82 + res.addCallback(fn) 37.83 + else: 37.84 + fn(res) 37.85 + 37.86 + def send_error(self, addr): 37.87 + (extype, exval) = sys.exc_info()[:2] 37.88 + self.send_reply(addr, ['err', 37.89 + ['type', str(extype) ], 37.90 + ['value', str(exval) ] ] ) 37.91 + 37.92 + def opname(self, name): 37.93 + """Get the name of the method for an operation. 37.94 + """ 37.95 + return 'op_' + name.replace('.', '_') 37.96 + 37.97 + def operror(self, name, v): 37.98 + """Default operation handler - signals an error. 37.99 + """ 37.100 + raise NotImplementedError('Invalid operation: ' +name) 37.101 + 37.102 + def dispatch(self, req): 37.103 + """Dispatch a request to its handler. 37.104 + """ 37.105 + op_name = sxp.name(req) 37.106 + op_method_name = self.opname(op_name) 37.107 + op_method = getattr(self, op_method_name, self.operror) 37.108 + return op_method(op_name, req) 37.109 + 37.110 + def op_console_create(self, name, req): 37.111 + """Create a new control interface - console for a domain. 37.112 + """ 37.113 + print name, req 37.114 + dom = sxp.child_value(req, 'domain') 37.115 + if not dom: raise ValueError('Missing domain') 37.116 + dom = int(dom) 37.117 + console_port = sxp.child_value(req, 'console_port') 37.118 + if console_port: 37.119 + console_port = int(console_port) 37.120 + resp = self.daemon.console_create(dom, console_port) 37.121 + print name, resp 37.122 + return resp 37.123 + 37.124 + def op_consoles(self, name, req): 37.125 + """Get a list of the consoles. 37.126 + """ 37.127 + return self.daemon.consoles() 37.128 + 37.129 + def op_console_disconnect(self, name, req): 37.130 + id = sxp.child_value(req, 'id') 37.131 + if not id: 37.132 + raise ValueError('Missing console id') 37.133 + id = int(id) 37.134 + console = self.daemon.get_console(id) 37.135 + if not console: 37.136 + raise ValueError('Invalid console id') 37.137 + if console.conn: 37.138 + console.conn.loseConnection() 37.139 + return ['ok'] 37.140 + 37.141 + def op_blkifs(self, name, req): 37.142 + pass 37.143 + 37.144 + def op_blkif_devs(self, name, req): 37.145 + pass 37.146 + 37.147 + def op_blkif_create(self, name, req): 37.148 + pass 37.149 + 37.150 + def op_blkif_dev_create(self, name, req): 37.151 + pass 37.152 + 37.153 + def op_netifs(self, name, req): 37.154 + pass 37.155 + 37.156 + def op_netif_devs(self, name, req): 37.157 + pass 37.158 + 37.159 + def op_netif_create(self, name, req): 37.160 + pass 37.161 + 37.162 + def op_netif_dev_create(self, name, req): 37.163 + pass 37.164 + 37.165 +class NotifierProtocol(protocol.Protocol): 37.166 + """Asynchronous handler for i/o on the notifier (event channel). 37.167 + """ 37.168 + 37.169 + def __init__(self, channelFactory): 37.170 + self.channelFactory = channelFactory 37.171 + 37.172 + def notificationReceived(self, idx, type): 37.173 + #print 'NotifierProtocol>notificationReceived>', idx, type 37.174 + channel = self.channelFactory.getChannel(idx) 37.175 + if not channel: 37.176 + return 37.177 + #print 'NotifierProtocol>notificationReceived> channel', channel 37.178 + channel.notificationReceived(type) 37.179 + 37.180 + def connectionLost(self, reason=None): 37.181 + pass 37.182 + 37.183 + def doStart(self): 37.184 + pass 37.185 + 37.186 + def doStop(self): 37.187 + pass 37.188 + 37.189 + def startProtocol(self): 37.190 + pass 37.191 + 37.192 + def stopProtocol(self): 37.193 + pass 37.194 + 37.195 +class NotifierPort(abstract.FileDescriptor): 37.196 + """Transport class for the event channel. 37.197 + """ 37.198 + 37.199 + def __init__(self, daemon, notifier, proto, reactor=None): 37.200 + assert isinstance(proto, NotifierProtocol) 37.201 + abstract.FileDescriptor.__init__(self, reactor) 37.202 + self.daemon = daemon 37.203 + self.notifier = notifier 37.204 + self.protocol = proto 37.205 + 37.206 + def startListening(self): 37.207 + self._bindNotifier() 37.208 + self._connectToProtocol() 37.209 + 37.210 + def stopListening(self): 37.211 + if self.connected: 37.212 + result = self.d = defer.Deferred() 37.213 + else: 37.214 + result = None 37.215 + self.loseConnection() 37.216 + return result 37.217 + 37.218 + def fileno(self): 37.219 + return self.notifier.fileno() 37.220 + 37.221 + def _bindNotifier(self): 37.222 + self.connected = 1 37.223 + 37.224 + def _connectToProtocol(self): 37.225 + self.protocol.makeConnection(self) 37.226 + self.startReading() 37.227 + 37.228 + def loseConnection(self): 37.229 + if self.connected: 37.230 + self.stopReading() 37.231 + self.disconnecting = 1 37.232 + reactor.callLater(0, self.connectionLost) 37.233 + 37.234 + def connectionLost(self, reason=None): 37.235 + abstract.FileDescriptor.connectionLost(self, reason) 37.236 + if hasattr(self, 'protocol'): 37.237 + self.protocol.doStop() 37.238 + self.connected = 0 37.239 + #self.notifier.close() # Not implemented. 37.240 + os.close(self.fileno()) 37.241 + del self.notifier 37.242 + if hasattr(self, 'd'): 37.243 + self.d.callback(None) 37.244 + del self.d 37.245 + 37.246 + def doRead(self): 37.247 + #print 'NotifierPort>doRead>', self 37.248 + count = 0 37.249 + while 1: 37.250 + #print 'NotifierPort>doRead>', count 37.251 + notification = self.notifier.read() 37.252 + if not notification: 37.253 + break 37.254 + (idx, type) = notification 37.255 + self.protocol.notificationReceived(idx, type) 37.256 + self.notifier.unmask(idx) 37.257 + count += 1 37.258 + #print 'NotifierPort>doRead<' 37.259 + 37.260 +class EventProtocol(protocol.Protocol): 37.261 + """Asynchronous handler for a connected event socket. 37.262 + """ 37.263 + 37.264 + def __init__(self, daemon): 37.265 + #protocol.Protocol.__init__(self) 37.266 + self.daemon = daemon 37.267 + # Event queue. 37.268 + self.queue = [] 37.269 + # Subscribed events. 37.270 + self.events = [] 37.271 + self.parser = sxp.Parser() 37.272 + self.pretty = 0 37.273 + 37.274 + # For debugging subscribe to everything and make output pretty. 37.275 + self.subscribe(['*']) 37.276 + self.pretty = 1 37.277 + 37.278 + def dataReceived(self, data): 37.279 + try: 37.280 + self.parser.input(data) 37.281 + if self.parser.ready(): 37.282 + val = self.parser.get_val() 37.283 + res = self.dispatch(val) 37.284 + self.send_result(res) 37.285 + if self.parser.at_eof(): 37.286 + self.loseConnection() 37.287 + except SystemExit: 37.288 + raise 37.289 + except: 37.290 + if DEBUG: 37.291 + raise 37.292 + else: 37.293 + self.send_error() 37.294 + 37.295 + def connectionLost(self, reason=None): 37.296 + self.unsubscribe() 37.297 + 37.298 + def send_reply(self, sxpr): 37.299 + io = StringIO.StringIO() 37.300 + if self.pretty: 37.301 + PrettyPrint.prettyprint(sxpr, out=io) 37.302 + else: 37.303 + sxp.show(sxpr, out=io) 37.304 + print >> io 37.305 + io.seek(0) 37.306 + return self.transport.write(io.getvalue()) 37.307 + 37.308 + def send_result(self, res): 37.309 + return self.send_reply(['ok', res]) 37.310 + 37.311 + def send_error(self): 37.312 + (extype, exval) = sys.exc_info()[:2] 37.313 + return self.send_reply(['err', 37.314 + ['type', str(extype)], 37.315 + ['value', str(exval)]]) 37.316 + 37.317 + def send_event(self, val): 37.318 + return self.send_reply(['event', val[0], val[1]]) 37.319 + 37.320 + def unsubscribe(self): 37.321 + for event in self.events: 37.322 + eserver.unsubscribe(event, self.queue_event) 37.323 + 37.324 + def subscribe(self, events): 37.325 + self.unsubscribe() 37.326 + for event in events: 37.327 + eserver.subscribe(event, self.queue_event) 37.328 + self.events = events 37.329 + 37.330 + def queue_event(self, name, v): 37.331 + # Despite the name we dont' queue the event here. 37.332 + # We send it because the transport will queue it. 37.333 + self.send_event([name, v]) 37.334 + 37.335 + def opname(self, name): 37.336 + return 'op_' + name.replace('.', '_') 37.337 + 37.338 + def operror(self, name, req): 37.339 + raise NotImplementedError('Invalid operation: ' +name) 37.340 + 37.341 + def dispatch(self, req): 37.342 + op_name = sxp.name(req) 37.343 + op_method_name = self.opname(op_name) 37.344 + op_method = getattr(self, op_method_name, self.operror) 37.345 + return op_method(op_name, req) 37.346 + 37.347 + def op_help(self, name, req): 37.348 + def nameop(x): 37.349 + if x.startswith('op_'): 37.350 + return x[3:].replace('_', '.') 37.351 + else: 37.352 + return x 37.353 + 37.354 + l = [ nameop(k) for k in dir(self) if k.startswith('op_') ] 37.355 + return l 37.356 + 37.357 + def op_quit(self, name, req): 37.358 + self.loseConnection() 37.359 + 37.360 + def op_exit(self, name, req): 37.361 + sys.exit(0) 37.362 + 37.363 + def op_pretty(self, name, req): 37.364 + self.pretty = 1 37.365 + return ['ok'] 37.366 + 37.367 + def op_console_disconnect(self, name, req): 37.368 + id = sxp.child_value(req, 'id') 37.369 + if not id: 37.370 + raise ValueError('Missing console id') 37.371 + self.daemon.console_disconnect(id) 37.372 + return ['ok'] 37.373 + 37.374 + def op_info(self, name, req): 37.375 + val = self.daemon.consoles() 37.376 + return val 37.377 + 37.378 + def op_sys_subscribe(self, name, v): 37.379 + # (sys.subscribe event*) 37.380 + # Subscribe to the events: 37.381 + self.subscribe(v[1:]) 37.382 + return ['ok'] 37.383 + 37.384 + def op_sys_inject(self, name, v): 37.385 + # (sys.inject event) 37.386 + event = v[1] 37.387 + eserver.inject(sxp.name(event), event) 37.388 + return ['ok'] 37.389 + 37.390 + 37.391 +class EventFactory(protocol.Factory): 37.392 + """Asynchronous handler for the event server socket. 37.393 + """ 37.394 + protocol = EventProtocol 37.395 + service = None 37.396 + 37.397 + def __init__(self, daemon): 37.398 + #protocol.Factory.__init__(self) 37.399 + self.daemon = daemon 37.400 + 37.401 + def buildProtocol(self, addr): 37.402 + proto = self.protocol(self.daemon) 37.403 + proto.factory = self 37.404 + return proto 37.405 + 37.406 +class Daemon: 37.407 + """The xend daemon. 37.408 + """ 37.409 + def __init__(self): 37.410 + self.shutdown = 0 37.411 + 37.412 + def daemon_pids(self): 37.413 + pids = [] 37.414 + pidex = '(?P<pid>\d+)' 37.415 + pythonex = '(?P<python>\S*python\S*)' 37.416 + cmdex = '(?P<cmd>.*)' 37.417 + procre = re.compile('^\s*' + pidex + '\s*' + pythonex + '\s*' + cmdex + '$') 37.418 + xendre = re.compile('^/usr/sbin/xend\s*(start|restart)\s*.*$') 37.419 + procs = os.popen('ps -e -o pid,args 2>/dev/null') 37.420 + for proc in procs: 37.421 + pm = procre.match(proc) 37.422 + if not pm: continue 37.423 + xm = xendre.match(pm.group('cmd')) 37.424 + if not xm: continue 37.425 + #print 'pid=', pm.group('pid'), 'cmd=', pm.group('cmd') 37.426 + pids.append(int(pm.group('pid'))) 37.427 + return pids 37.428 + 37.429 + def new_cleanup(self, kill=0): 37.430 + err = 0 37.431 + pids = self.daemon_pids() 37.432 + if kill: 37.433 + for pid in pids: 37.434 + print "Killing daemon pid=%d" % pid 37.435 + os.kill(pid, signal.SIGHUP) 37.436 + elif pids: 37.437 + err = 1 37.438 + print "Daemon already running: ", pids 37.439 + return err 37.440 + 37.441 + def cleanup(self, kill=False): 37.442 + # No cleanup to do if PID_FILE is empty. 37.443 + if not os.path.isfile(PID_FILE) or not os.path.getsize(PID_FILE): 37.444 + return 0 37.445 + # Read the pid of the previous invocation and search active process list. 37.446 + pid = open(PID_FILE, 'r').read() 37.447 + lines = os.popen('ps ' + pid + ' 2>/dev/null').readlines() 37.448 + for line in lines: 37.449 + if re.search('^ *' + pid + '.+xend', line): 37.450 + if not kill: 37.451 + print "Daemon is already running (pid %d)" % int(pid) 37.452 + return 1 37.453 + # Old daemon is still active: terminate it. 37.454 + os.kill(int(pid), 1) 37.455 + # Delete the stale PID_FILE. 37.456 + os.remove(PID_FILE) 37.457 + return 0 37.458 + 37.459 + def install_child_reaper(self): 37.460 + #signal.signal(signal.SIGCHLD, self.onSIGCHLD) 37.461 + # Ensure that zombie children are automatically reaped. 37.462 + xend.utils.autoreap() 37.463 + 37.464 + def onSIGCHLD(self, signum, frame): 37.465 + code = 1 37.466 + while code > 0: 37.467 + code = os.waitpid(-1, os.WNOHANG) 37.468 + 37.469 + def start(self): 37.470 + if self.cleanup(kill=False): 37.471 + return 1 37.472 + 37.473 + # Detach from TTY. 37.474 + if not DEBUG: 37.475 + os.setsid() 37.476 + 37.477 + if self.set_user(): 37.478 + return 1 37.479 + 37.480 + self.install_child_reaper() 37.481 + 37.482 + # Fork -- parent writes PID_FILE and exits. 37.483 + pid = os.fork() 37.484 + if pid: 37.485 + # Parent 37.486 + pidfile = open(PID_FILE, 'w') 37.487 + pidfile.write(str(pid)) 37.488 + pidfile.close() 37.489 + return 0 37.490 + # Child 37.491 + logfile = self.open_logfile() 37.492 + self.redirect_output(logfile) 37.493 + self.run() 37.494 + return 0 37.495 + 37.496 + def open_logfile(self): 37.497 + if not os.path.exists(CONTROL_DIR): 37.498 + os.makedirs(CONTROL_DIR) 37.499 + 37.500 + # Open log file. Truncate it if non-empty, and request line buffering. 37.501 + if os.path.isfile(LOG_FILE): 37.502 + os.rename(LOG_FILE, LOG_FILE+'.old') 37.503 + logfile = open(LOG_FILE, 'w+', 1) 37.504 + return logfile 37.505 + 37.506 + def set_user(self): 37.507 + # Set the UID. 37.508 + try: 37.509 + os.setuid(pwd.getpwnam(USER)[2]) 37.510 + return 0 37.511 + except KeyError, error: 37.512 + print "Error: no such user '%s'" % USER 37.513 + return 1 37.514 + 37.515 + def redirect_output(self, logfile): 37.516 + if DEBUG: return 37.517 + # Close down standard file handles 37.518 + try: 37.519 + os.close(0) # stdin 37.520 + os.close(1) # stdout 37.521 + os.close(2) # stderr 37.522 + except: 37.523 + pass 37.524 + # Redirect output to log file. 37.525 + sys.stdout = sys.stderr = logfile 37.526 + 37.527 + def stop(self): 37.528 + return self.cleanup(kill=True) 37.529 + 37.530 + def run(self): 37.531 + self.createFactories() 37.532 + self.listenMgmt() 37.533 + self.listenEvent() 37.534 + self.listenNotifier() 37.535 + SrvServer.create() 37.536 + reactor.run() 37.537 + 37.538 + def createFactories(self): 37.539 + self.channelF = channel.channelFactory() 37.540 + self.blkifCF = blkif.BlkifControllerFactory() 37.541 + self.netifCF = netif.NetifControllerFactory() 37.542 + self.consoleCF = console.ConsoleControllerFactory() 37.543 + 37.544 + def listenMgmt(self): 37.545 + protocol = MgmtProtocol(self) 37.546 + s = os.path.join(CONTROL_DIR, MGMT_SOCK) 37.547 + if os.path.exists(s): 37.548 + os.unlink(s) 37.549 + return reactor.listenUNIXDatagram(s, protocol) 37.550 + 37.551 + def listenEvent(self): 37.552 + protocol = EventFactory(self) 37.553 + return reactor.listenTCP(EVENT_PORT, protocol) 37.554 + 37.555 + def listenNotifier(self): 37.556 + protocol = NotifierProtocol(self.channelF) 37.557 + p = NotifierPort(self, self.channelF.notifier, protocol, reactor) 37.558 + p.startListening() 37.559 + return p 37.560 + 37.561 + def exit(self): 37.562 + reactor.diconnectAll() 37.563 + sys.exit(0) 37.564 + 37.565 + def blkif_create(self, dom): 37.566 + """Create a block device interface controller. 37.567 + 37.568 + Returns Deferred 37.569 + """ 37.570 + d = self.blkifCF.createInstance(dom) 37.571 + return d 37.572 + 37.573 + def blkif_dev_create(self, dom, vdev, mode, segment): 37.574 + """Create a block device. 37.575 + 37.576 + Returns Deferred 37.577 + """ 37.578 + ctrl = self.blkifCF.getInstanceByDom(dom) 37.579 + if not ctrl: 37.580 + raise ValueError('No blkif controller: %d' % dom) 37.581 + print 'blkif_dev_create>', dom, vdev, mode, segment 37.582 + d = ctrl.attach_device(vdev, mode, segment) 37.583 + return d 37.584 + 37.585 + def netif_create(self, dom): 37.586 + """Create a network interface controller. 37.587 + 37.588 + """ 37.589 + return self.netifCF.createInstance(dom) 37.590 + 37.591 + def netif_dev_create(self, dom, vif, vmac): 37.592 + """Create a network device. 37.593 + 37.594 + todo 37.595 + """ 37.596 + ctrl = self.netifCF.getInstanceByDom(dom) 37.597 + if not ctrl: 37.598 + raise ValueError('No netif controller: %d' % dom) 37.599 + d = ctrl.attach_device(vif, vmac) 37.600 + return d 37.601 + 37.602 + def console_create(self, dom, console_port=None): 37.603 + """Create a console for a domain. 37.604 + """ 37.605 + console = self.consoleCF.getInstanceByDom(dom) 37.606 + if console is None: 37.607 + console = self.consoleCF.createInstance(dom, console_port) 37.608 + return console.sxpr() 37.609 + 37.610 + def consoles(self): 37.611 + return [ c.sxpr() for c in self.consoleCF.getInstances() ] 37.612 + 37.613 + def get_console(self, id): 37.614 + return self.consoleCF.getInstance(id) 37.615 + 37.616 + def get_domain_console(self, dom): 37.617 + return self.consoleCF.getInstanceByDom(dom) 37.618 + 37.619 + def console_disconnect(self, id): 37.620 + """Disconnect any connected console client. 37.621 + """ 37.622 + console = self.get_console(id) 37.623 + if not console: 37.624 + raise ValueError('Invalid console id') 37.625 + if console.conn: 37.626 + console.conn.loseConnection() 37.627 + 37.628 +def instance(): 37.629 + global inst 37.630 + try: 37.631 + inst 37.632 + except: 37.633 + inst = Daemon() 37.634 + return inst
38.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 38.2 +++ b/tools/xenmgr/lib/server/SrvDeviceDir.py Fri Jun 11 18:31:12 2004 +0000 38.3 @@ -0,0 +1,9 @@ 38.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com> 38.5 + 38.6 +from SrvDir import SrvDir 38.7 + 38.8 +class SrvDeviceDir(SrvDir): 38.9 + """Device directory. 38.10 + """ 38.11 + 38.12 + pass
39.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 39.2 +++ b/tools/xenmgr/lib/server/SrvDir.py Fri Jun 11 18:31:12 2004 +0000 39.3 @@ -0,0 +1,91 @@ 39.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com> 39.5 + 39.6 +from twisted.web import error 39.7 +from xenmgr import sxp 39.8 +from SrvBase import SrvBase 39.9 + 39.10 +class SrvConstructor: 39.11 + """Delayed constructor for sub-servers. 39.12 + Does not import the sub-server class or create the object until needed. 39.13 + """ 39.14 + 39.15 + def __init__(self, klass): 39.16 + """Create a constructor. It is assumed that the class 39.17 + should be imported as 'import klass from klass'. 39.18 + 39.19 + klass name of its class 39.20 + """ 39.21 + self.klass = klass 39.22 + self.obj = None 39.23 + 39.24 + def getobj(self): 39.25 + """Get the sub-server object, importing its class and instantiating it if 39.26 + necessary. 39.27 + """ 39.28 + if not self.obj: 39.29 + exec 'from %s import %s' % (self.klass, self.klass) 39.30 + klassobj = eval(self.klass) 39.31 + self.obj = klassobj() 39.32 + return self.obj 39.33 + 39.34 +class SrvDir(SrvBase): 39.35 + """Base class for directory servlets. 39.36 + """ 39.37 + isLeaf = False 39.38 + 39.39 + def __init__(self): 39.40 + SrvBase.__init__(self) 39.41 + self.table = {} 39.42 + self.order = [] 39.43 + 39.44 + def getChild(self, x, req): 39.45 + if x == '': return self 39.46 + val = self.get(x) 39.47 + if val is None: 39.48 + return error.NoResource('Not found') 39.49 + else: 39.50 + return val 39.51 + 39.52 + def get(self, x): 39.53 + val = self.table.get(x) 39.54 + if val is not None: 39.55 + val = val.getobj() 39.56 + return val 39.57 + 39.58 + def add(self, x, xclass = None): 39.59 + if xclass is None: 39.60 + xclass = 'SrvDir' 39.61 + self.table[x] = SrvConstructor(xclass) 39.62 + self.order.append(x) 39.63 + 39.64 + def render_GET(self, req): 39.65 + if self.use_sxp(req): 39.66 + req.setHeader("Content-type", sxp.mime_type) 39.67 + self.ls(req, 1) 39.68 + else: 39.69 + req.write('<html><head></head><body>') 39.70 + self.print_path(req) 39.71 + self.ls(req) 39.72 + self.form(req) 39.73 + req.write('</body></html>') 39.74 + return '' 39.75 + 39.76 + def ls(self, req, use_sxp=0): 39.77 + url = req.prePathURL() 39.78 + if not url.endswith('/'): 39.79 + url += '/' 39.80 + if use_sxp: 39.81 + req.write('(ls ') 39.82 + for k in self.order: 39.83 + req.write(' ' + k) 39.84 + req.write(')') 39.85 + else: 39.86 + req.write('<ul>') 39.87 + for k in self.order: 39.88 + v = self.get(k) 39.89 + req.write('<li><a href="%s%s">%s</a></li>' 39.90 + % (url, k, k)) 39.91 + req.write('</ul>') 39.92 + 39.93 + def form(self, req): 39.94 + pass
40.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 40.2 +++ b/tools/xenmgr/lib/server/SrvDomain.py Fri Jun 11 18:31:12 2004 +0000 40.3 @@ -0,0 +1,202 @@ 40.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com> 40.5 + 40.6 +from xenmgr import sxp 40.7 +from xenmgr import XendDomain 40.8 +from xenmgr import XendConsole 40.9 +from xenmgr import PrettyPrint 40.10 +from xenmgr.Args import FormFn 40.11 + 40.12 +from SrvDir import SrvDir 40.13 + 40.14 +class SrvDomain(SrvDir): 40.15 + """Service managing a single domain. 40.16 + """ 40.17 + 40.18 + def __init__(self, dom): 40.19 + SrvDir.__init__(self) 40.20 + self.dom = dom 40.21 + self.xd = XendDomain.instance() 40.22 + self.xconsole = XendConsole.instance() 40.23 + 40.24 + def op_start(self, op, req): 40.25 + val = self.xd.domain_start(self.dom.id) 40.26 + return val 40.27 + 40.28 + def op_stop(self, op, req): 40.29 + val = self.xd.domain_stop(self.dom.id) 40.30 + return val 40.31 + 40.32 + def op_shutdown(self, op, req): 40.33 + val = self.xd.domain_shutdown(self.dom.id) 40.34 + req.setResponseCode(202) 40.35 + req.setHeader("Location", "%s/.." % req.prePathURL()) 40.36 + return val 40.37 + 40.38 + def op_halt(self, op, req): 40.39 + val = self.xd.domain_halt(self.dom.id) 40.40 + req.setHeader("Location", "%s/.." % req.prePathURL()) 40.41 + return val 40.42 + 40.43 + def op_save(self, op, req): 40.44 + fn = FormFn(self.xd.domain_save, 40.45 + [['dom', 'int'], 40.46 + ['dst', 'str']]) 40.47 + val = fn(req.args, {'dom': self.dom.id}) 40.48 + return val 40.49 + 40.50 + def op_restore(self, op, req): 40.51 + fn = FormFn(self.xd.domain_restore, 40.52 + [['dom', 'int'], 40.53 + ['src', 'str']]) 40.54 + val = fn(req.args, {'dom': self.dom.id}) 40.55 + return val 40.56 + 40.57 + def op_migrate(self, op, req): 40.58 + fn = FormFn(self.xd.domain_migrate, 40.59 + [['dom', 'int'], 40.60 + ['destination', 'str']]) 40.61 + val = fn(req.args, {'dom': self.dom.id}) 40.62 + val = 0 # Some migrate id. 40.63 + req.setResponseCode(202) 40.64 + #req.send_header("Location", "%s/.." % self.path) # Some migrate url. 40.65 + return val 40.66 + 40.67 + def op_pincpu(self, op, req): 40.68 + fn = FormFn(self.xd.domain_migrate, 40.69 + [['dom', 'int'], 40.70 + ['cpu', 'int']]) 40.71 + val = fn(req.args, {'dom': self.dom.id}) 40.72 + return val 40.73 + 40.74 + def op_cpu_bvt_set(self, op, req): 40.75 + fn = FormFn(self.xd.domain_cpu_bvt_set, 40.76 + [['dom', 'int'], 40.77 + ['mcuadv', 'int'], 40.78 + ['warp', 'int'], 40.79 + ['warpl', 'int'], 40.80 + ['warpu', 'int']]) 40.81 + val = fn(req.args, {'dom': self.dom.id}) 40.82 + return val 40.83 + 40.84 + def op_cpu_atropos_set(self, op, req): 40.85 + fn = FormFn(self.xd.domain_cpu_atropos_set, 40.86 + [['dom', 'int'], 40.87 + ['period', 'int'], 40.88 + ['slice', 'int'], 40.89 + ['latency', 'int'], 40.90 + ['xtratime', 'int']]) 40.91 + val = fn(req.args, {'dom': self.dom.id}) 40.92 + return val 40.93 + 40.94 + def op_vifs(self, op, req): 40.95 + return self.xd.domain_vif_ls(self.dom.id) 40.96 + 40.97 + def op_vif(self, op, req): 40.98 + fn = FormFn(self.xd.domain_vif_get, 40.99 + [['dom', 'int'], 40.100 + ['vif', 'int']]) 40.101 + val = fn(req.args, {'dom': self.dom.id}) 40.102 + return val 40.103 + 40.104 + def op_vif_stats(self, op, req): 40.105 + #todo 40.106 + fn = FormFn(self.xd.domain_vif_stats, 40.107 + [['dom', 'int'], 40.108 + ['vif', 'int']]) 40.109 + #val = fn(req.args, {'dom': self.dom.id}) 40.110 + val = 999 40.111 + #return val 40.112 + return val 40.113 + 40.114 + def op_vif_ip_add(self, op, req): 40.115 + fn = FormFn(self.xd.domain_vif_ip_add, 40.116 + [['dom', 'int'], 40.117 + ['vif', 'int'], 40.118 + ['ip', 'str']]) 40.119 + val = fn(req.args, {'dom': self.dom.id}) 40.120 + return val 40.121 + 40.122 + def op_vif_scheduler_set(self, op, req): 40.123 + fn = FormFn(self.xd.domain_vif_scheduler_set, 40.124 + [['dom', 'int'], 40.125 + ['vif', 'int'], 40.126 + ['bytes', 'int'], 40.127 + ['usecs', 'int']]) 40.128 + val = fn(req.args, {'dom': self.dom.id}) 40.129 + return val 40.130 + 40.131 + def op_vif_scheduler_get(self, op, req): 40.132 + fn = FormFn(self.xd.domain_vif_scheduler_set, 40.133 + [['dom', 'int'], 40.134 + ['vif', 'int']]) 40.135 + val = fn(req.args, {'dom': self.dom.id}) 40.136 + return val 40.137 + 40.138 + def op_vbds(self, op, req): 40.139 + return self.xd.domain_vbd_ls(self.dom.id) 40.140 + 40.141 + def op_vbd(self, op, req): 40.142 + fn = FormFn(self.xd.domain_vbd_get, 40.143 + [['dom', 'int'], 40.144 + ['vbd', 'int']]) 40.145 + val = fn(req.args, {'dom': self.dom.id}) 40.146 + return val 40.147 + 40.148 + def op_vbd_add(self, op, req): 40.149 + fn = FormFn(self.xd.domain_vbd_add, 40.150 + [['dom', 'int'], 40.151 + ['uname', 'str'], 40.152 + ['dev', 'str'], 40.153 + ['mode', 'str']]) 40.154 + val = fn(req.args, {'dom': self.dom.id}) 40.155 + return val 40.156 + 40.157 + def op_vbd_remove(self, op, req): 40.158 + fn = FormFn(self.xd.domain_vbd_remove, 40.159 + [['dom', 'int'], 40.160 + ['dev', 'str']]) 40.161 + val = fn(req.args, {'dom': self.dom.id}) 40.162 + return val 40.163 + 40.164 + def render_POST(self, req): 40.165 + return self.perform(req) 40.166 + 40.167 + def render_GET(self, req): 40.168 + op = req.args.get('op') 40.169 + if op and op[0] in ['vifs', 'vif', 'vif_stats', 'vbds', 'vbd']: 40.170 + return self.perform(req) 40.171 + if self.use_sxp(req): 40.172 + req.setHeader("Content-Type", sxp.mime_type) 40.173 + sxp.show(self.dom.sxpr(), out=req) 40.174 + else: 40.175 + req.write('<html><head></head><body>') 40.176 + self.print_path(req) 40.177 + #self.ls() 40.178 + req.write('<p>%s</p>' % self.dom) 40.179 + if self.dom.console: 40.180 + cinfo = self.dom.console 40.181 + cid = cinfo.id 40.182 + #todo: Local xref: need to know server prefix. 40.183 + req.write('<p><a href="/xend/console/%s">Console %s</a></p>' 40.184 + % (cid, cid)) 40.185 + req.write('<p><a href="%s">Connect to console</a></p>' 40.186 + % cinfo.uri()) 40.187 + if self.dom.config: 40.188 + req.write("<code><pre>") 40.189 + PrettyPrint.prettyprint(self.dom.config, out=req) 40.190 + req.write("</pre></code>") 40.191 + req.write('<a href="%s?op=vif_stats&vif=0">vif 0 stats</a>' 40.192 + % req.prePathURL()) 40.193 + self.form(req) 40.194 + req.write('</body></html>') 40.195 + return '' 40.196 + 40.197 + def form(self, req): 40.198 + req.write('<form method="post" action="%s">' % req.prePathURL()) 40.199 + req.write('<input type="submit" name="op" value="start">') 40.200 + req.write('<input type="submit" name="op" value="stop">') 40.201 + req.write('<input type="submit" name="op" value="shutdown">') 40.202 + req.write('<input type="submit" name="op" value="halt">') 40.203 + req.write('<br><input type="submit" name="op" value="migrate">') 40.204 + req.write('To: <input type="text" name="destination">') 40.205 + req.write('</form>')
41.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 41.2 +++ b/tools/xenmgr/lib/server/SrvDomainDir.py Fri Jun 11 18:31:12 2004 +0000 41.3 @@ -0,0 +1,130 @@ 41.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com> 41.5 + 41.6 +from StringIO import StringIO 41.7 + 41.8 +from twisted.protocols import http 41.9 +from twisted.web import error 41.10 + 41.11 +from xenmgr import sxp 41.12 +from xenmgr import XendDomain 41.13 + 41.14 +from SrvDir import SrvDir 41.15 +from SrvDomain import SrvDomain 41.16 + 41.17 +class SrvDomainDir(SrvDir): 41.18 + """Service that manages the domain directory. 41.19 + """ 41.20 + 41.21 + def __init__(self): 41.22 + SrvDir.__init__(self) 41.23 + self.xd = XendDomain.instance() 41.24 + 41.25 + def domain(self, x): 41.26 + val = None 41.27 + try: 41.28 + dom = self.xd.domain_get(x) 41.29 + val = SrvDomain(dom) 41.30 + except KeyError: 41.31 + pass 41.32 + return val 41.33 + 41.34 + def get(self, x): 41.35 + v = SrvDir.get(self, x) 41.36 + if v is not None: 41.37 + return v 41.38 + v = self.domain(x) 41.39 + return v 41.40 + 41.41 + def op_create(self, op, req): 41.42 + ok = 0 41.43 + try: 41.44 + configstring = req.args.get('config')[0] 41.45 + print 'config:', configstring 41.46 + pin = sxp.Parser() 41.47 + pin.input(configstring) 41.48 + pin.input_eof() 41.49 + config = pin.get_val() 41.50 + ok = 1 41.51 + except Exception, ex: 41.52 + print ex 41.53 + if not ok: 41.54 + req.setResponseCode(http.BAD_REQUEST, "Invalid configuration") 41.55 + return "Invalid configuration" 41.56 + return error.ErrorPage(http.BAD_REQUEST, 41.57 + "Invalid", 41.58 + "Invalid configuration") 41.59 + try: 41.60 + deferred = self.xd.domain_create(config) 41.61 + deferred.addCallback(self._cb_op_create, configstring, req) 41.62 + return deferred 41.63 + except Exception, ex: 41.64 + raise 41.65 + #return ['err', str(ex) ] 41.66 + #req.setResponseCode(http.BAD_REQUEST, "Error creating domain") 41.67 + #return str(ex) 41.68 + #return error.ErrorPage(http.BAD_REQUEST, 41.69 + # "Error creating domain", 41.70 + # str(ex)) 41.71 + 41.72 + 41.73 + def _cb_op_create(self, dominfo, configstring, req): 41.74 + """Callback to handle deferred domain creation. 41.75 + """ 41.76 + dom = dominfo.id 41.77 + domurl = "%s/%s" % (req.prePathURL(), dom) 41.78 + req.setResponseCode(201, "created") 41.79 + req.setHeader("Location", domurl) 41.80 + if self.use_sxp(req): 41.81 + return dominfo.sxpr() 41.82 + else: 41.83 + out = StringIO() 41.84 + print >> out, ('<p> Created <a href="%s">Domain %s</a></p>' 41.85 + % (domurl, dom)) 41.86 + print >> out, '<p><pre>' 41.87 + print >> out, configstring 41.88 + print >> out, '</pre></p>' 41.89 + val = out.getvalue() 41.90 + out.close() 41.91 + return val 41.92 + 41.93 + def render_POST(self, req): 41.94 + return self.perform(req) 41.95 + 41.96 + def render_GET(self, req): 41.97 + if self.use_sxp(req): 41.98 + req.setHeader("Content-Type", sxp.mime_type) 41.99 + self.ls_domain(req, 1) 41.100 + else: 41.101 + req.write("<html><head></head><body>") 41.102 + self.print_path(req) 41.103 + self.ls(req) 41.104 + self.ls_domain(req) 41.105 + self.form(req) 41.106 + req.write("</body></html>") 41.107 + return '' 41.108 + 41.109 + def ls_domain(self, req, use_sxp=0): 41.110 + url = req.prePathURL() 41.111 + if not url.endswith('/'): 41.112 + url += '/' 41.113 + if use_sxp: 41.114 + domains = self.xd.domain_ls() 41.115 + sxp.show(domains, out=req) 41.116 + else: 41.117 + domains = self.xd.domains() 41.118 + domains.sort(lambda x, y: cmp(x.id, y.id)) 41.119 + req.write('<ul>') 41.120 + for d in domains: 41.121 + req.write('<li><a href="%s%s"> Domain %s</a>' 41.122 + % (url, d.id, d.id)) 41.123 + req.write('name=%s' % d.name) 41.124 + req.write('memory=%d'% d.memory) 41.125 + req.write('</li>') 41.126 + req.write('</ul>') 41.127 + 41.128 + def form(self, req): 41.129 + req.write('<form method="post" action="%s" enctype="multipart/form-data">' 41.130 + % req.prePathURL()) 41.131 + req.write('<button type="submit" name="op" value="create">Create Domain</button>') 41.132 + req.write('Config <input type="file" name="config"><br>') 41.133 + req.write('</form>')
42.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 42.2 +++ b/tools/xenmgr/lib/server/SrvEventDir.py Fri Jun 11 18:31:12 2004 +0000 42.3 @@ -0,0 +1,41 @@ 42.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com> 42.5 + 42.6 +from xenmgr import sxp 42.7 +from xenmgr import EventServer 42.8 +from SrvDir import SrvDir 42.9 + 42.10 +class SrvEventDir(SrvDir): 42.11 + """Event directory. 42.12 + """ 42.13 + 42.14 + def __init__(self): 42.15 + SrvDir.__init__(self) 42.16 + self.eserver = EventServer.instance() 42.17 + 42.18 + def op_inject(self, op, req): 42.19 + eventstring = req.args.get('event') 42.20 + pin = sxp.Parser() 42.21 + pin.input(eventstring) 42.22 + pin.input_eof() 42.23 + sxpr = pin.get_val() 42.24 + self.eserver.inject(sxp.name(sxpr), sxpr) 42.25 + if req.use_sxp: 42.26 + sxp.name(sxpr) 42.27 + else: 42.28 + return '<code>' + eventstring + '</code>' 42.29 + 42.30 + def render_POST(self, req): 42.31 + return self.perform(req) 42.32 + 42.33 + def form(self, req): 42.34 + action = req.prePathURL() 42.35 + req.write('<form method="post" action="%s" enctype="multipart/form-data">' 42.36 + % action) 42.37 + req.write('<button type="submit" name="op" value="inject">Inject</button>') 42.38 + req.write('Event <input type="text" name="event" size="40"><br>') 42.39 + req.write('</form>') 42.40 + req.write('<form method="post" action="%s" enctype="multipart/form-data">' 42.41 + % action) 42.42 + req.write('<button type="submit" name="op" value="inject">Inject</button>') 42.43 + req.write('Event file<input type="file" name="event"><br>') 42.44 + req.write('</form>')
43.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 43.2 +++ b/tools/xenmgr/lib/server/SrvNode.py Fri Jun 11 18:31:12 2004 +0000 43.3 @@ -0,0 +1,59 @@ 43.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com> 43.5 + 43.6 +import os 43.7 +from SrvDir import SrvDir 43.8 +from xenmgr import sxp 43.9 +from xenmgr import XendNode 43.10 + 43.11 +class SrvNode(SrvDir): 43.12 + """Information about the node. 43.13 + """ 43.14 + 43.15 + def __init__(self): 43.16 + SrvDir.__init__(self) 43.17 + self.xn = XendNode.instance() 43.18 + 43.19 + def op_shutdown(self, op, req): 43.20 + val = self.xn.shutdown() 43.21 + return val 43.22 + 43.23 + def op_reboot(self, op, req): 43.24 + val = self.xn.reboot() 43.25 + return val 43.26 + 43.27 + def op_cpu_rrobin_slice_set(self, op, req): 43.28 + fn = FormFn(self.xn.cpu_rrobin_slice_set, 43.29 + [['slice', 'int']]) 43.30 + val = fn(req.args, {}) 43.31 + return val 43.32 + 43.33 + def op_cpu_bvt_slice_set(self, op, req): 43.34 + fn = FormFn(self.xn.cpu_bvt_slice_set, 43.35 + [['slice', 'int']]) 43.36 + val = fn(req.args, {}) 43.37 + return val 43.38 + 43.39 + def render_POST(self, req): 43.40 + return self.perform(req) 43.41 + 43.42 + def render_GET(self, req): 43.43 + if self.use_sxp(req): 43.44 + req.setHeader("Content-Type", sxp.mime_type) 43.45 + sxp.show(['node'] + self.info(), out=req) 43.46 + else: 43.47 + req.write('<html><head></head><body>') 43.48 + self.print_path(req) 43.49 + req.write('<ul>') 43.50 + for d in self.info(): 43.51 + req.write('<li> %10s: %s' % (d[0], d[1])) 43.52 + req.write('</ul>') 43.53 + req.write('</body></html>') 43.54 + return '' 43.55 + 43.56 + def info(self): 43.57 + (sys, host, rel, ver, mch) = os.uname() 43.58 + return [['system', sys], 43.59 + ['host', host], 43.60 + ['release', rel], 43.61 + ['version', ver], 43.62 + ['machine', mch]]
44.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 44.2 +++ b/tools/xenmgr/lib/server/SrvRoot.py Fri Jun 11 18:31:12 2004 +0000 44.3 @@ -0,0 +1,31 @@ 44.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com> 44.5 + 44.6 +from xenmgr import XendRoot 44.7 +xroot = XendRoot.instance() 44.8 +from SrvDir import SrvDir 44.9 + 44.10 +class SrvRoot(SrvDir): 44.11 + """The root of the xend server. 44.12 + """ 44.13 + 44.14 + """Server sub-components. Each entry is (name, class), where 44.15 + 'name' is the entry name and 'class' is the name of its class. 44.16 + """ 44.17 + #todo Get this list from the XendRoot config. 44.18 + subdirs = [ 44.19 + ('node', 'SrvNode' ), 44.20 + ('domain', 'SrvDomainDir' ), 44.21 + ('console', 'SrvConsoleDir' ), 44.22 + ('event', 'SrvEventDir' ), 44.23 + ('vdisk', 'SrvVdiskDir' ), 44.24 + ('device', 'SrvDeviceDir' ), 44.25 + ('vnet', 'SrvVnetDir' ), 44.26 + ] 44.27 + 44.28 + def __init__(self): 44.29 + SrvDir.__init__(self) 44.30 + for (name, klass) in self.subdirs: 44.31 + self.add(name, klass) 44.32 + for (name, klass) in self.subdirs: 44.33 + self.get(name) 44.34 + xroot.start()
45.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 45.2 +++ b/tools/xenmgr/lib/server/SrvServer.py Fri Jun 11 18:31:12 2004 +0000 45.3 @@ -0,0 +1,53 @@ 45.4 +#!/usr/bin/python2 45.5 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com> 45.6 + 45.7 +"""Example xend HTTP and console server. 45.8 + 45.9 + Can be accessed from a browser or from a program. 45.10 + Do 'python SrvServer.py' to run the server. 45.11 + Then point a web browser at http://localhost:8000/xend and follow the links. 45.12 + Most are stubs, except /domain which has a list of domains and a 'create domain' 45.13 + button. 45.14 + 45.15 + You can also access the server from a program. 45.16 + Do 'python XendClient.py' to run a few test operations. 45.17 + 45.18 + The data served differs depending on the client (as defined by User-Agent 45.19 + and Accept in the HTTP headers). If the client is a browser, data 45.20 + is returned in HTML, with interactive forms. If the client is a program, 45.21 + data is returned in SXP format, with no forms. 45.22 + 45.23 + The server serves to the world by default. To restrict it to the local host 45.24 + change 'interface' in main(). 45.25 + 45.26 + Mike Wray <mike.wray@hp.com> 45.27 +""" 45.28 +# todo Support security settings etc. in the config file. 45.29 +# todo Support command-line args. 45.30 + 45.31 +from twisted.web import server 45.32 +from twisted.web import resource 45.33 +from twisted.internet import reactor 45.34 + 45.35 +from xenmgr import XendRoot 45.36 +xroot = XendRoot.instance() 45.37 + 45.38 +from SrvRoot import SrvRoot 45.39 + 45.40 +def create(port=None, interface=None): 45.41 + if port is None: port = 8000 45.42 + if interface is None: interface = '' 45.43 + root = resource.Resource() 45.44 + xend = SrvRoot() 45.45 + root.putChild('xend', xend) 45.46 + site = server.Site(root) 45.47 + reactor.listenTCP(port, site, interface=interface) 45.48 + 45.49 + 45.50 +def main(port=None, interface=None): 45.51 + create(port, interface) 45.52 + reactor.run() 45.53 + 45.54 + 45.55 +if __name__ == '__main__': 45.56 + main()
46.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 46.2 +++ b/tools/xenmgr/lib/server/SrvVdisk.py Fri Jun 11 18:31:12 2004 +0000 46.3 @@ -0,0 +1,12 @@ 46.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com> 46.5 + 46.6 +from xenmgr import XendVdisk 46.7 +from SrvVdiskDir import SrvVdiskDir 46.8 + 46.9 +class SrvVdisk(SrvDir): 46.10 + """A virtual disk. 46.11 + """ 46.12 + 46.13 + def __init__(self): 46.14 + SrvDir.__init__(self) 46.15 + self.xvdisk = XendVdisk.instance()
47.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 47.2 +++ b/tools/xenmgr/lib/server/SrvVdiskDir.py Fri Jun 11 18:31:12 2004 +0000 47.3 @@ -0,0 +1,28 @@ 47.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com> 47.5 + 47.6 +from xenmgr import XendVdisk 47.7 +from SrvDir import SrvDir 47.8 + 47.9 +class SrvVdiskDir(SrvDir): 47.10 + """Virtual disk directory. 47.11 + """ 47.12 + 47.13 + def __init__(self): 47.14 + SrvDir.__init__(self) 47.15 + self.xvdisk = XendVdisk.instance() 47.16 + 47.17 + def vdisk(self, x): 47.18 + val = None 47.19 + try: 47.20 + dom = self.xvdisk.vdisk_get(x) 47.21 + val = SrvVdisk(dom) 47.22 + except KeyError: 47.23 + pass 47.24 + return val 47.25 + 47.26 + def get(self, x): 47.27 + v = SrvDir.get(self, x) 47.28 + if v is not None: 47.29 + return v 47.30 + v = self.vdisk(x) 47.31 + return v
48.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 48.2 +++ b/tools/xenmgr/lib/server/SrvVnetDir.py Fri Jun 11 18:31:12 2004 +0000 48.3 @@ -0,0 +1,9 @@ 48.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com> 48.5 + 48.6 +from SrvDir import SrvDir 48.7 + 48.8 +class SrvVnetDir(SrvDir): 48.9 + """Vnet directory. 48.10 + """ 48.11 + 48.12 + pass
49.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 49.2 +++ b/tools/xenmgr/lib/server/__init__.py Fri Jun 11 18:31:12 2004 +0000 49.3 @@ -0,0 +1,1 @@ 49.4 +
50.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 50.2 +++ b/tools/xenmgr/lib/server/blkif.py Fri Jun 11 18:31:12 2004 +0000 50.3 @@ -0,0 +1,232 @@ 50.4 +import channel 50.5 +import controller 50.6 +from messages import * 50.7 + 50.8 +class BlkifControllerFactory(controller.ControllerFactory): 50.9 + """Factory for creating block device interface controllers. 50.10 + Also handles the 'back-end' channel to dom0. 50.11 + """ 50.12 + 50.13 + # todo: add support for setting dom controlling blkifs (don't assume 0). 50.14 + # todo: add support for 'recovery'. 50.15 + 50.16 + def __init__(self): 50.17 + controller.ControllerFactory.__init__(self) 50.18 + 50.19 + self.majorTypes = [ CMSG_BLKIF_BE ] 50.20 + 50.21 + self.subTypes = { 50.22 + CMSG_BLKIF_BE_CREATE : self.recv_be_create, 50.23 + CMSG_BLKIF_BE_CONNECT : self.recv_be_connect, 50.24 + CMSG_BLKIF_BE_VBD_CREATE : self.recv_be_vbd_create, 50.25 + CMSG_BLKIF_BE_VBD_GROW : self.recv_be_vbd_grow, 50.26 + CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED: self.recv_be_driver_status_changed, 50.27 + } 50.28 + self.attached = 1 50.29 + self.registerChannel() 50.30 + 50.31 + def createInstance(self, dom): 50.32 + d = self.addDeferred() 50.33 + blkif = self.getInstanceByDom(dom) 50.34 + if blkif: 50.35 + self.callDeferred(blkif) 50.36 + else: 50.37 + blkif = BlkifController(self, dom) 50.38 + self.addInstance(blkif) 50.39 + blkif.send_be_create() 50.40 + return d 50.41 + 50.42 + def setControlDomain(self, dom): 50.43 + if self.channel: 50.44 + self.deregisterChannel() 50.45 + self.attached = 0 50.46 + self.dom = dom 50.47 + self.registerChannel() 50.48 + # 50.49 + #if xend.blkif.be_port: 50.50 + # xend.blkif.recovery = True 50.51 + #xend.blkif.be_port = xend.main.port_from_dom(dom) 50.52 + 50.53 + def recv_be_create(self, msg, req): 50.54 + #print 'recv_be_create>' 50.55 + val = unpackMsg('blkif_be_create_t', msg) 50.56 + blkif = self.getInstanceByDom(val['domid']) 50.57 + self.callDeferred(blkif) 50.58 + 50.59 + def recv_be_connect(self, msg, req): 50.60 + #print 'recv_be_create>' 50.61 + val = unpackMsg('blkif_be_connect_t', msg) 50.62 + blkif = self.getInstanceByDom(val['domid']) 50.63 + if blkif: 50.64 + blkif.send_fe_interface_status_changed() 50.65 + else: 50.66 + pass 50.67 + 50.68 + def recv_be_vbd_create(self, msg, req): 50.69 + #print 'recv_be_vbd_create>' 50.70 + val = unpackMsg('blkif_be_vbd_create_t', msg) 50.71 + blkif = self.getInstanceByDom(val['domid']) 50.72 + if blkif: 50.73 + blkif.send_be_vbd_grow(val['vdevice']) 50.74 + else: 50.75 + pass 50.76 + 50.77 + def recv_be_vbd_grow(self, msg, req): 50.78 + #print 'recv_be_vbd_grow>' 50.79 + val = unpackMsg('blkif_be_vbd_grow_t', msg) 50.80 + # Check status? 50.81 + if self.attached: 50.82 + self.callDeferred(0) 50.83 + else: 50.84 + self.reattach_device(val['domid'], val['vdevice']) 50.85 + 50.86 + def reattach_device(self, dom, vdev): 50.87 + blkif = self.getInstanceByDom(dom) 50.88 + if blkif: 50.89 + blkif.reattach_device(vdev) 50.90 + attached = 1 50.91 + for blkif in self.getInstances(): 50.92 + if not blkif.attached: 50.93 + attached = 0 50.94 + break 50.95 + self.attached = attached 50.96 + if self.attached: 50.97 + self.reattached() 50.98 + 50.99 + def reattached(self): 50.100 + for blkif in self.getInstances(): 50.101 + blkif.reattached() 50.102 + 50.103 + def recv_be_driver_status_changed(self, msg, req): 50.104 + val = unpackMsg('blkif_be_driver_status_changed_t'. msg) 50.105 + status = val['status'] 50.106 + if status == BLKIF_DRIVER_STATUS_UP and not self.attached: 50.107 + for blkif in self.getInstances(): 50.108 + blkif.detach() 50.109 + 50.110 +class BlkDev: 50.111 + """Info record for a block device. 50.112 + """ 50.113 + 50.114 + def __init__(self, vdev, mode, segment): 50.115 + self.vdev = vdev 50.116 + self.mode = mode 50.117 + self.device = segment['device'] 50.118 + self.start_sector = segment['start_sector'] 50.119 + self.nr_sectors = segment['nr_sectors'] 50.120 + self.attached = 1 50.121 + 50.122 + def readonly(self): 50.123 + return 'w' not in self.mode 50.124 + 50.125 +class BlkifController(controller.Controller): 50.126 + """Block device interface controller. Handles all block devices 50.127 + for a domain. 50.128 + """ 50.129 + 50.130 + def __init__(self, factory, dom): 50.131 + #print 'BlkifController> dom=', dom 50.132 + controller.Controller.__init__(self, factory, dom) 50.133 + self.devices = {} 50.134 + 50.135 + self.majorTypes = [ CMSG_BLKIF_FE ] 50.136 + 50.137 + self.subTypes = { 50.138 + CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED: 50.139 + self.recv_fe_driver_status_changed, 50.140 + CMSG_BLKIF_FE_INTERFACE_CONNECT : 50.141 + self.recv_fe_interface_connect, 50.142 + } 50.143 + self.attached = 1 50.144 + self.registerChannel() 50.145 + #print 'BlkifController<', 'dom=', self.dom, 'idx=', self.idx 50.146 + 50.147 + def attach_device(self, vdev, mode, segment): 50.148 + """Attach a device to the specified interface. 50.149 + """ 50.150 + #print 'BlkifController>attach_device>', self.dom, vdev, mode, segment 50.151 + if vdev in self.devices: return -1 50.152 + dev = BlkDev(vdev, mode, segment) 50.153 + self.devices[vdev] = dev 50.154 + self.send_be_vbd_create(vdev) 50.155 + return self.factory.addDeferred() 50.156 + 50.157 + def detach(self): 50.158 + self.attached = 0 50.159 + for dev in self.devices.values(): 50.160 + dev.attached = 0 50.161 + self.send_be_vbd_create(vdev) 50.162 + 50.163 + def reattach_device(self, vdev): 50.164 + dev = self.devices[vdev] 50.165 + dev.attached = 1 50.166 + attached = 1 50.167 + for dev in self.devices.values(): 50.168 + if not dev.attached: 50.169 + attached = 0 50.170 + break 50.171 + self.attached = attached 50.172 + return self.attached 50.173 + 50.174 + def reattached(self): 50.175 + msg = packMsg('blkif_fe_interface_status_changed_t', 50.176 + { 'handle' : 0, 50.177 + 'status' : BLKIF_INTERFACE_STATUS_DISCONNECTED}) 50.178 + self.writeRequest(msg) 50.179 + 50.180 + def recv_fe_driver_status_changed(self, msg, req): 50.181 + msg = packMsg('blkif_fe_interface_status_changed_t', 50.182 + { 'handle' : 0, 50.183 + 'status' : BLKIF_INTERFACE_STATUS_DISCONNECTED, 50.184 + 'evtchn' : 0 }) 50.185 + self.writeRequest(msg) 50.186 + 50.187 + def recv_fe_interface_connect(self, msg, req): 50.188 + val = unpackMsg('blkif_fe_interface_connect_t', msg) 50.189 + self.evtchn = channel.eventChannel(0, self.dom) 50.190 + msg = packMsg('blkif_be_connect_t', 50.191 + { 'domid' : self.dom, 50.192 + 'blkif_handle' : val['handle'], 50.193 + 'evtchn' : self.evtchn['port1'], 50.194 + 'shmem_frame' : val['shmem_frame'] }) 50.195 + self.factory.writeRequest(msg) 50.196 + pass 50.197 + 50.198 + #def recv_fe_interface_status_changed(self, msg, req): 50.199 + # (hnd, status, chan) = unpackMsg('blkif_fe_interface_status_changed_t', msg) 50.200 + # print 'recv_fe_interface_status_changed>', hnd, status, chan 50.201 + # pass 50.202 + 50.203 + def send_fe_interface_status_changed(self): 50.204 + msg = packMsg('blkif_fe_interface_status_changed_t', 50.205 + { 'handle' : 0, 50.206 + 'status' : BLKIF_INTERFACE_STATUS_CONNECTED, 50.207 + 'evtchn' : self.evtchn['port2'] }) 50.208 + self.writeRequest(msg) 50.209 + 50.210 + def send_be_create(self): 50.211 + msg = packMsg('blkif_be_create_t', 50.212 + { 'domid' : self.dom, 50.213 + 'blkif_handle' : 0 }) 50.214 + self.factory.writeRequest(msg) 50.215 + 50.216 + def send_be_vbd_create(self, vdev): 50.217 + dev = self.devices[vdev] 50.218 + msg = packMsg('blkif_be_vbd_create_t', 50.219 + { 'domid' : self.dom, 50.220 + 'blkif_handle' : 0, 50.221 + 'vdevice' : dev.vdev, 50.222 + 'readonly' : dev.readonly() }) 50.223 + self.factory.writeRequest(msg) 50.224 + 50.225 + def send_be_vbd_grow(self, vdev): 50.226 + dev = self.devices[vdev] 50.227 + msg = packMsg('blkif_be_vbd_grow_t', 50.228 + { 'domid' : self.dom, 50.229 + 'blkif_handle' : 0, 50.230 + 'vdevice' : dev.vdev, 50.231 + 'extent.device' : dev.device, 50.232 + 'extent.sector_start' : dev.start_sector, 50.233 + 'extent.sector_length' : dev.nr_sectors }) 50.234 + self.factory.writeRequest(msg) 50.235 +
51.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 51.2 +++ b/tools/xenmgr/lib/server/channel.py Fri Jun 11 18:31:12 2004 +0000 51.3 @@ -0,0 +1,259 @@ 51.4 +import Xc; xc = Xc.new() 51.5 +import xend.utils 51.6 +from messages import msgTypeName 51.7 + 51.8 +def eventChannel(dom1, dom2): 51.9 + return xc.evtchn_bind_interdomain(dom1=dom1, dom2=dom2) 51.10 + 51.11 +class ChannelFactory: 51.12 + """Factory for creating channels. 51.13 + Maintains a table of channels. 51.14 + """ 51.15 + 51.16 + channels = {} 51.17 + 51.18 + def __init__(self): 51.19 + self.notifier = xend.utils.notifier() 51.20 + 51.21 + def addChannel(self, channel): 51.22 + idx = channel.idx 51.23 + self.channels[idx] = channel 51.24 + self.notifier.bind(idx) 51.25 + # Try to wake it up 51.26 + #self.notifier.unmask(idx) 51.27 + #channel.notify() 51.28 + 51.29 + def getChannel(self, idx): 51.30 + return self.channels.get(idx) 51.31 + 51.32 + def delChannel(self, idx): 51.33 + if idx in self.channels: 51.34 + del self.channels[idx] 51.35 + self.notifier.unbind(idx) 51.36 + 51.37 + def domChannel(self, dom): 51.38 + for chan in self.channels.values(): 51.39 + if chan.dom == dom: 51.40 + return chan 51.41 + chan = Channel(self, dom) 51.42 + self.addChannel(chan) 51.43 + return chan 51.44 + 51.45 + def channelClosed(self, channel): 51.46 + self.delChannel(channel.idx) 51.47 + 51.48 + def createPort(self, dom): 51.49 + return xend.utils.port(dom) 51.50 + 51.51 +def channelFactory(): 51.52 + global inst 51.53 + try: 51.54 + inst 51.55 + except: 51.56 + inst = ChannelFactory() 51.57 + return inst 51.58 + 51.59 +class Channel: 51.60 + """A control channel to a domain. Messages for the domain device controllers 51.61 + are multiplexed over the channel (console, block devs, net devs). 51.62 + """ 51.63 + 51.64 + def __init__(self, factory, dom): 51.65 + self.factory = factory 51.66 + self.dom = dom 51.67 + self.port = self.factory.createPort(dom) 51.68 + self.idx = self.port.local_port 51.69 + self.devs = [] 51.70 + self.devs_by_type = {} 51.71 + self.closed = 0 51.72 + self.queue = [] 51.73 + 51.74 + def getIndex(self): 51.75 + return self.idx 51.76 + 51.77 + def getLocalPort(self): 51.78 + return self.port.local_port 51.79 + 51.80 + def getRemotePort(self): 51.81 + return self.port.remote_port 51.82 + 51.83 + def close(self): 51.84 + for d in self.devs: 51.85 + d.lostChannel() 51.86 + self.factory.channelClosed(self) 51.87 + del self.devs 51.88 + del self.devs_by_type 51.89 + 51.90 + def registerDevice(self, types, dev): 51.91 + """Register a device controller. 51.92 + 51.93 + @param types message types the controller handles 51.94 + @param dev device controller 51.95 + """ 51.96 + self.devs.append(dev) 51.97 + for ty in types: 51.98 + self.devs_by_type[ty] = dev 51.99 + 51.100 + def unregisterDevice(self, dev): 51.101 + """Remove the registration for a device controller. 51.102 + 51.103 + @param dev device controller 51.104 + """ 51.105 + self.devs.remove(dev) 51.106 + types = [ ty for (ty, d) in self.devs_by_type.items() 51.107 + if d == dev ] 51.108 + for ty in types: 51.109 + del devs_by_type[ty] 51.110 + 51.111 + def getDevice(self, type): 51.112 + """Get the device controller handling a message type. 51.113 + 51.114 + @param type message type 51.115 + @returns controller or None 51.116 + """ 51.117 + return self.devs_by_type.get(type) 51.118 + 51.119 + def getMessageType(self, msg): 51.120 + hdr = msg.get_header() 51.121 + return (hdr['type'], hdr.get('subtype')) 51.122 + 51.123 + def __repr__(self): 51.124 + return ('<Channel dom=%d ports=%d:%d>' 51.125 + % (self.dom, 51.126 + self.port.local_port, 51.127 + self.port.remote_port)) 51.128 + 51.129 + def notificationReceived(self, type): 51.130 + #print 'notificationReceived> type=', type, self 51.131 + if self.closed: return 51.132 + if type == self.factory.notifier.EXCEPTION: 51.133 + print 'notificationReceived> EXCEPTION' 51.134 + info = xc.evtchn_status(self.idx) 51.135 + if info['status'] == 'unbound': 51.136 + print 'notificationReceived> EXCEPTION closing...' 51.137 + self.close() 51.138 + return 51.139 + work = 0 51.140 + work += self.handleRequests() 51.141 + work += self.handleResponses() 51.142 + work += self.handleWrites() 51.143 + if work: 51.144 + self.notify() 51.145 + #print 'notificationReceived<', work 51.146 + 51.147 + def notify(self): 51.148 + #print 'notify>', self 51.149 + self.port.notify() 51.150 + 51.151 + def handleRequests(self): 51.152 + #print 'handleRequests>' 51.153 + work = 0 51.154 + while 1: 51.155 + #print 'handleRequests>', work 51.156 + msg = self.readRequest() 51.157 + #print 'handleRequests> msg=', msg 51.158 + if not msg: break 51.159 + self.requestReceived(msg) 51.160 + work += 1 51.161 + #print 'handleRequests<', work 51.162 + return work 51.163 + 51.164 + def requestReceived(self, msg): 51.165 + (ty, subty) = self.getMessageType(msg) 51.166 + #print 'requestReceived>', ty, subty, self 51.167 + #todo: Must respond before writing any more messages. 51.168 + #todo: Should automate this (respond on write) 51.169 + self.port.write_response(msg) 51.170 + dev = self.getDevice(ty) 51.171 + if dev: 51.172 + dev.requestReceived(msg, ty, subty) 51.173 + else: 51.174 + print ("requestReceived> No device: Message type %s %d:%d" 51.175 + % (msgTypeName(ty, subty), ty, subty)), self 51.176 + 51.177 + def handleResponses(self): 51.178 + #print 'handleResponses>', self 51.179 + work = 0 51.180 + while 1: 51.181 + #print 'handleResponses>', work 51.182 + msg = self.readResponse() 51.183 + #print 'handleResponses> msg=', msg 51.184 + if not msg: break 51.185 + self.responseReceived(msg) 51.186 + work += 1 51.187 + #print 'handleResponses<', work 51.188 + return work 51.189 + 51.190 + def responseReceived(self, msg): 51.191 + (ty, subty) = self.getMessageType(msg) 51.192 + #print 'responseReceived>', ty, subty 51.193 + dev = self.getDevice(ty) 51.194 + if dev: 51.195 + dev.responseReceived(msg, ty, subty) 51.196 + else: 51.197 + print ("responseReceived> No device: Message type %d:%d" 51.198 + % (msgTypeName(ty, subty), ty, subty)), self 51.199 + 51.200 + def handleWrites(self): 51.201 + #print 'handleWrites>', self 51.202 + work = 0 51.203 + # Pull data from producers. 51.204 + #print 'handleWrites> pull...' 51.205 + for dev in self.devs: 51.206 + work += dev.produceRequests() 51.207 + # Flush the queue. 51.208 + #print 'handleWrites> flush...' 51.209 + while self.queue and self.port.space_to_write_request(): 51.210 + msg = self.queue.pop(0) 51.211 + self.port.write_request(msg) 51.212 + work += 1 51.213 + #print 'handleWrites<', work 51.214 + return work 51.215 + 51.216 + def writeRequest(self, msg, notify=1): 51.217 + #print 'writeRequest>', self 51.218 + if self.closed: 51.219 + val = -1 51.220 + elif self.writeReady(): 51.221 + self.port.write_request(msg) 51.222 + if notify: self.notify() 51.223 + val = 1 51.224 + else: 51.225 + self.queue.append(msg) 51.226 + val = 0 51.227 + #print 'writeRequest<', val 51.228 + return val 51.229 + 51.230 + def writeResponse(self, msg): 51.231 + #print 'writeResponse>', self 51.232 + if self.closed: return -1 51.233 + self.port.write_response(msg) 51.234 + return 1 51.235 + 51.236 + def writeReady(self): 51.237 + if self.closed or self.queue: return 0 51.238 + return self.port.space_to_write_request() 51.239 + 51.240 + def readRequest(self): 51.241 + #print 'readRequest>', self 51.242 + if self.closed: 51.243 + #print 'readRequest> closed' 51.244 + return None 51.245 + if self.port.request_to_read(): 51.246 + val = self.port.read_request() 51.247 + else: 51.248 + val = None 51.249 + #print 'readRequest< ', val 51.250 + return val 51.251 + 51.252 + def readResponse(self): 51.253 + #print 'readResponse>', self 51.254 + if self.closed: 51.255 + #print 'readResponse> closed' 51.256 + return None 51.257 + if self.port.response_to_read(): 51.258 + val = self.port.read_response() 51.259 + else: 51.260 + val = None 51.261 + #print 'readResponse<', val 51.262 + return val
52.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 52.2 +++ b/tools/xenmgr/lib/server/console.py Fri Jun 11 18:31:12 2004 +0000 52.3 @@ -0,0 +1,220 @@ 52.4 + 52.5 +from twisted.internet import reactor 52.6 +from twisted.internet import protocol 52.7 +from twisted.protocols import telnet 52.8 + 52.9 +import xend.utils 52.10 + 52.11 +from xenmgr import EventServer 52.12 +eserver = EventServer.instance() 52.13 + 52.14 +import controller 52.15 +from messages import * 52.16 +from params import * 52.17 + 52.18 +"""Telnet binary option.""" 52.19 +TRANSMIT_BINARY = '0' 52.20 +WILL = chr(251) 52.21 +IAC = chr(255) 52.22 + 52.23 +class ConsoleProtocol(protocol.Protocol): 52.24 + """Asynchronous handler for a console TCP socket. 52.25 + """ 52.26 + 52.27 + def __init__(self, controller, idx): 52.28 + self.controller = controller 52.29 + self.idx = idx 52.30 + self.addr = None 52.31 + self.binary = 0 52.32 + 52.33 + def connectionMade(self): 52.34 + peer = self.transport.getPeer() 52.35 + self.addr = (peer.host, peer.port) 52.36 + if self.controller.connect(self.addr, self): 52.37 + self.transport.write("Cannot connect to console %d on domain %d\n" 52.38 + % (self.idx, self.controller.dom)) 52.39 + self.loseConnection() 52.40 + return 52.41 + else: 52.42 + self.transport.write("Connected to console %d on domain %d\n" 52.43 + % (self.idx, self.controller.dom)) 52.44 + self.setTelnetTransmitBinary() 52.45 + eserver.inject('xend.console.connect', 52.46 + [self.idx, self.addr[0], self.addr[1]]) 52.47 + 52.48 + def setTelnetTransmitBinary(self): 52.49 + """Send the sequence to set the telnet TRANSMIT-BINARY option. 52.50 + """ 52.51 + self.write(IAC + WILL + TRANSMIT_BINARY) 52.52 + 52.53 + def dataReceived(self, data): 52.54 + if self.controller.handleInput(self, data): 52.55 + self.loseConnection() 52.56 + 52.57 + def write(self, data): 52.58 + #if not self.connected: return -1 52.59 + self.transport.write(data) 52.60 + return len(data) 52.61 + 52.62 + def connectionLost(self, reason=None): 52.63 + eserver.inject('xend.console.disconnect', 52.64 + [self.idx, self.addr[0], self.addr[1]]) 52.65 + self.controller.disconnect() 52.66 + 52.67 + def loseConnection(self): 52.68 + self.transport.loseConnection() 52.69 + 52.70 +class ConsoleFactory(protocol.ServerFactory): 52.71 + """Asynchronous handler for a console server socket. 52.72 + """ 52.73 + protocol = ConsoleProtocol 52.74 + 52.75 + def __init__(self, controller, idx): 52.76 + #protocol.ServerFactory.__init__(self) 52.77 + self.controller = controller 52.78 + self.idx = idx 52.79 + 52.80 + def buildProtocol(self, addr): 52.81 + proto = self.protocol(self.controller, self.idx) 52.82 + proto.factory = self 52.83 + return proto 52.84 + 52.85 +class ConsoleControllerFactory(controller.ControllerFactory): 52.86 + """Factory for creating console controllers. 52.87 + """ 52.88 + 52.89 + def createInstance(self, dom, console_port=None): 52.90 + if console_port is None: 52.91 + console_port = CONSOLE_PORT_BASE + dom 52.92 + console = ConsoleController(self, dom, console_port) 52.93 + self.addInstance(console) 52.94 + eserver.inject('xend.console.create', 52.95 + [console.idx, console.dom, console.console_port]) 52.96 + return console 52.97 + 52.98 + def consoleClosed(self, console): 52.99 + eserver.inject('xend.console.close', console.idx) 52.100 + self.delInstance(console) 52.101 + 52.102 +class ConsoleController(controller.Controller): 52.103 + """Console controller for a domain. 52.104 + Does not poll for i/o itself, but relies on the notifier to post console 52.105 + output and the connected TCP sockets to post console input. 52.106 + """ 52.107 + 52.108 + def __init__(self, factory, dom, console_port): 52.109 + #print 'ConsoleController> dom=', dom 52.110 + controller.Controller.__init__(self, factory, dom) 52.111 + self.majorTypes = [ CMSG_CONSOLE ] 52.112 + self.status = "new" 52.113 + self.addr = None 52.114 + self.conn = None 52.115 + self.rbuf = xend.utils.buffer() 52.116 + self.wbuf = xend.utils.buffer() 52.117 + self.console_port = console_port 52.118 + 52.119 + self.registerChannel() 52.120 + self.listener = None 52.121 + self.listen() 52.122 + #print 'ConsoleController<', 'dom=', self.dom, 'idx=', self.idx 52.123 + 52.124 + def sxpr(self): 52.125 + val =['console', 52.126 + ['id', self.idx ], 52.127 + ['domain', self.dom ], 52.128 + ['local_port', self.channel.getLocalPort() ], 52.129 + ['remote_port', self.channel.getRemotePort() ], 52.130 + ['console_port', self.console_port ] ] 52.131 + if self.addr: 52.132 + val.append(['connected', self.addr[0], self.addr[1]]) 52.133 + return val 52.134 + 52.135 + def ready(self): 52.136 + return not (self.closed() or self.rbuf.empty()) 52.137 + 52.138 + def closed(self): 52.139 + return self.status == 'closed' 52.140 + 52.141 + def connected(self): 52.142 + return self.status == 'connected' 52.143 + 52.144 + def close(self): 52.145 + self.status = "closed" 52.146 + self.listener.stopListening() 52.147 + self.deregisterChannel() 52.148 + self.lostChannel() 52.149 + 52.150 + def listen(self): 52.151 + """Listen for TCP connections to the console port.. 52.152 + """ 52.153 + if self.closed(): return 52.154 + self.status = "listening" 52.155 + if self.listener: 52.156 + #self.listener.startListening() 52.157 + pass 52.158 + else: 52.159 + f = ConsoleFactory(self, self.idx) 52.160 + self.listener = reactor.listenTCP(self.console_port, f) 52.161 + 52.162 + def connect(self, addr, conn): 52.163 + if self.closed(): return -1 52.164 + if self.connected(): return -1 52.165 + self.addr = addr 52.166 + self.conn = conn 52.167 + self.status = "connected" 52.168 + self.handleOutput() 52.169 + return 0 52.170 + 52.171 + def disconnect(self): 52.172 + self.addr = None 52.173 + self.conn = None 52.174 + self.listen() 52.175 + 52.176 + def requestReceived(self, msg, type, subtype): 52.177 + #print '***Console', self.dom, msg.get_payload() 52.178 + self.rbuf.write(msg.get_payload()) 52.179 + self.handleOutput() 52.180 + 52.181 + def responseReceived(self, msg, type, subtype): 52.182 + pass 52.183 + 52.184 + def produceRequests(self): 52.185 + # Send as much pending console data as there is room for. 52.186 + work = 0 52.187 + while not self.wbuf.empty() and self.channel.writeReady(): 52.188 + msg = xend.utils.message(CMSG_CONSOLE, 0, 0) 52.189 + msg.append_payload(self.wbuf.read(msg.MAX_PAYLOAD)) 52.190 + work += self.channel.writeRequest(msg, notify=0) 52.191 + return work 52.192 + 52.193 + def handleInput(self, conn, data): 52.194 + """Handle some external input aimed at the console. 52.195 + Called from a TCP connection (conn). 52.196 + """ 52.197 + if self.closed(): return -1 52.198 + if conn != self.conn: return 0 52.199 + self.wbuf.write(data) 52.200 + if self.produceRequests(): 52.201 + self.channel.notify() 52.202 + return 0 52.203 + 52.204 + def handleOutput(self): 52.205 + """Handle buffered output from the console. 52.206 + Sends it to the connected console (if any). 52.207 + """ 52.208 + if self.closed(): 52.209 + #print 'Console>handleOutput> closed' 52.210 + return -1 52.211 + if not self.conn: 52.212 + #print 'Console>handleOutput> not connected' 52.213 + return 0 52.214 + while not self.rbuf.empty(): 52.215 + try: 52.216 + #print 'Console>handleOutput> writing...' 52.217 + bytes = self.conn.write(self.rbuf.peek()) 52.218 + if bytes > 0: 52.219 + self.rbuf.discard(bytes) 52.220 + except socket.error, error: 52.221 + pass 52.222 + #print 'Console>handleOutput<' 52.223 + return 0
53.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 53.2 +++ b/tools/xenmgr/lib/server/controller.py Fri Jun 11 18:31:12 2004 +0000 53.3 @@ -0,0 +1,133 @@ 53.4 +from twisted.internet import defer 53.5 + 53.6 +import channel 53.7 +from messages import msgTypeName 53.8 + 53.9 +class CtrlMsgRcvr: 53.10 + """Abstract class for things that deal with a control interface to a domain. 53.11 + """ 53.12 + 53.13 + 53.14 + def __init__(self): 53.15 + self.channelFactory = channel.channelFactory() 53.16 + self.majorTypes = [ ] 53.17 + self.subTypes = {} 53.18 + self.dom = None 53.19 + self.channel = None 53.20 + self.idx = None 53.21 + 53.22 + def requestReceived(self, msg, type, subtype): 53.23 + method = self.subTypes.get(subtype) 53.24 + if method: 53.25 + method(msg, 1) 53.26 + else: 53.27 + print ('requestReceived> No handler: Message type %s %d:%d' 53.28 + % (msgTypeName(type, subtype), type, subtype)), self 53.29 + 53.30 + def responseReceived(self, msg, type, subtype): 53.31 + method = self.subTypes.get(subtype) 53.32 + if method: 53.33 + method(msg, 0) 53.34 + else: 53.35 + print ('responseReceived> No handler: Message type %s %d:%d' 53.36 + % (msgTypeName(type, subtype), type, subtype)), self 53.37 + 53.38 + def lostChannel(self): 53.39 + pass 53.40 + 53.41 + def registerChannel(self): 53.42 + self.channel = self.channelFactory.domChannel(self.dom) 53.43 + #print 'registerChannel> channel=', self.channel, self 53.44 + self.idx = self.channel.getIndex() 53.45 + #print 'registerChannel> idx=', self.idx 53.46 + if self.majorTypes: 53.47 + self.channel.registerDevice(self.majorTypes, self) 53.48 + 53.49 + def deregisterChannel(self): 53.50 + if self.channel: 53.51 + self.channel.deregisterDevice(self) 53.52 + del self.channel 53.53 + 53.54 + def produceRequests(self): 53.55 + return 0 53.56 + 53.57 + def writeRequest(self, msg): 53.58 + if self.channel: 53.59 + self.channel.writeRequest(msg) 53.60 + else: 53.61 + print 'CtrlMsgRcvr>writeRequest>', 'no channel!', self 53.62 + 53.63 + def writeResponse(self, msg): 53.64 + if self.channel: 53.65 + self.channel.writeResponse(msg) 53.66 + else: 53.67 + print 'CtrlMsgRcvr>writeResponse>', 'no channel!', self 53.68 + 53.69 +class ControllerFactory(CtrlMsgRcvr): 53.70 + """Abstract class for factories creating controllers. 53.71 + Maintains a table of instances. 53.72 + """ 53.73 + 53.74 + def __init__(self): 53.75 + CtrlMsgRcvr.__init__(self) 53.76 + self.instances = {} 53.77 + self.dlist = [] 53.78 + self.dom = 0 53.79 + 53.80 + def addInstance(self, instance): 53.81 + self.instances[instance.idx] = instance 53.82 + 53.83 + def getInstance(self, idx): 53.84 + return self.instances.get(idx) 53.85 + 53.86 + def getInstances(self): 53.87 + return self.instances.values() 53.88 + 53.89 + def getInstanceByDom(self, dom): 53.90 + for inst in self.instances.values(): 53.91 + if inst.dom == dom: 53.92 + return inst 53.93 + return None 53.94 + 53.95 + def delInstance(self, instance): 53.96 + if instance in self.instances: 53.97 + del self.instances[instance.idx] 53.98 + 53.99 + def createInstance(self, dom): 53.100 + raise NotImplementedError() 53.101 + 53.102 + def instanceClosed(self, instance): 53.103 + self.delInstance(instance) 53.104 + 53.105 + def addDeferred(self): 53.106 + d = defer.Deferred() 53.107 + self.dlist.append(d) 53.108 + return d 53.109 + 53.110 + def callDeferred(self, *args): 53.111 + if self.dlist: 53.112 + d = self.dlist.pop(0) 53.113 + d.callback(*args) 53.114 + 53.115 + def errDeferred(self, *args): 53.116 + if self.dlist: 53.117 + d = self.dlist.pop(0) 53.118 + d.errback(*args) 53.119 + 53.120 +class Controller(CtrlMsgRcvr): 53.121 + """Abstract class for a device controller attached to a domain. 53.122 + """ 53.123 + 53.124 + def __init__(self, factory, dom): 53.125 + CtrlMsgRcvr.__init__(self) 53.126 + self.factory = factory 53.127 + self.dom = dom 53.128 + self.channel = None 53.129 + self.idx = None 53.130 + 53.131 + def close(self): 53.132 + self.deregisterChannel() 53.133 + self.lostChannel(self) 53.134 + 53.135 + def lostChannel(self): 53.136 + self.factory.instanceClosed(self)
54.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 54.2 +++ b/tools/xenmgr/lib/server/cstruct.py Fri Jun 11 18:31:12 2004 +0000 54.3 @@ -0,0 +1,269 @@ 54.4 +import struct 54.5 + 54.6 +class Struct: 54.7 + 54.8 + maxDepth = 10 54.9 + 54.10 + base = ['x', 'B', 'H', 'I', 'L', 'Q', 'c', 'h', 'i', 'l', 'q', ] 54.11 + 54.12 + sizes = {'B': 1, 54.13 + 'H': 2, 54.14 + 'I': 4, 54.15 + 'L': 4, 54.16 + 'Q': 8, 54.17 + 'c': 1, 54.18 + 'h': 2, 54.19 + 'i': 4, 54.20 + 'l': 4, 54.21 + 'q': 8, 54.22 + 'x': 1, 54.23 + } 54.24 + 54.25 + formats = { 54.26 + 'int8' : 'B', 54.27 + 'int16' : 'H', 54.28 + 'int32' : 'I', 54.29 + 'int64' : 'Q', 54.30 + 'u8' : 'B', 54.31 + 'u16' : 'H', 54.32 + 'u32' : 'I', 54.33 + 'u64' : 'Q' 54.34 + } 54.35 + 54.36 + def typedef(self, name, val): 54.37 + self.formats[name] = val 54.38 + 54.39 + def struct(self, name, *f): 54.40 + self.typedef(name, StructInfo(self, f)) 54.41 + 54.42 + def getType(self, name): 54.43 + return self.formats[name] 54.44 + 54.45 + def format(self, ty): 54.46 + d = 0 54.47 + f = ty 54.48 + while d < self.maxDepth: 54.49 + d += 1 54.50 + f = self.formats[f] 54.51 + if isinstance(f, StructInfo): 54.52 + return f.format() 54.53 + if f in self.base: 54.54 + return f 54.55 + return -1 54.56 + 54.57 + def alignedformat(self, ty): 54.58 + fmt = self.format(ty) 54.59 + #print 'alignedformat> %s |%s|' %(ty, fmt) 54.60 + afmt = self.align(fmt) 54.61 + #print 'alignedformat< %s |%s| |%s|' % (ty, fmt, afmt) 54.62 + return afmt 54.63 + 54.64 + def align(self, fmt): 54.65 + n1 = 0 54.66 + afmt = '' 54.67 + for a in fmt: 54.68 + n2 = self.getSize(a) 54.69 + m = n1 % n2 54.70 + if m: 54.71 + d = (n2 - m) 54.72 + afmt += 'x' * d 54.73 + n1 += d 54.74 + afmt += a 54.75 + n1 += n2 54.76 + return afmt 54.77 + 54.78 + def fmtsize(self, fmt): 54.79 + s = 0 54.80 + for f in fmt: 54.81 + s += self.getSize(f) 54.82 + return s 54.83 + 54.84 + def getSize(self, f): 54.85 + return self.sizes[f] 54.86 + 54.87 + def pack(self, ty, data): 54.88 + return self.getType(ty).pack(data) 54.89 + 54.90 + def unpack(self, ty, data): 54.91 + return self.getType(ty).unpack(data) 54.92 + 54.93 + def show(self): 54.94 + l = self.formats.keys() 54.95 + l.sort() 54.96 + for v in l: 54.97 + print "%-35s %-10s %s" % (v, self.format(v), self.alignedformat(v)) 54.98 + 54.99 + 54.100 +class StructInfo: 54.101 + 54.102 + def __init__(self, s, f): 54.103 + self.fmt = None 54.104 + self.structs = s 54.105 + self.fields = f 54.106 + 54.107 + def alignedformat(self): 54.108 + if self.afmt: return self.afmt 54.109 + self.afmt = self.structs.align(self.format()) 54.110 + return self.afmt 54.111 + 54.112 + def format(self): 54.113 + if self.fmt: return self.fmt 54.114 + fmt = "" 54.115 + for (ty, name) in self.fields: 54.116 + fmt += self.formatString(ty) 54.117 + self.fmt = fmt 54.118 + return fmt 54.119 + 54.120 + def formatString(self, ty): 54.121 + if ty in self.fields: 54.122 + ty = self.fields[ty] 54.123 + return self.structs.format(ty) 54.124 + 54.125 + def pack(self, *args): 54.126 + return struct.pack(self.alignedformat(), *args) 54.127 + 54.128 + def unpack(self, data): 54.129 + return struct.unpack(self.alignedformat(), data) 54.130 + 54.131 +types = Struct() 54.132 + 54.133 +types.typedef('short' , 'h') 54.134 +types.typedef('int' , 'i') 54.135 +types.typedef('long' , 'l') 54.136 +types.typedef('unsigned short', 'H') 54.137 +types.typedef('unsigned int' , 'I') 54.138 +types.typedef('unsigned long' , 'L') 54.139 +types.typedef('domid_t' , 'u64') 54.140 +types.typedef('blkif_vdev_t' , 'u16') 54.141 +types.typedef('blkif_pdev_t' , 'u16') 54.142 +types.typedef('blkif_sector_t', 'u64') 54.143 + 54.144 +types.struct('u8[6]', 54.145 + ('u8', 'a1'), 54.146 + ('u8', 'a2'), 54.147 + ('u8', 'a3'), 54.148 + ('u8', 'a4'), 54.149 + ('u8', 'a5'), 54.150 + ('u8', 'a6')) 54.151 + 54.152 +types.struct('blkif_fe_interface_status_changed_t', 54.153 + ('unsigned int', 'handle'), 54.154 + ('unsigned int', 'status'), 54.155 + ('unsigned int', 'evtchn')) 54.156 + 54.157 +types.struct('blkif_fe_driver_status_changed_t', 54.158 + ('unsigned int', 'status'), 54.159 + ('unsigned int', 'nr_interfaces')) 54.160 + 54.161 +types.struct('blkif_fe_interface_connect_t', 54.162 + ('unsigned int' , 'handle'), 54.163 + ('unsigned long', 'shmem_frame')) 54.164 + 54.165 +types.struct('blkif_fe_interface_disconnect_t', 54.166 + ('unsigned int', 'handle')) 54.167 + 54.168 +types.struct('blkif_extent_t', 54.169 + ('blkif_pdev_t' , 'device'), 54.170 + ('blkif_sector_t', 'sector_start'), 54.171 + ('blkif_sector_t', 'sector_length')) 54.172 + 54.173 +types.struct('blkif_be_create_t', 54.174 + ('domid_t' , 'domid'), 54.175 + ('unsigned int', 'blkif_handle'), 54.176 + ('unsigned int', 'status')) 54.177 + 54.178 +types.struct('blkif_be_destroy_t', 54.179 + ('domid_t' , 'domid'), 54.180 + ('unsigned int', 'blkif_handle'), 54.181 + ('unsigned int', 'status')) 54.182 + 54.183 +types.struct('blkif_be_connect_t', 54.184 + ('domid_t' , 'domid'), 54.185 + ('unsigned int' , 'blkif_handle'), 54.186 + ('unsigned int' , 'evtchn'), 54.187 + ('unsigned long', 'shmem_frame'), 54.188 + ('unsigned int' , 'status')) 54.189 + 54.190 +types.struct('blkif_be_disconnect_t', 54.191 + ('domid_t' , 'domid'), 54.192 + ('unsigned int', 'blkif_handle'), 54.193 + ('unsigned int', 'status')) 54.194 + 54.195 +types.struct('blkif_be_vbd_create_t', 54.196 + ('domid_t' , 'domid'), #Q 54.197 + ('unsigned int', 'blkif_handle'), #I 54.198 + ('blkif_vdev_t', 'vdevice'), #H 54.199 + ('int' , 'readonly'), #i 54.200 + ('unsigned int', 'status')) #I 54.201 + 54.202 +types.struct('blkif_be_vbd_destroy_t', 54.203 + ('domid_t' , 'domid'), 54.204 + ('unsigned int', 'blkif_handle'), 54.205 + ('blkif_vdev_t', 'vdevice'), 54.206 + ('unsigned int', 'status')) 54.207 + 54.208 +types.struct('blkif_be_vbd_grow_t', 54.209 + ('domid_t' , 'domid'), #Q 54.210 + ('unsigned int' , 'blkif_handle'), #I 54.211 + ('blkif_vdev_t' , 'vdevice'), #H 54.212 + ('blkif_extent_t', 'extent'), #HQQ 54.213 + ('unsigned int' , 'status')) #I 54.214 + 54.215 +types.struct('blkif_be_vbd_shrink_t', 54.216 + ('domid_t' , 'domid'), 54.217 + ('unsigned int', 'blkif_handle'), 54.218 + ('blkif_vdev_t', 'vdevice'), 54.219 + ('unsigned int', 'status')) 54.220 + 54.221 +types.struct('blkif_be_driver_status_changed_t', 54.222 + ('unsigned int', 'status'), 54.223 + ('unsigned int', 'nr_interfaces')) 54.224 + 54.225 +types.struct('netif_fe_interface_status_changed_t', 54.226 + ('unsigned int', 'handle'), 54.227 + ('unsigned int', 'status'), 54.228 + ('unsigned int', 'evtchn'), 54.229 + ('u8[6]', 'mac')) 54.230 + 54.231 +types.struct('netif_fe_driver_status_changed_t', 54.232 + ('unsigned int', 'status'), 54.233 + ('unsigned int', 'nr_interfaces')) 54.234 + 54.235 +types.struct('netif_fe_interface_connect_t', 54.236 + ('unsigned int', 'handle'), 54.237 + ('unsigned long', 'tx_shmem_frame'), 54.238 + ('unsigned long', 'rx_shmem_frame')) 54.239 + 54.240 +types.struct('netif_fe_interface_disconnect_t', 54.241 + ('unsigned int', 'handle')) 54.242 + 54.243 +types.struct('netif_be_create_t', 54.244 + ('domid_t' , 'domid'), 54.245 + ('unsigned int', 'netif_handle'), 54.246 + ('u8[6]' , 'mac'), 54.247 + ('unsigned int', 'status')) 54.248 + 54.249 +types.struct('netif_be_destroy_t', 54.250 + ('domid_t' , 'domid'), 54.251 + ('unsigned int', 'netif_handle'), 54.252 + ('unsigned int', 'status')) 54.253 + 54.254 +types.struct('netif_be_connect_t', 54.255 + ('domid_t' , 'domid'), 54.256 + ('unsigned int' , 'netif_handle'), 54.257 + ('unsigned int' , 'evtchn'), 54.258 + ('unsigned long', 'tx_shmem_frame'), 54.259 + ('unsigned long', 'rx_shmem_frame'), 54.260 + ('unsigned int' , 'status')) 54.261 + 54.262 +types.struct('netif_be_disconnect_t', 54.263 + ('domid_t' , 'domid'), 54.264 + ('unsigned int', 'netif_handle'), 54.265 + ('unsigned int', 'status')) 54.266 + 54.267 +types.struct('netif_be_driver_status_changed_t', 54.268 + ('unsigned int', 'status'), 54.269 + ('unsigned int', 'nr_interfaces')) 54.270 + 54.271 +if 1 or __name__ == "__main__": 54.272 + types.show()
55.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 55.2 +++ b/tools/xenmgr/lib/server/messages.py Fri Jun 11 18:31:12 2004 +0000 55.3 @@ -0,0 +1,186 @@ 55.4 +import struct 55.5 + 55.6 +import xend.utils 55.7 + 55.8 +""" All message formats. 55.9 +Added to incrementally for the various message types. 55.10 +See below. 55.11 +""" 55.12 +msg_formats = {} 55.13 + 55.14 +#============================================================================ 55.15 +# Console message types. 55.16 +#============================================================================ 55.17 + 55.18 +CMSG_CONSOLE = 0 55.19 + 55.20 +console_formats = { 'console_data': (CMSG_CONSOLE, 0, "?") } 55.21 + 55.22 +msg_formats.update(console_formats) 55.23 + 55.24 +#============================================================================ 55.25 +# Block interface message types. 55.26 +#============================================================================ 55.27 + 55.28 +CMSG_BLKIF_BE = 1 55.29 +CMSG_BLKIF_FE = 2 55.30 + 55.31 +CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED = 0 55.32 +CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED = 32 55.33 +CMSG_BLKIF_FE_INTERFACE_CONNECT = 33 55.34 +CMSG_BLKIF_FE_INTERFACE_DISCONNECT = 34 55.35 + 55.36 +CMSG_BLKIF_BE_CREATE = 0 55.37 +CMSG_BLKIF_BE_DESTROY = 1 55.38 +CMSG_BLKIF_BE_CONNECT = 2 55.39 +CMSG_BLKIF_BE_DISCONNECT = 3 55.40 +CMSG_BLKIF_BE_VBD_CREATE = 4 55.41 +CMSG_BLKIF_BE_VBD_DESTROY = 5 55.42 +CMSG_BLKIF_BE_VBD_GROW = 6 55.43 +CMSG_BLKIF_BE_VBD_SHRINK = 7 55.44 +CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED = 32 55.45 + 55.46 +BLKIF_DRIVER_STATUS_DOWN = 0 55.47 +BLKIF_DRIVER_STATUS_UP = 1 55.48 + 55.49 +BLKIF_INTERFACE_STATUS_DESTROYED = 0 #/* Interface doesn't exist. */ 55.50 +BLKIF_INTERFACE_STATUS_DISCONNECTED = 1 #/* Exists but is disconnected. */ 55.51 +BLKIF_INTERFACE_STATUS_CONNECTED = 2 #/* Exists and is connected. */ 55.52 + 55.53 +BLKIF_BE_STATUS_OKAY = 0 55.54 +BLKIF_BE_STATUS_ERROR = 1 55.55 +BLKIF_BE_STATUS_INTERFACE_EXISTS = 2 55.56 +BLKIF_BE_STATUS_INTERFACE_NOT_FOUND = 3 55.57 +BLKIF_BE_STATUS_INTERFACE_CONNECTED = 4 55.58 +BLKIF_BE_STATUS_VBD_EXISTS = 5 55.59 +BLKIF_BE_STATUS_VBD_NOT_FOUND = 6 55.60 +BLKIF_BE_STATUS_OUT_OF_MEMORY = 7 55.61 +BLKIF_BE_STATUS_EXTENT_NOT_FOUND = 8 55.62 +BLKIF_BE_STATUS_MAPPING_ERROR = 9 55.63 + 55.64 +blkif_formats = { 55.65 + 'blkif_be_connect_t': 55.66 + (CMSG_BLKIF_BE, CMSG_BLKIF_BE_CONNECT, "QIILI"), 55.67 + 55.68 + 'blkif_be_create_t': 55.69 + (CMSG_BLKIF_BE, CMSG_BLKIF_BE_CREATE, "QII"), 55.70 + 55.71 + 'blkif_be_destroy_t': 55.72 + (CMSG_BLKIF_BE, CMSG_BLKIF_BE_DESTROY, "QII"), 55.73 + 55.74 + 'blkif_be_vbd_create_t': 55.75 + (CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_CREATE, "QIHII"), 55.76 + 55.77 + 'blkif_be_vbd_grow_t': 55.78 + (CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_GROW , "QIHHHQQI"), 55.79 + 55.80 + 'blkif_fe_interface_status_changed_t': 55.81 + (CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED, "III"), 55.82 + 55.83 + 'blkif_fe_driver_status_changed_t': 55.84 + (CMSG_BLKIF_FE, CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED, "?"), 55.85 + 55.86 + 'blkif_fe_interface_connect_t': 55.87 + (CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_CONNECT, "IL"), 55.88 +} 55.89 + 55.90 +msg_formats.update(blkif_formats) 55.91 + 55.92 +#============================================================================ 55.93 +# Network interface message types. 55.94 +#============================================================================ 55.95 + 55.96 +CMSG_NETIF_BE = 3 55.97 +CMSG_NETIF_FE = 4 55.98 + 55.99 +CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED = 0 55.100 +CMSG_NETIF_FE_DRIVER_STATUS_CHANGED = 32 55.101 +CMSG_NETIF_FE_INTERFACE_CONNECT = 33 55.102 +CMSG_NETIF_FE_INTERFACE_DISCONNECT = 34 55.103 + 55.104 +CMSG_NETIF_BE_CREATE = 0 55.105 +CMSG_NETIF_BE_DESTROY = 1 55.106 +CMSG_NETIF_BE_CONNECT = 2 55.107 +CMSG_NETIF_BE_DISCONNECT = 3 55.108 +CMSG_NETIF_BE_DRIVER_STATUS_CHANGED = 32 55.109 + 55.110 +NETIF_INTERFACE_STATUS_DESTROYED = 0 #/* Interface doesn't exist. */ 55.111 +NETIF_INTERFACE_STATUS_DISCONNECTED = 1 #/* Exists but is disconnected. */ 55.112 +NETIF_INTERFACE_STATUS_CONNECTED = 2 #/* Exists and is connected. */ 55.113 + 55.114 +NETIF_DRIVER_STATUS_DOWN = 0 55.115 +NETIF_DRIVER_STATUS_UP = 1 55.116 + 55.117 +netif_formats = { 55.118 + 'netif_be_connect_t': 55.119 + (CMSG_NETIF_BE, CMSG_NETIF_BE_CONNECT, "QIILLI"), 55.120 + 55.121 + 'netif_be_create_t': 55.122 + (CMSG_NETIF_BE, CMSG_NETIF_BE_CREATE, "QIBBBBBBBBI"), 55.123 + 55.124 + 'netif_be_destroy_t': 55.125 + (CMSG_NETIF_BE, CMSG_NETIF_BE_DESTROY, "QII"), 55.126 + 55.127 + 'netif_be_disconnect_t': 55.128 + (CMSG_NETIF_BE, CMSG_NETIF_BE_DISCONNECT, "QII"), 55.129 + 55.130 + 'netif_be_driver_status_changed_t': 55.131 + (CMSG_NETIF_BE, CMSG_NETIF_BE_DRIVER_STATUS_CHANGED, "QII"), 55.132 + 55.133 + 'netif_fe_driver_status_changed_t': 55.134 + (CMSG_NETIF_FE, CMSG_NETIF_FE_DRIVER_STATUS_CHANGED, "II"), 55.135 + 55.136 + 'netif_fe_interface_connect_t': 55.137 + (CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_CONNECT, "ILL"), 55.138 + 55.139 + 'netif_fe_interface_status_changed_t': 55.140 + (CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED, "IIIBBBBBBBB"), 55.141 + } 55.142 + 55.143 +msg_formats.update(netif_formats) 55.144 + 55.145 +#============================================================================ 55.146 + 55.147 +class Msg: 55.148 + pass 55.149 + 55.150 +def packMsg(ty, params): 55.151 + print '>packMsg', ty, params 55.152 + (major, minor, packing) = msg_formats[ty] 55.153 + args = {} 55.154 + for (k, v) in params.items(): 55.155 + if k == 'mac': 55.156 + for i in range(0, 6): 55.157 + args['mac[%d]' % i] = v[i] 55.158 + else: 55.159 + args[k] = v 55.160 + for (k, v) in args.items(): 55.161 + print 'packMsg>', k, v, type(v) 55.162 + msgid = 0 55.163 + msg = xend.utils.message(major, minor, msgid, args) 55.164 + return msg 55.165 + 55.166 +def unpackMsg(ty, msg): 55.167 + args = msg.get_payload() 55.168 + mac = [0, 0, 0, 0, 0, 0] 55.169 + macs = [] 55.170 + for (k, v) in args.items(): 55.171 + if k.startswith('mac['): 55.172 + macs += k 55.173 + i = int(k[4:5]) 55.174 + mac[i] = v 55.175 + else: 55.176 + pass 55.177 + if macs: 55.178 + args['mac'] = mac 55.179 + for k in macs: 55.180 + del args[k] 55.181 + print '<unpackMsg', ty, args 55.182 + return args 55.183 + 55.184 +def msgTypeName(ty, subty): 55.185 + for (name, info) in msg_formats.items(): 55.186 + if info[0] == ty and info[1] == subty: 55.187 + return name 55.188 + return None 55.189 +
56.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 56.2 +++ b/tools/xenmgr/lib/server/netif.py Fri Jun 11 18:31:12 2004 +0000 56.3 @@ -0,0 +1,205 @@ 56.4 +import random 56.5 + 56.6 +import channel 56.7 +import controller 56.8 +from messages import * 56.9 + 56.10 +class NetifControllerFactory(controller.ControllerFactory): 56.11 + """Factory for creating network interface controllers. 56.12 + Also handles the 'back-end' channel to dom0. 56.13 + """ 56.14 + # todo: add support for setting dom controlling blkifs (don't assume 0). 56.15 + # todo: add support for 'recovery'. 56.16 + 56.17 + def __init__(self): 56.18 + controller.ControllerFactory.__init__(self) 56.19 + 56.20 + self.majorTypes = [ CMSG_NETIF_BE ] 56.21 + 56.22 + self.subTypes = { 56.23 + CMSG_NETIF_BE_CREATE : self.recv_be_create, 56.24 + CMSG_NETIF_BE_CONNECT: self.recv_be_connect, 56.25 + CMSG_NETIF_BE_DRIVER_STATUS_CHANGED: self.recv_be_driver_status_changed, 56.26 + } 56.27 + self.attached = 1 56.28 + self.registerChannel() 56.29 + 56.30 + def createInstance(self, dom): 56.31 + #print 'netif>createInstance> dom=', dom 56.32 + netif = self.getInstanceByDom(dom) 56.33 + if netif is None: 56.34 + netif = NetifController(self, dom) 56.35 + self.addInstance(netif) 56.36 + return netif 56.37 + 56.38 + def setControlDomain(self, dom): 56.39 + self.deregisterChannel() 56.40 + self.attached = 0 56.41 + self.dom = dom 56.42 + self.registerChannel() 56.43 + # 56.44 + #if xend.netif.be_port.remote_dom != 0: 56.45 + # xend.netif.recovery = True 56.46 + # xend.netif.be_port = xend.main.port_from_dom(dom) 56.47 + # 56.48 + pass 56.49 + 56.50 + def recv_be_create(self, msg, req): 56.51 + self.callDeferred(0) 56.52 + 56.53 + def recv_be_connect(self, msg, req): 56.54 + val = unpackMsg('netif_be_connect_t', msg) 56.55 + dom = val['domid'] 56.56 + vif = val['netif_handle'] 56.57 + netif = self.getInstanceByDom(dom) 56.58 + if netif: 56.59 + netif.send_interface_connected(vif) 56.60 + else: 56.61 + print "recv_be_connect> unknown vif=", vif 56.62 + pass 56.63 + 56.64 + def recv_be_driver_status_changed(self, msg, req): 56.65 + val = unpackMsg('netif_be_driver_status_changed_t', msg) 56.66 + status = val['status'] 56.67 + if status == NETIF_DRIVER_STATUS_UP and not self.attached: 56.68 + for netif in self.getInstances(): 56.69 + netif.reattach_devices() 56.70 + self.attached = 1 56.71 + 56.72 +## pl = msg.get_payload() 56.73 +## status = pl['status'] 56.74 +## if status == NETIF_DRIVER_STATUS_UP: 56.75 +## if xend.netif.recovery: 56.76 +## print "New netif backend now UP, notifying guests:" 56.77 +## for netif_key in interface.list.keys(): 56.78 +## netif = interface.list[netif_key] 56.79 +## netif.create() 56.80 +## print " Notifying %d" % netif.dom 56.81 +## msg = xend.utils.message( 56.82 +## CMSG_NETIF_FE, 56.83 +## CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED, 0, 56.84 +## { 'handle' : 0, 'status' : 1 }) 56.85 +## netif.ctrlif_tx_req(xend.main.port_from_dom(netif.dom),msg) 56.86 +## print "Done notifying guests" 56.87 +## recovery = False 56.88 + 56.89 +class NetDev: 56.90 + """Info record for a network device. 56.91 + """ 56.92 + 56.93 + def __init__(self, vif, mac): 56.94 + self.vif = vif 56.95 + self.mac = mac 56.96 + self.evtchn = None 56.97 + 56.98 +class NetifController(controller.Controller): 56.99 + """Network interface controller. Handles all network devices for a domain. 56.100 + """ 56.101 + 56.102 + def __init__(self, factory, dom): 56.103 + #print 'NetifController> dom=', dom 56.104 + controller.Controller.__init__(self, factory, dom) 56.105 + self.devices = {} 56.106 + 56.107 + self.majorTypes = [ CMSG_NETIF_FE ] 56.108 + 56.109 + self.subTypes = { 56.110 + CMSG_NETIF_FE_DRIVER_STATUS_CHANGED: 56.111 + self.recv_fe_driver_status_changed, 56.112 + CMSG_NETIF_FE_INTERFACE_CONNECT : 56.113 + self.recv_fe_interface_connect, 56.114 + } 56.115 + self.registerChannel() 56.116 + #print 'NetifController<', 'dom=', self.dom, 'idx=', self.idx 56.117 + 56.118 + 56.119 + def randomMAC(self): 56.120 + # VIFs get a random MAC address with a "special" vendor id. 56.121 + # 56.122 + # NB. The vendor is currently an "obsolete" one that used to belong 56.123 + # to DEC (AA-00-00). Using it is probably a bit rude :-) 56.124 + # 56.125 + # NB2. The first bit of the first random octet is set to zero for 56.126 + # all dynamic MAC addresses. This may allow us to manually specify 56.127 + # MAC addresses for some VIFs with no fear of clashes. 56.128 + mac = [ 0xaa, 0x00, 0x00, 56.129 + random.randint(0x00, 0x7f), 56.130 + random.randint(0x00, 0xff), 56.131 + random.randint(0x00, 0xff) ] 56.132 + return mac 56.133 + 56.134 + def attach_device(self, vif, vmac): 56.135 + if vmac is None: 56.136 + mac = self.randomMAC() 56.137 + else: 56.138 + mac = [ int(x, 16) for x in vmac.split(':') ] 56.139 + if len(mac) != 6: raise ValueError("invalid mac") 56.140 + #print "attach_device>", "vif=", vif, "mac=", mac 56.141 + self.devices[vif] = NetDev(vif, mac) 56.142 + d = self.factory.addDeferred() 56.143 + self.send_be_create(vif) 56.144 + return d 56.145 + 56.146 + def reattach_devices(self): 56.147 + d = self.factory.addDeferred() 56.148 + self.send_be_create(vif) 56.149 + self.attach_fe_devices(0) 56.150 + 56.151 + def attach_fe_devices(self): 56.152 + for dev in self.devices.values(): 56.153 + msg = packMsg('netif_fe_interface_status_changed_t', 56.154 + { 'handle' : dev.vif, 56.155 + 'status' : NETIF_INTERFACE_STATUS_DISCONNECTED, 56.156 + 'evtchn' : 0, 56.157 + 'mac' : dev.mac }) 56.158 + self.writeRequest(msg) 56.159 + 56.160 + def recv_fe_driver_status_changed(self, msg, req): 56.161 + if not req: return 56.162 + msg = packMsg('netif_fe_driver_status_changed_t', 56.163 + { 'status' : NETIF_DRIVER_STATUS_UP, 56.164 + 'nr_interfaces' : len(self.devices) }) 56.165 + self.writeRequest(msg) 56.166 + self.attach_fe_devices() 56.167 + 56.168 + def recv_fe_interface_connect(self, msg, req): 56.169 + val = unpackMsg('netif_fe_interface_connect_t', msg) 56.170 + dev = self.devices[val['handle']] 56.171 + dev.evtchn = channel.eventChannel(0, self.dom) 56.172 + msg = packMsg('netif_be_connect_t', 56.173 + { 'domid' : self.dom, 56.174 + 'netif_handle' : dev.vif, 56.175 + 'evtchn' : dev.evtchn['port1'], 56.176 + 'tx_shmem_frame' : val['tx_shmem_frame'], 56.177 + 'rx_shmem_frame' : val['rx_shmem_frame'] }) 56.178 + self.factory.writeRequest(msg) 56.179 + 56.180 + #def recv_fe_interface_status_changed(self): 56.181 + # print 'recv_fe_interface_status_changed>' 56.182 + # pass 56.183 + 56.184 + def send_interface_connected(self, vif): 56.185 + dev = self.devices[vif] 56.186 + msg = packMsg('netif_fe_interface_status_changed_t', 56.187 + { 'handle' : dev.vif, 56.188 + 'status' : NETIF_INTERFACE_STATUS_CONNECTED, 56.189 + 'evtchn' : dev.evtchn['port2'], 56.190 + 'mac' : dev.mac }) 56.191 + self.writeRequest(msg) 56.192 + 56.193 + def send_be_create(self, vif): 56.194 + dev = self.devices[vif] 56.195 + msg = packMsg('netif_be_create_t', 56.196 + { 'domid' : self.dom, 56.197 + 'netif_handle' : dev.vif, 56.198 + 'mac' : dev.mac }) 56.199 + self.factory.writeRequest(msg) 56.200 + 56.201 + def send_be_destroy(self, vif): 56.202 + print 'send_be_destroy>', 'dom=', self.dom, 'vif=', vif 56.203 + dev = self.devices[vif] 56.204 + del self.devices[vif] 56.205 + msg = packMsg('netif_be_destroy_t', 56.206 + { 'domid' : self.dom, 56.207 + 'netif_handle' : vif }) 56.208 + self.factory.writeRequest(msg)
57.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 57.2 +++ b/tools/xenmgr/lib/server/params.py Fri Jun 11 18:31:12 2004 +0000 57.3 @@ -0,0 +1,10 @@ 57.4 +# The following parameters could be placed in a configuration file. 57.5 +PID_FILE = '/var/run/xend.pid' 57.6 +LOG_FILE = '/var/log/xend.log' 57.7 +USER = 'root' 57.8 +CONTROL_DIR = '/var/run/xend' 57.9 +MGMT_SOCK = 'xenmgrsock' # relative to CONTROL_DIR 57.10 +EVENT_PORT = 8001 57.11 + 57.12 +CONSOLE_PORT_BASE = 9600 57.13 +
58.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 58.2 +++ b/tools/xenmgr/lib/sxp.py Fri Jun 11 18:31:12 2004 +0000 58.3 @@ -0,0 +1,557 @@ 58.4 +#!/usr/bin/python2 58.5 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com> 58.6 +""" 58.7 +Input-driven parsing for s-expression (sxp) format. 58.8 +Create a parser: pin = Parser(); 58.9 +Then call pin.input(buf) with your input. 58.10 +Call pin.input_eof() when done. 58.11 +Use pin.read() to see if a value has been parsed, pin.get_val() 58.12 +to get a parsed value. You can call ready and get_val at any time - 58.13 +you don't have to wait until after calling input_eof. 58.14 + 58.15 +""" 58.16 +from __future__ import generators 58.17 + 58.18 +import sys 58.19 +import types 58.20 +import errno 58.21 +import string 58.22 + 58.23 +__all__ = [ 58.24 + "mime_type", 58.25 + "ParseError", 58.26 + "Parser", 58.27 + "atomp", 58.28 + "show", 58.29 + "show_xml", 58.30 + "elementp", 58.31 + "name", 58.32 + "attributes", 58.33 + "attribute", 58.34 + "children", 58.35 + "child", 58.36 + "child_at", 58.37 + "child0", 58.38 + "child1", 58.39 + "child2", 58.40 + "child3", 58.41 + "child4", 58.42 + "child_value", 58.43 + "has_id", 58.44 + "with_id", 58.45 + "child_with_id", 58.46 + "elements", 58.47 + "parse", 58.48 + ] 58.49 + 58.50 +mime_type = "application/sxp" 58.51 + 58.52 +escapes = { 58.53 + 'a': '\a', 58.54 + 'b': '\b', 58.55 + 't': '\t', 58.56 + 'n': '\n', 58.57 + 'v': '\v', 58.58 + 'f': '\f', 58.59 + 'r': '\r', 58.60 + '\\': '\\', 58.61 + '\'': '\'', 58.62 + '\"': '\"'} 58.63 + 58.64 +k_list_open = "(" 58.65 +k_list_close = ")" 58.66 +k_attr_open = "@" 58.67 +k_eval = "!" 58.68 + 58.69 +escapes_rev = {} 58.70 +for k in escapes: 58.71 + escapes_rev[escapes[k]] = k 58.72 + 58.73 +class ParseError(StandardError): 58.74 + 58.75 + def __init__(self, parser, value): 58.76 + self.parser = parser 58.77 + self.value = value 58.78 + 58.79 + def __str__(self): 58.80 + return self.value 58.81 + 58.82 +class ParserState: 58.83 + 58.84 + def __init__(self, fn, parent=None): 58.85 + self.parent = parent 58.86 + self.buf = '' 58.87 + self.val = [] 58.88 + self.delim = None 58.89 + self.fn = fn 58.90 + 58.91 + def push(self, fn): 58.92 + return ParserState(fn, parent=self) 58.93 + 58.94 +class Parser: 58.95 + 58.96 + def __init__(self): 58.97 + self.error = sys.stderr 58.98 + self.reset() 58.99 + 58.100 + def reset(self): 58.101 + self.val = [] 58.102 + self.eof = 0 58.103 + self.err = 0 58.104 + self.line_no = 0 58.105 + self.char_no = 0 58.106 + self.state = None 58.107 + 58.108 + def push_state(self, fn): 58.109 + self.state = self.state.push(fn) 58.110 + 58.111 + def pop_state(self): 58.112 + val = self.state 58.113 + self.state = self.state.parent 58.114 + if self.state and self.state.fn == self.state_start: 58.115 + # Return to start state - produce the value. 58.116 + self.val += self.state.val 58.117 + self.state.val = [] 58.118 + return val 58.119 + 58.120 + def in_class(self, c, s): 58.121 + return s.find(c) >= 0 58.122 + 58.123 + def in_space_class(self, c): 58.124 + return self.in_class(c, ' \t\n\v\f\r') 58.125 + 58.126 + def is_separator(self, c): 58.127 + return self.in_class(c, '{}()<>[]!;') 58.128 + 58.129 + def in_comment_class(self, c): 58.130 + return self.in_class(c, '#') 58.131 + 58.132 + def in_string_quote_class(self, c): 58.133 + return self.in_class(c, '"\'') 58.134 + 58.135 + def in_printable_class(self, c): 58.136 + return self.in_class(c, string.printable) 58.137 + 58.138 + def set_error_stream(self, error): 58.139 + self.error = error 58.140 + 58.141 + def has_error(self): 58.142 + return self.err > 0 58.143 + 58.144 + def at_eof(self): 58.145 + return self.eof 58.146 + 58.147 + def input_eof(self): 58.148 + self.eof = 1 58.149 + self.input_char(-1) 58.150 + 58.151 + def input(self, buf): 58.152 + if not buf or len(buf) == 0: 58.153 + self.input_eof() 58.154 + else: 58.155 + for c in buf: 58.156 + self.input_char(c) 58.157 + 58.158 + def input_char(self, c): 58.159 + if self.at_eof(): 58.160 + pass 58.161 + elif c == '\n': 58.162 + self.line_no += 1 58.163 + self.char_no = 0 58.164 + else: 58.165 + self.char_no += 1 58.166 + 58.167 + if self.state is None: 58.168 + self.begin_start(None) 58.169 + self.state.fn(c) 58.170 + 58.171 + def ready(self): 58.172 + return len(self.val) > 0 58.173 + 58.174 + def get_val(self): 58.175 + v = self.val[0] 58.176 + self.val = self.val[1:] 58.177 + return v 58.178 + 58.179 + def get_all(self): 58.180 + return self.val 58.181 + 58.182 + def begin_start(self, c): 58.183 + self.state = ParserState(self.state_start) 58.184 + 58.185 + def end_start(self): 58.186 + self.val += self.state.val 58.187 + self.pop_state() 58.188 + 58.189 + def state_start(self, c): 58.190 + if self.at_eof(): 58.191 + self.end_start() 58.192 + elif self.in_space_class(c): 58.193 + pass 58.194 + elif self.in_comment_class(c): 58.195 + self.begin_comment(c) 58.196 + elif c == k_list_open: 58.197 + self.begin_list(c) 58.198 + elif c == k_list_close: 58.199 + raise ParseError(self, "syntax error: "+c) 58.200 + elif self.in_string_quote_class(c): 58.201 + self.begin_string(c) 58.202 + elif self.in_printable_class(c): 58.203 + self.begin_atom(c) 58.204 + elif c == chr(4): 58.205 + # ctrl-D, EOT: end-of-text. 58.206 + self.input_eof() 58.207 + else: 58.208 + raise ParseError(self, "invalid character: code %d" % ord(c)) 58.209 + 58.210 + def begin_comment(self, c): 58.211 + self.push_state(self.state_comment) 58.212 + self.state.buf += c 58.213 + 58.214 + def end_comment(self): 58.215 + self.pop_state() 58.216 + 58.217 + def state_comment(self, c): 58.218 + if c == '\n' or self.at_eof(): 58.219 + self.end_comment() 58.220 + else: 58.221 + self.state.buf += c 58.222 + 58.223 + def begin_string(self, c): 58.224 + self.push_state(self.state_string) 58.225 + self.state.delim = c 58.226 + 58.227 + def end_string(self): 58.228 + val = self.state.buf 58.229 + self.state.parent.val.append(val) 58.230 + self.pop_state() 58.231 + 58.232 + def state_string(self, c): 58.233 + if self.at_eof(): 58.234 + raise ParseError(self, "unexpected EOF") 58.235 + elif c == self.state.delim: 58.236 + self.end_string() 58.237 + elif c == '\\': 58.238 + self.push_state(self.state_escape) 58.239 + else: 58.240 + self.state.buf += c 58.241 + 58.242 + def state_escape(self, c): 58.243 + if self.at_eof(): 58.244 + raise ParseError(self, "unexpected EOF") 58.245 + d = escapes.get(c) 58.246 + if d: 58.247 + self.state.parent.buf += d 58.248 + self.pop_state() 58.249 + elif c == 'x': 58.250 + self.state.fn = self.state_hex 58.251 + self.state.val = 0 58.252 + else: 58.253 + self.state.fn = self.state_octal 58.254 + self.state.val = 0 58.255 + self.input_char(c) 58.256 + 58.257 + def state_octal(self, c): 58.258 + def octaldigit(c): 58.259 + self.state.val *= 8 58.260 + self.state.val += ord(c) - ord('0') 58.261 + self.state.buf += c 58.262 + if self.state.val < 0 or self.state.val > 0xff: 58.263 + raise ParseError(self, "invalid octal escape: out of range " + self.state.buf) 58.264 + if len(self.state.buf) == 3: 58.265 + octaldone() 58.266 + 58.267 + def octaldone(): 58.268 + d = chr(self.state.val) 58.269 + self.state.parent.buf += d 58.270 + self.pop_state() 58.271 + 58.272 + if self.at_eof(): 58.273 + raise ParseError(self, "unexpected EOF") 58.274 + elif '0' <= c <= '7': 58.275 + octaldigit(c) 58.276 + elif len(self.buf): 58.277 + octaldone() 58.278 + self.input_char(c) 58.279 + 58.280 + def state_hex(self, c): 58.281 + def hexdone(): 58.282 + d = chr(self.state.val) 58.283 + self.state.parent.buf += d 58.284 + self.pop_state() 58.285 + 58.286 + def hexdigit(c, d): 58.287 + self.state.val *= 16 58.288 + self.state.val += ord(c) - ord(d) 58.289 + self.state.buf += c 58.290 + if self.state.val < 0 or self.state.val > 0xff: 58.291 + raise ParseError(self, "invalid hex escape: out of range " + self.state.buf) 58.292 + if len(self.state.buf) == 2: 58.293 + hexdone() 58.294 + 58.295 + if self.at_eof(): 58.296 + raise ParseError(self, "unexpected EOF") 58.297 + elif '0' <= c <= '9': 58.298 + hexdigit(c, '0') 58.299 + elif 'A' <= c <= 'F': 58.300 + hexdigit(c, 'A') 58.301 + elif 'a' <= c <= 'f': 58.302 + hexdigit(c, 'a') 58.303 + elif len(buf): 58.304 + hexdone() 58.305 + self.input_char(c) 58.306 + 58.307 + def begin_atom(self, c): 58.308 + self.push_state(self.state_atom) 58.309 + self.state.buf = c 58.310 + 58.311 + def end_atom(self): 58.312 + val = self.state.buf 58.313 + self.state.parent.val.append(val) 58.314 + self.pop_state() 58.315 + 58.316 + def state_atom(self, c): 58.317 + if self.at_eof(): 58.318 + self.end_atom() 58.319 + elif (self.is_separator(c) or 58.320 + self.in_space_class(c) or 58.321 + self.in_comment_class(c)): 58.322 + self.end_atom() 58.323 + self.input_char(c) 58.324 + else: 58.325 + self.state.buf += c 58.326 + 58.327 + def begin_list(self, c): 58.328 + self.push_state(self.state_list) 58.329 + 58.330 + def end_list(self): 58.331 + val = self.state.val 58.332 + self.state.parent.val.append(val) 58.333 + self.pop_state() 58.334 + 58.335 + def state_list(self, c): 58.336 + if self.at_eof(): 58.337 + raise ParseError(self, "unexpected EOF") 58.338 + elif c == k_list_close: 58.339 + self.end_list() 58.340 + else: 58.341 + self.state_start(c) 58.342 + 58.343 +def atomp(sxpr): 58.344 + if sxpr.isalnum() or sxpr == '@': 58.345 + return 1 58.346 + for c in sxpr: 58.347 + if c in string.whitespace: return 0 58.348 + if c in '"\'\\(){}[]<>$#&%^': return 0 58.349 + if c in string.ascii_letters: continue 58.350 + if c in string.digits: continue 58.351 + if c in '.-_:/~': continue 58.352 + return 0 58.353 + return 1 58.354 + 58.355 +def show(sxpr, out=sys.stdout): 58.356 + if isinstance(sxpr, types.ListType): 58.357 + out.write(k_list_open) 58.358 + i = 0 58.359 + for x in sxpr: 58.360 + if i: out.write(' ') 58.361 + show(x, out) 58.362 + i += 1 58.363 + out.write(k_list_close) 58.364 + elif isinstance(sxpr, types.StringType) and atomp(sxpr): 58.365 + out.write(sxpr) 58.366 + else: 58.367 + #out.write("'" + str(sxpr) + "'") 58.368 + out.write(repr(str(sxpr))) 58.369 + 58.370 +def show_xml(sxpr, out=sys.stdout): 58.371 + if isinstance(sxpr, types.ListType): 58.372 + element = name(sxpr) 58.373 + out.write('<%s' % element) 58.374 + for attr in attributes(sxpr): 58.375 + out.write(' %s=%s' % (attr[0], attr[1])) 58.376 + out.write('>') 58.377 + i = 0 58.378 + for x in children(sxpr): 58.379 + if i: out.write(' ') 58.380 + show_xml(x, out) 58.381 + i += 1 58.382 + out.write('</%s>' % element) 58.383 + elif isinstance(sxpr, types.StringType) and atomp(sxpr): 58.384 + out.write(sxpr) 58.385 + else: 58.386 + out.write(str(sxpr)) 58.387 + 58.388 +def elementp(sxpr, elt=None): 58.389 + return (isinstance(sxpr, types.ListType) 58.390 + and len(sxpr) 58.391 + and (None == elt or sxpr[0] == elt)) 58.392 + 58.393 +def name(sxpr): 58.394 + val = None 58.395 + if isinstance(sxpr, types.StringType): 58.396 + val = sxpr 58.397 + elif isinstance(sxpr, types.ListType) and len(sxpr): 58.398 + val = sxpr[0] 58.399 + return val 58.400 + 58.401 +def attributes(sxpr): 58.402 + val = [] 58.403 + if isinstance(sxpr, types.ListType) and len(sxpr) > 1: 58.404 + attr = sxpr[1] 58.405 + if elementp(attr, k_attr_open): 58.406 + val = attr[1:] 58.407 + return val 58.408 + 58.409 +def attribute(sxpr, key, val=None): 58.410 + for x in attributes(sxpr): 58.411 + if x[0] == key: 58.412 + val = x[1] 58.413 + break 58.414 + return val 58.415 + 58.416 +def children(sxpr, elt=None): 58.417 + val = [] 58.418 + if isinstance(sxpr, types.ListType) and len(sxpr) > 1: 58.419 + i = 1 58.420 + x = sxpr[i] 58.421 + if elementp(x, k_attr_open): 58.422 + i += 1 58.423 + val = sxpr[i : ] 58.424 + if elt: 58.425 + def iselt(x): 58.426 + return elementp(x, elt) 58.427 + val = filter(iselt, val) 58.428 + return val 58.429 + 58.430 +def child(sxpr, elt, val=None): 58.431 + for x in children(sxpr): 58.432 + if elementp(x, elt): 58.433 + val = x 58.434 + break 58.435 + return val 58.436 + 58.437 +def child_at(sxpr, index, val=None): 58.438 + kids = children(sxpr) 58.439 + if len(kids) > index: 58.440 + val = kids[index] 58.441 + return val 58.442 + 58.443 +def child0(sxpr, val=None): 58.444 + return child_at(sxpr, 0, val) 58.445 + 58.446 +def child1(sxpr, val=None): 58.447 + return child_at(sxpr, 1, val) 58.448 + 58.449 +def child2(sxpr, val=None): 58.450 + return child_at(sxpr, 2, val) 58.451 + 58.452 +def child3(sxpr, val=None): 58.453 + return child_at(sxpr, 3, val) 58.454 + 58.455 +def child4(sxpr, val=None): 58.456 + return child_at(sxpr, 4, val) 58.457 + 58.458 +def child_value(sxpr, elt, val=None): 58.459 + kid = child(sxpr, elt) 58.460 + if kid: 58.461 + val = child_at(kid, 0, val) 58.462 + return val 58.463 + 58.464 +def has_id(sxpr, id): 58.465 + """Test if an s-expression has a given id. 58.466 + """ 58.467 + return attribute(sxpr, 'id') == id 58.468 + 58.469 +def with_id(sxpr, id, val=None): 58.470 + """Find the first s-expression with a given id, at any depth. 58.471 + 58.472 + sxpr s-exp or list 58.473 + id id 58.474 + val value if not found (default None) 58.475 + 58.476 + return s-exp or val 58.477 + """ 58.478 + if isinstance(sxpr, types.ListType): 58.479 + for n in sxpr: 58.480 + if has_id(n, id): 58.481 + val = n 58.482 + break 58.483 + v = with_id(n, id) 58.484 + if v is None: continue 58.485 + val = v 58.486 + break 58.487 + return val 58.488 + 58.489 +def child_with_id(sxpr, id, val=None): 58.490 + """Find the first child with a given id. 58.491 + 58.492 + sxpr s-exp or list 58.493 + id id 58.494 + val value if not found (default None) 58.495 + 58.496 + return s-exp or val 58.497 + """ 58.498 + if isinstance(sxpr, types.ListType): 58.499 + for n in sxpr: 58.500 + if has_id(n, id): 58.501 + val = n 58.502 + break 58.503 + return val 58.504 + 58.505 +def elements(sxpr, ctxt=None): 58.506 + """Generate elements (at any depth). 58.507 + Visit elements in pre-order. 58.508 + Values generated are (node, context) 58.509 + The context is None if there is no parent, otherwise 58.510 + (index, parent, context) where index is the node's index w.r.t its parent, 58.511 + and context is the parent's context. 58.512 + 58.513 + sxpr s-exp 58.514 + 58.515 + returns generator 58.516 + """ 58.517 + yield (sxpr, ctxt) 58.518 + i = 0 58.519 + for n in children(sxpr): 58.520 + if isinstance(n, types.ListType): 58.521 + # Calling elements() recursively does not generate recursively, 58.522 + # it just returns a generator object. So we must iterate over it. 58.523 + for v in elements(n, (i, sxpr, ctxt)): 58.524 + yield v 58.525 + i += 1 58.526 + 58.527 +def parse(io): 58.528 + """Completely parse all input from 'io'. 58.529 + 58.530 + io input file object 58.531 + returns list of values, None if incomplete 58.532 + raises ParseError on parse error 58.533 + """ 58.534 + pin = Parser() 58.535 + while 1: 58.536 + buf = io.readline() 58.537 + pin.input(buf) 58.538 + if len(buf) == 0: 58.539 + break 58.540 + if pin.ready(): 58.541 + val = pin.get_all() 58.542 + else: 58.543 + val = None 58.544 + return val 58.545 + 58.546 + 58.547 +if __name__ == '__main__': 58.548 + print ">main" 58.549 + pin = Parser() 58.550 + while 1: 58.551 + buf = sys.stdin.read(1024) 58.552 + #buf = sys.stdin.readline() 58.553 + pin.input(buf) 58.554 + while pin.ready(): 58.555 + val = pin.get_val() 58.556 + print 58.557 + print '****** val=', val 58.558 + if len(buf) == 0: 58.559 + break 58.560 +
59.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 59.2 +++ b/tools/xenmgr/netfix Fri Jun 11 18:31:12 2004 +0000 59.3 @@ -0,0 +1,150 @@ 59.4 +#!/usr/bin/python 59.5 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com> 59.6 +#============================================================================ 59.7 +# Move the IP address from eth0 onto the Xen bridge (nbe-br). 59.8 +# Works best if the bridge control utils (brctl) have been installed. 59.9 +#============================================================================ 59.10 +import os 59.11 +import os.path 59.12 +import re 59.13 +import sys 59.14 + 59.15 +from getopt import getopt 59.16 + 59.17 +CMD_IFCONFIG = '/sbin/ifconfig' 59.18 +CMD_ROUTE = '/sbin/route' 59.19 +CMD_BRCTL = '/usr/local/sbin/brctl' 59.20 + 59.21 +def routes(): 59.22 + """Return a list of the routes. 59.23 + """ 59.24 + fin = os.popen(CMD_ROUTE + ' -n', 'r') 59.25 + routes = [] 59.26 + for x in fin: 59.27 + if x.startswith('Kernel'): continue 59.28 + if x.startswith('Destination'): continue 59.29 + x = x.strip() 59.30 + y = x.split() 59.31 + z = { 'destination': y[0], 59.32 + 'gateway' : y[1], 59.33 + 'mask' : y[2], 59.34 + 'flags' : y[3], 59.35 + 'metric' : y[4], 59.36 + 'ref' : y[5], 59.37 + 'use' : y[6], 59.38 + 'interface' : y[7] } 59.39 + routes.append(z) 59.40 + return routes 59.41 + 59.42 +def cmd(p, s): 59.43 + """Print and execute command 'p' with args 's'. 59.44 + """ 59.45 + global opts 59.46 + c = p + ' ' + s 59.47 + if opts.verbose: print c 59.48 + if not opts.dryrun: 59.49 + os.system(c) 59.50 + 59.51 +def ifconfig(interface): 59.52 + """Return the ip config for an interface, 59.53 + """ 59.54 + fin = os.popen(CMD_IFCONFIG + ' %s' % interface, 'r') 59.55 + inetre = re.compile('\s*inet\s*addr:(?P<address>\S*)\s*Bcast:(?P<broadcast>\S*)\s*Mask:(?P<mask>\S*)') 59.56 + info = None 59.57 + for x in fin: 59.58 + m = inetre.match(x) 59.59 + if not m: continue 59.60 + info = m.groupdict() 59.61 + info['interface'] = interface 59.62 + break 59.63 + return info 59.64 + 59.65 +def reconfigure(interface, bridge): 59.66 + """Reconfigure an interface to be attached to a bridge, and give the bridge 59.67 + the IP address etc. from interface. Move the default route to the interface 59.68 + to the bridge. 59.69 + """ 59.70 + intf_info = ifconfig(interface) 59.71 + if not intf_info: 59.72 + print 'Interface not found:', interface 59.73 + return 59.74 + #bridge_info = ifconfig(bridge) 59.75 + #if not bridge_info: 59.76 + # print 'Bridge not found:', bridge 59.77 + # return 59.78 + route_info = routes() 59.79 + intf_info['bridge'] = bridge 59.80 + intf_info['gateway'] = None 59.81 + for r in route_info: 59.82 + if (r['destination'] == '0.0.0.0' and 59.83 + 'G' in r['flags'] and 59.84 + r['interface'] == interface): 59.85 + intf_info['gateway'] = r['gateway'] 59.86 + if not intf_info['gateway']: 59.87 + print 'Gateway not found: ', interface 59.88 + return 59.89 + cmd(CMD_IFCONFIG, '%(interface)s 0.0.0.0' % intf_info) 59.90 + cmd(CMD_IFCONFIG, '%(bridge)s %(address)s netmask %(mask)s broadcast %(broadcast)s up' % intf_info) 59.91 + cmd(CMD_ROUTE, 'add default gateway %(gateway)s dev %(bridge)s' % intf_info) 59.92 + if os.path.exists(CMD_BRCTL): 59.93 + cmd(CMD_BRCTL, 'addif %(bridge)s %(interface)s' % intf_info) 59.94 + 59.95 +defaults = { 59.96 + 'interface': 'eth0', 59.97 + 'bridge' : 'nbe-br', 59.98 + 'verbose' : 1, 59.99 + 'dryrun' : 0, 59.100 + } 59.101 + 59.102 +short_options = 'hvqni:b:' 59.103 +long_options = ['help', 'verbose', 'quiet', 'interface=', 'bridge='] 59.104 + 59.105 +def usage(): 59.106 + print """Usage: 59.107 + %s [options] 59.108 + 59.109 + Reconfigure routing so that <bridge> has the IP address from 59.110 + <interface>. This lets IP carry on working when <interface> 59.111 + is attached to <bridge> for virtual networking. 59.112 + If brctl is available, <interface> is added to <bridge>, 59.113 + so this can be run before any domains have been created. 59.114 + """ % sys.argv[0] 59.115 + print """ 59.116 + -i, --interface <interface> interface, default %(interface)s. 59.117 + -b, --bridge <bridge> bridge, default %(bridge)s. 59.118 + -v, --verbose Print commands. 59.119 + -q, --quiet Don't print commands. 59.120 + -n, --dry-run Don't execute commands. 59.121 + -h, --help Print this help. 59.122 + """ % defaults 59.123 + sys.exit(1) 59.124 + 59.125 +class Opts: 59.126 + 59.127 + def __init__(self, defaults): 59.128 + for (k, v) in defaults.items(): 59.129 + setattr(self, k, v) 59.130 + pass 59.131 + 59.132 +def main(): 59.133 + global opts 59.134 + opts = Opts(defaults) 59.135 + (options, args) = getopt(sys.argv[1:], short_options, long_options) 59.136 + if args: usage() 59.137 + for k, v in options: 59.138 + if k in ['-h', '--help']: 59.139 + usage() 59.140 + elif k in ['-i', '--interface']: 59.141 + opts.interface = v 59.142 + elif k in ['-b', '--bridge']: 59.143 + opts.bridge = v 59.144 + elif k in ['-q', '--quiet']: 59.145 + opts.verbose = 0 59.146 + elif k in ['-v', '--verbose']: 59.147 + opts.verbose = 1 59.148 + elif k in ['-n', '--dry-run']: 59.149 + opts.dryrun = 1 59.150 + reconfigure(opts.interface, opts.bridge) 59.151 + 59.152 +if __name__ == '__main__': 59.153 + main()
60.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 60.2 +++ b/tools/xenmgr/setup.py Fri Jun 11 18:31:12 2004 +0000 60.3 @@ -0,0 +1,14 @@ 60.4 + 60.5 +from distutils.core import setup, Extension 60.6 + 60.7 +PACKAGE = 'xenmgr' 60.8 +VERSION = '1.0' 60.9 + 60.10 +setup(name = PACKAGE, 60.11 + version = VERSION, 60.12 + description = 'Xen Management API', 60.13 + author = 'Mike Wray', 60.14 + author_email = 'mike.wray@hp.com', 60.15 + packages = [ PACKAGE, PACKAGE + '.server' ], 60.16 + package_dir = { PACKAGE: 'lib' }, 60.17 + )
61.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 61.2 +++ b/tools/xenmgr/xend Fri Jun 11 18:31:12 2004 +0000 61.3 @@ -0,0 +1,40 @@ 61.4 +#!/usr/bin/python 61.5 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com> 61.6 + 61.7 +"""Xen management daemon. Lives in /usr/sbin. 61.8 + Provides console server and HTTP management api. 61.9 + 61.10 + Run: 61.11 + 61.12 + xend start 61.13 + 61.14 + The daemon is stopped with: 61.15 + 61.16 + xend stop 61.17 + 61.18 + Unfortunately restarting it upsets the channel to dom0 and 61.19 + domain management stops working - needs a reboot to fix. 61.20 +""" 61.21 +import os 61.22 +import sys 61.23 +from xenmgr.server import SrvConsoleServer 61.24 + 61.25 +def main(): 61.26 + daemon = SrvConsoleServer.instance() 61.27 + if not sys.argv[1:]: 61.28 + print 'usage: %s {start|stop|restart}' % sys.argv[0] 61.29 + elif os.fork(): 61.30 + pid, status = os.wait() 61.31 + return status >> 8 61.32 + elif sys.argv[1] == 'start': 61.33 + return daemon.start() 61.34 + elif sys.argv[1] == 'stop': 61.35 + return daemon.stop() 61.36 + elif sys.argv[1] == 'restart': 61.37 + return daemon.stop() or daemon.start() 61.38