[Kimchi-devel] [PATCH v11 6/6] Host device passthrough (Front-end): Add PCI Devices to VM

Zhou Zheng Sheng zhshzhou at linux.vnet.ibm.com
Tue Sep 30 10:00:56 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 | 86 ++++++++++++++++++++++++++++++++++++-
 ui/js/src/kimchi.api.js             | 55 ++++++++++++++++++++++++
 ui/js/src/kimchi.guest_edit_main.js | 81 ++++++++++++++++++++++++++++++++++
 ui/pages/guest-edit.html.tmpl       | 28 ++++++++++++
 4 files changed, 248 insertions(+), 2 deletions(-)

diff --git a/ui/css/theme-default/guest-edit.css b/ui/css/theme-default/guest-edit.css
index 76fbaf2..ef2266f 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,85 @@
     width: 46%;
     float: right;
 }
+
+.guest-edit-pci {
+    height: 79%;
+    overflow: auto;
+    font-size: 12px;
+}
+
+.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 3398bd4..86bfd22 100644
--- a/ui/js/src/kimchi.api.js
+++ b/ui/js/src/kimchi.api.js
@@ -1114,6 +1114,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) : '';
@@ -1144,6 +1158,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..69b11a7 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,23 @@
                         </div>
                     </div>
             </form>
+            <form id="form-guest-edit-pci" class="guest-edit-pci">
+                <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>
+            </form>
         </div>
     </div>
     <footer>
@@ -221,6 +241,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.9.3




More information about the Kimchi-devel mailing list