]> xenbits.xen.org Git - xenclient/toolstack.git/commitdiff
[xenvm] Add support for virtual wireless network device (vwif!)
authorTomasz Wroblewski <tomasz.wroblewski@citrix.com>
Thu, 28 Jan 2010 16:22:23 +0000 (16:22 +0000)
committerTomasz Wroblewski <tomasz.wroblewski@citrix.com>
Thu, 28 Jan 2010 16:22:54 +0000 (16:22 +0000)
xenops/device.ml
xenops/device.mli
xenops/device_common.ml
xenops/device_common.mli
xenops/hotplug.ml
xenvm/vmact.ml
xenvm/vmconfig.ml

index 5abd72758379f9d23767ac92dfa707a2a19a31a5..7831090f876d25c55f79ee99449e561e9d462430 100644 (file)
@@ -43,7 +43,6 @@ let add_device ~xs device backend_list frontend_list =
        let frontend_path = frontend_path_of_device ~xs device
        and backend_path = backend_path_of_device ~xs device
        and hotplug_path = Hotplug.get_hotplug_path device in
-
        debug "adding device  B%d[%s]  F%d[%s]  H[%s]" device.backend.domid backend_path device.frontend.domid frontend_path hotplug_path;
        Xs.transaction xs (fun t ->
                begin try
@@ -761,6 +760,153 @@ let release ~xs (x: device) =
        Hotplug.release ~xs x
 end
 
+(****************************************************************************************)
+(** VWIFs:                                                                              *)
+module Vwif = struct
+
+exception Invalid_Mac of string
+
+let check_mac mac =
+        try
+                if String.length mac <> 17 then failwith "mac length";
+               Scanf.sscanf mac "%2x:%2x:%2x:%2x:%2x:%2x" (fun a b c d e f -> ());
+               mac
+        with _ ->
+               raise (Invalid_Mac mac)
+
+let get_backend_dev ~xs (x: device) =
+        try
+               let path = Hotplug.get_hotplug_path x in
+               xs.Xs.read (path ^ "/vif")
+       with Xb.Noent ->
+               raise (Hotplug_script_expecting_field (x, "vif"))
+
+(** Plug in the backend of a guest's VIF in dom0. Note that a guest may disconnect and
+    then reconnect their network interface: we have to re-run this code every time we
+    see a hotplug online event. *)
+let plug ~xs ~netty ~mac ?(mtu=0) ?rate ?protocol (x: device) =
+       let backend_dev = get_backend_dev xs x in
+
+       if mtu > 0 then
+               Netdev.set_mtu backend_dev mtu;
+       Netman.online backend_dev netty;
+
+       (* set <backend>/hotplug-status = connected to interact nicely with the
+          xs-xen.pq.hq:91e986b8e49f netback-wait-for-hotplug patch *)
+       xs.Xs.write (Hotplug.connected_node ~xs x) "connected";
+
+       x
+
+
+let add ~xs ~devid ~netty ~mac ?mtu ?(rate=None) ?(protocol=Protocol_Native) ?(backend_domid=0) domid =
+       debug "Device.Vwif.add domid=%d devid=%d mac=%s rate=%s" domid devid mac
+             (match rate with None -> "none" | Some (a, b) -> sprintf "(%Ld,%Ld)" a b);
+       let frontend = { domid = domid; kind = Vwif; devid = devid } in
+       let backend = { domid = backend_domid; kind = Vif; devid = devid } in
+       let device = { backend = backend; frontend = frontend } in
+
+       let mac = check_mac mac in
+
+       let back_options =
+               match rate with
+               | None                              -> []
+               | Some (kbytes_per_s, timeslice_us) ->
+                       let (^*) = Int64.mul and (^/) = Int64.div in
+                       let timeslice_us =
+                               if timeslice_us > 0L then
+                                       timeslice_us
+                               else
+                                       50000L (* 50ms by default *) in
+                       let bytes_per_interval = ((kbytes_per_s ^* 1024L) ^* timeslice_us)
+                                                ^/ 1000000L in
+                       if bytes_per_interval > 0L && bytes_per_interval < 0xffffffffL then
+                               [ "rate", sprintf "%Lu,%Lu" bytes_per_interval timeslice_us ]
+                       else (
+                               debug "VIF qos: invalid value for byte/interval: %Lu" bytes_per_interval;
+                               []
+                       )
+               in
+
+       let back = [
+               "frontend-id", sprintf "%u" domid;
+               "online", "1";
+               "state", string_of_int (Xenbus.int_of Xenbus.Initialising);
+               "script", "/etc/xensource/scripts/vif";
+               "mac", mac;
+               "handle", string_of_int devid
+       ] @ back_options in
+
+       let front_options =
+               if protocol <> Protocol_Native then
+                       [ "protocol", string_of_protocol protocol; ]
+               else
+                       [] in
+
+       let front = [
+               "backend-id", string_of_int backend_domid;
+               "state", string_of_int (Xenbus.int_of Xenbus.Initialising);
+               "handle", string_of_int devid;
+               "mac", mac;
+               "rssi", "-65";
+               "link-quality", "95";
+               "ssid", "XenWireless";
+       ] @ front_options in
+
+
+       Generic.add_device ~xs device back front;
+       Hotplug.wait_for_plug ~xs device;
+       plug ~xs ~netty ~mac ?rate ?mtu device
+
+(** When hot-unplugging a device we ask nicely *)
+let request_closure ~xs (x: device) =
+       let backend_path = backend_path_of_device ~xs x in
+       let state_path = backend_path ^ "/state" in
+       Xs.transaction xs (fun t ->
+               let online_path = backend_path ^ "/online" in
+               debug "xenstore-write %s = 0" online_path;
+               t.Xst.write online_path "0";
+               let state = try Xenbus.of_string (t.Xst.read state_path) with _ -> Xenbus.Closed in
+               if state == Xenbus.Connected then (
+                       debug "Device.del_device setting backend to Closing";
+                       t.Xst.write state_path (Xenbus.string_of Xenbus.Closing);
+               )
+       )
+
+let unplug_watch ~xs (x: device) = Watch.map (fun () -> "") (Watch.key_to_disappear (Hotplug.status_node x))
+let error_watch ~xs (x: device) = Watch.value_to_appear (error_path_of_device ~xs x) 
+
+let clean_shutdown ~xs (x: device) =
+       debug "Device.Vwif.clean_shutdown %s" (string_of_device x);
+
+       request_closure ~xs x;
+       match Watch.wait_for ~xs (Watch.any_of [ `OK, unplug_watch ~xs x; `Failed, error_watch ~xs x ]) with
+       | `OK, _ ->
+           (* Delete the trees (otherwise attempting to plug the device in again doesn't
+              work. This also clears any stale error nodes. *)
+           Generic.rm_device_state ~xs x
+       | `Failed, error ->
+           debug "Device.Vwif.shutdown_common: read an error: %s" error;
+           raise (Device_error (x, error))     
+
+let hard_shutdown ~xs (x: device) =
+       debug "Device.Vwif.hard_shutdown %s" (string_of_device x);
+
+       let backend_path = backend_path_of_device ~xs x in
+       let online_path = backend_path ^ "/online" in
+       debug "xenstore-write %s = 0" online_path;
+       xs.Xs.write online_path "0";
+       (* blow away the frontend *)
+       debug "Device.Vwif.hard_shutdown about to blow away frontend";
+       let frontend_path = frontend_path_of_device ~xs x in
+       xs.Xs.rm frontend_path;
+
+       ignore(Watch.wait_for ~xs (unplug_watch ~xs x))
+
+let release ~xs (x: device) =
+       debug "Device.Vwif.release %s" (string_of_device x);
+       Hotplug.release ~xs x
+end
+
 (*****************************************************************************)
 (** Vcpus:                                                                   *)
 module Vcpu = struct
@@ -1140,6 +1286,7 @@ end
 
 let hard_shutdown ~xs (x: device) = match x.backend.kind with
   | Vif -> Vif.hard_shutdown ~xs x
+  | Vwif -> Vwif.hard_shutdown ~xs x
   | Vbd | Tap -> Vbd.hard_shutdown ~xs x
   | Pci -> PCI.hard_shutdown ~xs x
   | Vfb -> Vfb.hard_shutdown ~xs x
@@ -1147,6 +1294,7 @@ let hard_shutdown ~xs (x: device) = match x.backend.kind with
 
 let clean_shutdown ~xs (x: device) = match x.backend.kind with
   | Vif -> Vif.clean_shutdown ~xs x
+  | Vwif -> Vwif.clean_shutdown ~xs x
   | Vbd | Tap -> Vbd.clean_shutdown ~xs x
   | Pci -> PCI.clean_shutdown ~xs x
   | Vfb -> Vfb.clean_shutdown ~xs x
index eb96ddc1eec37cb00f4c5179198d8668cf8bc235..baf2af0d50785af2fc5e041672e7135683c555a5 100644 (file)
@@ -79,6 +79,7 @@ sig
        val hard_shutdown_complete : xs:Xs.xsh -> device -> string Watch.t
 end
 
+(** Virtual network interface *)
 module Vif :
 sig
        exception Invalid_Mac of string
@@ -94,6 +95,22 @@ sig
        val release : xs:Xs.xsh -> device -> unit
 end
 
+(** Virtual wireless network interface *)
+module Vwif :
+sig
+       exception Invalid_Mac of string
+       val get_backend_dev : xs:Xs.xsh -> device -> string
+       val add : xs:Xs.xsh -> devid:int -> netty:Netman.netty
+              -> mac:string -> ?mtu:int -> ?rate:(int64 * int64) option
+              -> ?protocol:protocol -> ?backend_domid:Xc.domid -> Xc.domid
+              -> device
+       val plug : xs:Xs.xsh -> netty:Netman.netty
+               -> mac:string -> ?mtu:int -> ?rate:(int64 * int64) option
+               -> ?protocol:protocol -> device
+               -> device
+       val release : xs:Xs.xsh -> device -> unit
+end
+
 val clean_shutdown : xs:Xs.xsh -> device -> unit
 val hard_shutdown  : xs:Xs.xsh -> device -> unit
 
index 9025908877dc87763efe79db1b240bf5dec591a0..b8a4017915c5acb8913221cb13cfde86994924bd 100644 (file)
@@ -19,7 +19,7 @@ open Stringext
 open Hashtblext
 open Pervasiveext
 
-type kind = Vif | Vbd | Tap | Pci | Vfb | Vkb
+type kind = Vif | Vwif | Vbd | Tap | Pci | Vfb | Vkb
 
 type devid = int
 (** Represents one end of a device *)
@@ -46,9 +46,9 @@ open D
 open Printf
 
 let string_of_kind = function
-  | Vif -> "vif" | Vbd -> "vbd" | Tap -> "tap" | Pci -> "pci" | Vfb -> "vfb" | Vkb -> "vkbd"
+  | Vif -> "vif" | Vwif -> "vwif" | Vbd -> "vbd" | Tap -> "tap" | Pci -> "pci" | Vfb -> "vfb" | Vkb -> "vkbd"
 let kind_of_string = function
-  | "vif" -> Vif | "vbd" -> Vbd | "tap" -> Tap | "pci" -> Pci | "vfb" -> Vfb | "vkbd" -> Vkb
+  | "vif" -> Vif | "vwif" -> Vwif | "vbd" -> Vbd | "tap" -> Tap | "pci" -> Pci | "vfb" -> Vfb | "vkbd" -> Vkb
   | x -> raise (Unknown_device_type x)
 
 let string_of_endpoint (x: endpoint) =
index 69d17a077dad6f545ed030ab42472ed053a61f34..b26901be9ba9aa5ac55e0441ffab1232157b5ba2 100644 (file)
@@ -15,7 +15,7 @@
  * GNU Lesser General Public License for more details.
  *)
 
-type kind = Vif | Vbd | Tap | Pci | Vfb | Vkb
+type kind = Vif | Vwif | Vbd | Tap | Pci | Vfb | Vkb
 
 type devid = int
 
index 4b2f97201f2f1f77aa002589e55f765c087051aa..fe01582663acecfbe2291a631953219792cbf6c5 100644 (file)
@@ -93,7 +93,7 @@ let device_is_online ~xs (x: device) =
 
   match x.backend.kind with
   | Pci | Vfb | Vkb -> assert false (* PCI/Vfb backend doesn't create online node *)
-  | Vif -> backend_hotplug ()
+  | Vif | Vwif -> backend_hotplug ()
   | ( Vbd | Tap ) -> 
       if backend_request () 
       then not(backend_shutdown ())
index 084e8948a29f8bf8f99c5e187fba8abe962cbeca..18ce10334334a95269e52d12693df8f11b9d0fc2 100644 (file)
@@ -167,8 +167,9 @@ let add_pci_to_vm ~xs state pci =
 let add_nic_to_vm ~xs state nic =
        let netty = Netman.Bridge nic.nic_bridge in
        let (_: Device_common.device) =
-               Device.Vif.add ~xs ~devid:nic.nic_id ~netty ~mac:nic.nic_mac
-                              ~protocol:(devproto_of_state state) state.vm_domid in
+               let add = if nic.nic_wireless then Device.Vwif.add else Device.Vif.add in
+               add ~xs ~devid:nic.nic_id ~netty ~mac:nic.nic_mac
+                       ~protocol:(devproto_of_state state) state.vm_domid in
         state.vm_nics <- {ns_id=nic.nic_id; ns_bridge=nic.nic_bridge}::state.vm_nics;
        ()
 
index 0cf50b4c60300b01c31c2c5fa2d358b270b16c8f..da5a9dd2983dcc6d4c9f469c1401dca943016ebc 100644 (file)
@@ -101,6 +101,7 @@ type config_nic = {
        nic_mac: string;
        nic_model: string;
        nic_dynadded: bool;
+       nic_wireless: bool;
 }
 
 type config = {
@@ -171,6 +172,7 @@ let default_nic =
                nic_mac = "";
                nic_model = "";
                nic_dynadded = false;
+               nic_wireless = false;
        }
 
 module Config = struct
@@ -223,7 +225,8 @@ let config_nic_of_string s =
        let id = ref (-1)
        and bridge = ref ""
        and model = ref ""
-       and mac = ref "" in
+       and mac = ref ""
+       and wireless = ref false in
 
        List.iter (fun v ->
                let lv = String.split '=' v in
@@ -231,11 +234,12 @@ let config_nic_of_string s =
                and value = List.nth lv 1 in
 
                match lvalue with
-               | "id"     -> id := int_of_string value
-               | "bridge" -> bridge := value
-               | "model"  -> model := value
-               | "mac"    -> mac := value
-               | _        -> ()
+               | "id"       -> id := int_of_string value
+               | "bridge"   -> bridge := value
+               | "model"    -> model := value
+               | "mac"      -> mac := value
+               | "wireless" -> wireless := bool_of_string value
+               | _          -> ()
        ) ls;
 
        { default_nic with
@@ -243,6 +247,7 @@ let config_nic_of_string s =
                nic_bridge = !bridge;
                nic_mac = !mac;
                nic_model = !model;
+               nic_wireless = !wireless;
        }
 
 (* Where NIC IDs have been left blank (or explicitly set to -1), here we allocate them a reasonable number. We also allocate a bridge and a mac, if necessary *)