[Kimchi-devel] [PATCH V13] Host device passthrough (Front-end): Add PCI Devices to VM
Wen Wang
wenwang at linux.vnet.ibm.com
Tue Oct 14 10:05:23 UTC 2014
From: Yu Xin Huo <huoyuxin at linux.vnet.ibm.com>
Signed-off-by: Yu Xin Huo <huoyuxin at linux.vnet.ibm.com>
Signed-off-by: Wen Wang <wenwang at linux.vnet.ibm.com>
---
ui/css/theme-default/guest-edit.css | 90 ++++++++++++++++++++++++++++++++++-
ui/js/src/kimchi.api.js | 55 +++++++++++++++++++++
ui/js/src/kimchi.guest_edit_main.js | 81 +++++++++++++++++++++++++++++++
ui/pages/guest-edit.html.tmpl | 30 ++++++++++++
4 files changed, 254 insertions(+), 2 deletions(-)
diff --git a/ui/css/theme-default/guest-edit.css b/ui/css/theme-default/guest-edit.css
index 76fbaf2..b1d3931 100644
--- a/ui/css/theme-default/guest-edit.css
+++ b/ui/css/theme-default/guest-edit.css
@@ -17,8 +17,8 @@
*/
#guest-edit-window {
font-size: 13px;
- height: 400px;
- width: 610px;
+ height: 420px;
+ width: 820px;
}
#guest-edit-tabs {
@@ -261,3 +261,89 @@
width: 46%;
float: right;
}
+
+.guest-edit-pci {
+ height: 79%;
+ overflow: auto;
+ font-size: 12px;
+}
+
+.guest-edit-pci .guest-scroll-indent {
+ width: 783px;
+}
+
+.guest-edit-pci .filter {
+ height: 35px;
+ margin-right: 5px;
+ overflow: hidden;
+}
+
+.guest-edit-pci .group {
+ float: right;
+}
+
+.guest-edit-pci .filter .control {
+ border: 1px solid #AAAAAA;
+ font-size: 12px;
+ background-color: white;
+}
+
+.guest-edit-pci .filter select {
+ border-right: 0px!important;
+ border-radius: 7px 0px 0px 7px;
+ padding: 2px 2px 2px 7px;
+ width: 100px;
+}
+
+.guest-edit-pci .filter select option {
+ padding-left: 7px;
+}
+
+.guest-edit-pci .filter input {
+ border-radius: 0px 7px 7px 0px;
+ padding: 3px 3px 3px 10px;
+ width: 200px;
+ font-style: italic;
+}
+
+.guest-edit-pci .header {
+ margin-bottom: 8px;
+ padding-bottom: 2px;
+ font-weight: bold;
+ border-bottom: 1px solid #999999;
+}
+
+.guest-edit-pci .item {
+ margin-bottom: 4px;
+ overflow: hidden;
+}
+
+.guest-edit-pci .cell {
+ display: inline-block;
+ vertical-align: middle;
+ margin-right: 10px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.guest-edit-pci .item button {
+ width: 20px;
+ height: 20px;
+ float: right;
+}
+
+.guest-edit-pci .name {
+ width: 18%;
+ max-width: 18%;
+}
+
+.guest-edit-pci .product {
+ width: 45%;
+ max-width: 45%;
+}
+
+.guest-edit-pci .vendor {
+ width: 25%;
+ max-width: 25%;
+}
diff --git a/ui/js/src/kimchi.api.js b/ui/js/src/kimchi.api.js
index f0506fa..5895a07 100644
--- a/ui/js/src/kimchi.api.js
+++ b/ui/js/src/kimchi.api.js
@@ -1115,6 +1115,20 @@ var kimchi = {
});
},
+ getHostPCIDevices : function(suc, err) {
+ kimchi.requestJSON({
+ url : kimchi.url + 'host/devices?_passthrough=true&_cap=pci',
+ type : 'GET',
+ contentType : 'application/json',
+ dataType : 'json',
+ resend : true,
+ success : suc,
+ error : err ? err : function(data) {
+ kimchi.message.error(data.responseJSON.reason);
+ }
+ });
+ },
+
getISCSITargets : function(server, port, suc, err) {
server = encodeURIComponent(server);
port = port ? '&_server_port='+encodeURIComponent(port) : '';
@@ -1145,6 +1159,47 @@ var kimchi = {
});
},
+ getVMPCIDevices : function(id, suc, err) {
+ kimchi.requestJSON({
+ url : kimchi.url + 'vms/'+encodeURIComponent(id)+'/hostdevs',
+ type : 'GET',
+ contentType : 'application/json',
+ dataType : 'json',
+ resend : true,
+ success : suc,
+ error : err ? err : function(data) {
+ kimchi.message.error(data.responseJSON.reason);
+ }
+ });
+ },
+
+ addVMPCIDevice : function(vm, device, suc, err) {
+ kimchi.requestJSON({
+ url : kimchi.url + 'vms/'+ encodeURIComponent(vm) +'/hostdevs',
+ type : 'POST',
+ contentType : 'application/json',
+ dataType : 'json',
+ data : JSON.stringify(device),
+ success : suc,
+ error : err ? err : function(data) {
+ kimchi.message.error(data.responseJSON.reason);
+ }
+ });
+ },
+
+ removeVMPCIDevice : function(vm, device, suc, err) {
+ kimchi.requestJSON({
+ url : kimchi.url + 'vms/'+ encodeURIComponent(vm) +'/hostdevs/' + encodeURIComponent(device),
+ type : 'DELETE',
+ contentType : 'application/json',
+ dataType : 'json',
+ success : suc,
+ error : err ? err : function(data) {
+ kimchi.message.error(data.responseJSON.reason);
+ }
+ });
+ },
+
/**
* Add a volume to a given storage pool.
*/
diff --git a/ui/js/src/kimchi.guest_edit_main.js b/ui/js/src/kimchi.guest_edit_main.js
index c281289..030e112 100644
--- a/ui/js/src/kimchi.guest_edit_main.js
+++ b/ui/js/src/kimchi.guest_edit_main.js
@@ -359,6 +359,86 @@ kimchi.guest_edit_main = function() {
});
};
+ var setupPCIDevice = function(){
+ kimchi.getHostPCIDevices(function(hostPCIs){
+ kimchi.getVMPCIDevices(kimchi.selectedGuest, function(vmPCIs){
+ kimchi.getCapabilities(function(result) {
+ var pciEnabled = result.kernel_vfio;
+ for(var i=0; i<hostPCIs.length; i++){
+ var itemNode = $.parseHTML(kimchi.substitute($('#pci-tmpl').html(),{
+ name: hostPCIs[i].name,
+ product: hostPCIs[i].product.description,
+ vendor: hostPCIs[i].vendor.description
+ }));
+ $(".body", "#form-guest-edit-pci").append(itemNode);
+ var iconClass = "ui-icon-plus";
+ for(var j=0; j<vmPCIs.length; j++){
+ if(hostPCIs[i].name==vmPCIs[j].name){
+ iconClass = "ui-icon-minus";
+ break;
+ }
+ }
+ pciEnabled || $("button", itemNode).remove();
+ $("button", itemNode).button({
+ icons: { primary: iconClass },
+ text: false
+ }).click(function(){
+ var obj = $(this);
+ if(obj.button("option", "icons").primary == "ui-icon-minus"){
+ kimchi.removeVMPCIDevice(kimchi.selectedGuest, obj.parent().prop("id"), function(){
+ kimchi.getVMPCIDevices(kimchi.selectedGuest, function(vmPCIs1){
+ for(var k=0; k<hostPCIs.length; k++) {
+ $("button", "#" + hostPCIs[k].name).button("option", "icons", {primary: "ui-icon-plus"});
+ }
+ for(var k=0; k<vmPCIs1.length; k++) {
+ $("button", "#" + vmPCIs1[k].name).button("option", "icons", {primary: "ui-icon-minus"});
+ }
+ });
+ filterNodes($("select", "#form-guest-edit-pci").val(), $("input", "#form-guest-edit-pci").val());
+ });
+ }else{
+ kimchi.addVMPCIDevice(kimchi.selectedGuest, { name: obj.parent().prop("id") }, function(){
+ kimchi.getVMPCIDevices(kimchi.selectedGuest, function(vmPCIs1){
+ for(var k=0; k<vmPCIs1.length; k++) {
+ $("button", "#" + vmPCIs1[k].name).button("option", "icons", {primary: "ui-icon-minus"});
+ }
+ });
+ filterNodes($("select", "#form-guest-edit-pci").val(), $("input", "#form-guest-edit-pci").val());
+ });
+ }
+ });
+ }
+ });
+ });
+ });
+ var filterNodes = function(group, text){
+ text = text.toLowerCase();
+ $(".body", "#form-guest-edit-pci").children().each(function(){
+ var textFilter = $(".name", this).text().toLowerCase().indexOf(text)!=-1;
+ textFilter = textFilter || $(".product", this).text().toLowerCase().indexOf(text)!=-1;
+ textFilter = textFilter || $(".vendor", this).text().toLowerCase().indexOf(text)!=-1;
+ var display = "none";
+ var itemGroup = $("button", this).button("option", "icons").primary;
+ if(textFilter){
+ if(group == "all"){
+ display = "";
+ }else if(group=="toAdd" && itemGroup=="ui-icon-plus"){
+ display = ""
+ }else if(group == "added" && itemGroup=="ui-icon-minus"){
+ display = ""
+ }
+ }
+ $(this).css("display", display);
+ });
+ };
+ $("select", "#form-guest-edit-pci").change(function(){
+ filterNodes($(this).val(), $("input", "#form-guest-edit-pci").val());
+ });
+ $("input", "#form-guest-edit-pci").on("keyup", function() {
+ filterNodes($("select", "#form-guest-edit-pci").val(), $(this).val());
+ });
+ };
+
var initContent = function(guest) {
guest['icon'] = guest['icon'] || 'images/icon-vm.png';
$('#form-guest-edit-general').fillWithObject(guest);
@@ -395,6 +475,7 @@ kimchi.guest_edit_main = function() {
initStorageListeners();
setupInterface();
setupPermission();
+ setupPCIDevice();
kimchi.topic('kimchi/vmCDROMAttached').subscribe(onAttached);
kimchi.topic('kimchi/vmCDROMReplaced').subscribe(onReplaced);
diff --git a/ui/pages/guest-edit.html.tmpl b/ui/pages/guest-edit.html.tmpl
index 917b2e8..512909a 100644
--- a/ui/pages/guest-edit.html.tmpl
+++ b/ui/pages/guest-edit.html.tmpl
@@ -41,6 +41,9 @@
<li>
<a href="#form-guest-edit-permission">$_("Permission")</a>
</li>
+ <li>
+ <a href="#form-guest-edit-pci">$_("Host PCI Device")</a>
+ </li>
</ul>
<form id="form-guest-edit-general">
<fieldset class="guest-edit-fieldset">
@@ -138,6 +141,25 @@
</div>
</div>
</form>
+ <form id="form-guest-edit-pci" class="guest-edit-pci">
+ <div class="guest-scroll-indent">
+ <div class="filter">
+ <span class="group">
+ <select class="control">
+ <option value="all">$_("All")</option>
+ <option value="toAdd">$_("To Add")</option>
+ <option value="added">$_("Added")</option>
+ </select><input type="text" class="control" placeholder="$_("filter")">
+ </span>
+ </div>
+ <div class="header">
+ <span class="cell name">$_("Name")</span>
+ <span class="cell product">$_("Product")</span>
+ <span class="cell vendor">$_("Vendor")</span>
+ </div>
+ <div class="body"></div>
+ </div>
+ </form>
</div>
</div>
<footer>
@@ -221,6 +243,14 @@
<label>{val}</label>
</div>
</script>
+<script id="pci-tmpl" type="text/html">
+<div class="item" id="{name}">
+ <span class="cell name" title="{name}">{name}</span>
+ <span class="cell product" title="{product}">{product}</span>
+ <span class="cell vendor" title="{vendor}">{vendor}</span>
+ <button></button>
+</div>
+</script>
<script type="text/javascript">
kimchi.guest_edit_main();
</script>
--
1.7.1
More information about the Kimchi-devel
mailing list