diff --git a/network/jbuild b/network/jbuild index a506878c..bf09ace8 100644 --- a/network/jbuild +++ b/network/jbuild @@ -15,42 +15,27 @@ let flags = function in go ic "" +let rewriters_ppx = ["ppx_deriving_rpc"] + let coverage_rewriter = let is_coverage = try Unix.getenv "BISECT_ENABLE" = "YES" with Not_found -> false in if is_coverage then "(preprocess (pps (bisect_ppx -conditional)))" else - "" - -let rewriters_camlp4 = ["rpclib.idl -syntax camlp4o"] -let rewriters_ppx = ["ppx_deriving_rpc"; "ppx_sexp_conv"] + Printf.sprintf "(preprocess (pps (%s)))" (String.concat " " rewriters_ppx) let () = Printf.ksprintf Jbuild_plugin.V1.send {| (jbuild_version 1) -(library - ((name xcp_network_interface) - (public_name xcp.network.interface) - (modules (network_interface)) - (flags (:standard -w -39 %s)) - (libraries - (rpclib - threads - xcp)) - (wrapped false) - %s)) - (library ((name xcp_network) (public_name xcp.network) - (modules (:standard \ network_interface)) (flags (:standard -w -39-33 %s)) (libraries (rpclib threads - xcp - xcp_network_interface)) + xcp)) (wrapped false) %s)) -|} (flags rewriters_camlp4) coverage_rewriter (flags rewriters_ppx) coverage_rewriter +|} (flags rewriters_ppx) coverage_rewriter diff --git a/network/network_client.ml b/network/network_client.ml index c1340438..a5cf847d 100644 --- a/network/network_client.ml +++ b/network/network_client.ml @@ -12,9 +12,6 @@ * GNU Lesser General Public License for more details. *) -open Network_interface -open Xcp_client - let retry_econnrefused f = let rec loop () = let result = @@ -28,16 +25,16 @@ let retry_econnrefused f = | None -> loop () in loop () -module Client = Network_interface.Client(struct - let rpc call = - retry_econnrefused - (fun () -> - if !use_switch - then json_switch_rpc !queue_name call - else xml_http_rpc - ~srcstr:(Xcp_client.get_user_agent ()) - ~dststr:"network" - Network_interface.uri - call - ) -end) +let rpc call = + retry_econnrefused + (fun () -> + if !Xcp_client.use_switch + then Xcp_client.json_switch_rpc !Network_interface.queue_name call + else Xcp_client.xml_http_rpc + ~srcstr:(Xcp_client.get_user_agent ()) + ~dststr:"network" + Network_interface.uri + call + ) + +module Client = Network_interface.Interface_API(Idl.GenClientExnRpc(struct let rpc=rpc end)) diff --git a/network/network_interface.ml b/network/network_interface.ml index 7fca40d2..eeb81746 100644 --- a/network/network_interface.ml +++ b/network/network_interface.ml @@ -11,6 +11,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. *) +open Rpc +open Idl (** {2 Helper functions} *) @@ -25,111 +27,131 @@ let uri () = "file:" ^ !default_path let comp f g x = f (g x) let (++) f g x = comp f g x -module Unix = struct - include Unix - let inet_addr_of_rpc rpc = Unix.inet_addr_of_string (Rpc.string_of_rpc rpc) - let rpc_of_inet_addr inet = Rpc.rpc_of_string (Unix.string_of_inet_addr inet) -end - let netmask_to_prefixlen netmask = - Scanf.sscanf netmask "%d.%d.%d.%d" (fun a b c d -> - let rec length l x = - if x > 0 then - length (succ l) (x lsr 1) - else - l - in - let masks = List.map ((-) 255) [a; b; c; d] in - 32 - (List.fold_left length 0 masks) - ) + Scanf.sscanf netmask "%d.%d.%d.%d" (fun a b c d -> + let rec length l x = + if x > 0 then + length (succ l) (x lsr 1) + else + l + in + let masks = List.map ((-) 255) [a; b; c; d] in + 32 - (List.fold_left length 0 masks) + ) let prefixlen_to_netmask len = - let mask l = - if l <= 0 then - 0 - else if l > 8 then - 255 - else - 256 - (1 lsl (8 - l)) - in - let lens = [len; len - 8; len - 16; len - 24] in - let masks = List.map (string_of_int ++ mask) lens in - String.concat "." masks - -(** {2 Exceptions} *) + let mask l = + if l <= 0 then + 0 + else if l > 8 then + 255 + else + 256 - (1 lsl (8 - l)) + in + let lens = [len; len - 8; len - 16; len - 24] in + let masks = List.map (string_of_int ++ mask) lens in + String.concat "." masks -exception Script_missing of string -exception Script_error of (string * string) list -exception Read_error of string -exception Write_error of string -exception Not_implemented -exception Vlan_in_use of (string * int) +module Unix = struct + include Unix + let typ_of_inet_addr = Rpc.Types.Abstract ({ + rpc_of = (fun t -> Rpc.String (Unix.string_of_inet_addr t)); + of_rpc = (function + | Rpc.String s -> Ok (Unix.inet_addr_of_string s) + | r -> Error (`Msg (Printf.sprintf "typ_of_inet_addr: expectd rpc string but got %s" (Rpc.to_string r)))); + }) +end (** {2 Types} *) -type debug_info = string -type iface = string -type port = string -type bridge = string -type dhcp_options = [`set_gateway | `set_dns] -type ipv4 = None4 | DHCP4 | Static4 of (Unix.inet_addr * int) list -type ipv6 = None6 | Linklocal6 | DHCP6 | Autoconf6 | Static6 of (Unix.inet_addr * int) list - -type duplex = Duplex_unknown | Duplex_half | Duplex_full +type debug_info = string [@@deriving rpcty] +type iface = string [@@deriving rpcty] +type port = string [@@deriving rpcty] +type bridge = string [@@deriving rpcty] +(* rpcty cannot handle polymorphic variant, so change the definition to variant *) +type dhcp_options = Set_gateway | Set_dns [@@deriving rpcty] +type ipv4 = None4 | DHCP4 | Static4 of (Unix.inet_addr * int) list [@@deriving rpcty] +type ipv6 = None6 | Linklocal6 | DHCP6 | Autoconf6 | Static6 of (Unix.inet_addr * int) list [@@deriving rpcty] + +type duplex = + | Duplex_unknown + | Duplex_half + | Duplex_full +[@@default Duplex_unknown] +[@@deriving rpcty] let string_of_duplex = function - | Duplex_unknown -> "unknown" - | Duplex_half -> "half" - | Duplex_full -> "full" + | Duplex_unknown -> "unknown" + | Duplex_half -> "half" + | Duplex_full -> "full" let duplex_of_string = function - | "full" -> Duplex_full - | "half" -> Duplex_half - | _ -> Duplex_unknown + | "full" -> Duplex_full + | "half" -> Duplex_half + | _ -> Duplex_unknown +(* `Basic` is conflict with Rpc.Basic so rename it to `Basic_port`*) type port_kind = - | Basic - | PVS_proxy + | Basic_port + | PVS_proxy +[@@deriving rpcty] let string_of_port_kind = function - | Basic -> "basic" - | PVS_proxy -> "PVS proxy" + | Basic_port -> "basic" + | PVS_proxy -> "PVS proxy" + +type ipv4_route_t = { + subnet : Unix.inet_addr; + netmask : int; + gateway : Unix.inet_addr; +} [@@deriving rpcty] + +type kind = Openvswitch | Bridge [@@deriving rpcty] + +let string_of_kind = function + | Openvswitch -> "openvswitch" + | Bridge -> "bridge" + +type bond_mode = Balance_slb | Active_backup | Lacp [@@deriving rpcty] +type fail_mode = Standalone | Secure [@@deriving rpcty] type interface_config_t = { - ipv4_conf: ipv4; - ipv4_gateway: Unix.inet_addr option; - ipv6_conf: ipv6; - ipv6_gateway: Unix.inet_addr option; - ipv4_routes: (Unix.inet_addr * int * Unix.inet_addr) list; - dns: Unix.inet_addr list * string list; - mtu: int; - ethtool_settings: (string * string) list; - ethtool_offload: (string * string) list; - persistent_i: bool; -} + ipv4_conf: ipv4 [@default None4]; + ipv4_gateway: Unix.inet_addr option [@default None]; + ipv6_conf: ipv6 [@default None6]; + ipv6_gateway: Unix.inet_addr option [@default None]; + ipv4_routes: ipv4_route_t list [@default []]; + dns: Unix.inet_addr list * string list [@default [], []]; + mtu: int [@default 1500]; + ethtool_settings: (string * string) list [@default []]; + ethtool_offload: (string * string) list [@default ["lro", "off"]]; + persistent_i: bool [@default false]; +} [@@deriving rpcty] + type port_config_t = { - interfaces: iface list; - bond_properties: (string * string) list; - bond_mac: string option; - kind: port_kind; -} + interfaces: iface list [@default []]; + bond_properties: (string * string) list [@default []]; + bond_mac: string option [@default None]; + kind: port_kind [@default Basic_port]; +} [@@deriving rpcty] + type bridge_config_t = { - ports: (port * port_config_t) list; - vlan: (bridge * int) option; - bridge_mac: string option; - igmp_snooping: bool option; - other_config: (string * string) list; - persistent_b: bool; -} + ports: (port * port_config_t) list [@default []]; + vlan: (bridge * int) option [@default None]; + bridge_mac: string option [@default None]; + igmp_snooping: bool option [@default None]; + other_config: (string * string) list [@default []]; + persistent_b: bool [@default false]; +} [@@deriving rpcty] + type config_t = { - interface_config: (iface * interface_config_t) list; - bridge_config: (bridge * bridge_config_t) list; - gateway_interface: iface option; - dns_interface: iface option; -} + interface_config: (iface * interface_config_t) list [@default []]; + bridge_config: (bridge * bridge_config_t) list [@default []]; + gateway_interface: iface option [@default None]; + dns_interface: iface option [@default None]; +} [@@deriving rpcty] (** {2 Default configuration} *) - let default_interface = { ipv4_conf = None4; ipv4_gateway = None; @@ -142,6 +164,7 @@ let default_interface = { ethtool_offload = ["lro", "off"]; persistent_i = false; } + let default_bridge = { ports = []; vlan = None; @@ -150,12 +173,14 @@ let default_bridge = { other_config = []; persistent_b = false; } + let default_port = { interfaces = []; bond_properties = []; bond_mac = None; - kind = Basic; + kind = Basic_port; } + let default_config = { interface_config = []; bridge_config = []; @@ -163,161 +188,425 @@ let default_config = { dns_interface = None } -(** {2 RPC functions} *) - -let interface_config_t_add_defaults rpc = - Rpc.struct_extend rpc (rpc_of_interface_config_t default_interface) - -let port_config_t_add_defaults rpc = - Rpc.struct_extend rpc (rpc_of_port_config_t default_port) - -let bridge_config_t_add_defaults rpc = - (* This needs some special treatment, because bridge_config_t contains a list of port_config_t records - * that may need to have defaults inserted. Rpc.struct_extend does not currently support this. *) - let open Rpc in - let rpc' = Rpc.struct_extend rpc (rpc_of_bridge_config_t default_bridge) in - match rpc' with - | Dict r -> - Dict (List.map (fun (k, v) -> - match k, v with - | "ports", Dict v' -> - k, Dict (List.map (fun (name, config) -> name, port_config_t_add_defaults config) v') - | x -> x - ) r) - | x -> x - -let config_t_add_defaults rpc = - (* This needs some special treatment, because config_t contains lists of bridge_config_t and - * interface_config_t records that may need to have defaults inserted. Rpc.struct_extend does - * not currently support this. *) - let open Rpc in - let rpc' = Rpc.struct_extend rpc (rpc_of_config_t default_config) in - match rpc' with - | Dict r -> - Dict (List.map (fun (k, v) -> - match k, v with - | "bridge_config", Dict v' -> - k, Dict (List.map (fun (name, config) -> name, bridge_config_t_add_defaults config) v') - | "interface_config", Dict v' -> - k, Dict (List.map (fun (name, config) -> name, interface_config_t_add_defaults config) v') - | x -> x - ) r) - | x -> x - -let interface_config_t_of_rpc rpc = rpc |> interface_config_t_add_defaults |> interface_config_t_of_rpc -let port_config_t_of_rpc rpc = rpc |> port_config_t_add_defaults |> port_config_t_of_rpc -let bridge_config_t_of_rpc rpc = rpc |> bridge_config_t_add_defaults |> bridge_config_t_of_rpc -let config_t_of_rpc rpc = rpc |> config_t_add_defaults |> config_t_of_rpc - (** {2 Configuration manipulation} *) -let empty_config = default_config - let get_config config default name = - if List.mem_assoc name config = false then - default - else - List.assoc name config + try + List.assoc name config + with _ -> default let remove_config config name = - if List.mem_assoc name config then - List.remove_assoc name config - else - config - - + List.remove_assoc name config let update_config config name data = - let replace_assoc key new_value existing = - (key, new_value) :: (List.filter (fun (k, _) -> k <> key) existing) in + let replace_assoc key new_value existing = + (key, new_value) :: (List.filter (fun (k, _) -> k <> key) existing) in - if List.mem_assoc name config then begin - replace_assoc name data config - end else - (name, data) :: config + if List.mem_assoc name config then begin + replace_assoc name data config + end else + (name, data) :: config -(** {2 API functions} *) +(** {2 Exceptions} *) -external clear_state: unit -> unit = "" -external reset_state: unit -> unit = "" - -external set_gateway_interface: debug_info -> name:iface -> unit = "" -external set_dns_interface: debug_info -> name:iface -> unit = "" - -module Interface = struct - external get_all : debug_info -> unit -> iface list = "" - external exists : debug_info -> name:iface -> bool = "" - external get_mac : debug_info -> name:iface -> string = "" - external is_up : debug_info -> name:iface -> bool = "" - external get_ipv4_addr : debug_info -> name:iface -> (Unix.inet_addr * int) list = "" - external set_ipv4_conf : debug_info -> name:iface -> conf:ipv4 -> unit = "" - external get_ipv4_gateway : debug_info -> name:iface -> Unix.inet_addr option = "" - external get_ipv6_addr : debug_info -> name:iface -> (Unix.inet_addr * int) list = "" - external get_dns : debug_info -> name:iface -> Unix.inet_addr list * string list = "" - external get_mtu : debug_info -> name:iface -> int = "" - external get_capabilities : debug_info -> name:iface -> string list = "" - external is_connected : debug_info -> name:iface -> bool = "" - external is_physical : debug_info -> name:iface -> bool = "" - external has_vlan: debug_info -> name:iface -> vlan:int -> bool = "" - external bring_down : debug_info -> name:iface -> unit = "" - external set_persistent : debug_info -> name:iface -> value:bool -> unit = "" - external make_config : debug_info -> ?conservative:bool -> config:(iface * interface_config_t) list-> unit -> unit = "" -end +type errors = + | Script_missing of string (** [Script_missing (script)] is reported if unable to find [script] *) + | Script_error of (string * string) list (** [Script_error ([(key * value); ...])] is reported when error occurs when executing script, the [key] and [value] indicates the information about the script and the error *) + | Read_error of string (** [Read_error (file)] is reported when error occurs when reading [file] *) + | Write_error of string (** [Write_error (file)] is reported when error occurs when writing [file] *) + | Not_implemented (** [Not_implemented] is reported if the interface is not implemented *) + | Vlan_in_use of (string * int) (** [Vlan_in_use (bridge, vlan_id)] is reported when [vlan_id] on [bridge] is inuse *) + | PVS_proxy_connection_error (** [PVS_proxy_connection_error] is reported when unable to connect PVS proxy *) + | Internal_error of string + | Unknown_error (** The default variant for forward compatibility. *) +[@@default Unknown_error] +[@@deriving rpcty] + +exception Network_error of errors + +let err = Error.{ + def = errors; + raiser = (function | e -> raise (Network_error e)); + matcher = (function + | Network_error e -> Some e + | e -> Some (Internal_error (Printexc.to_string e))) + } -type kind = Openvswitch | Bridge -type bond_mode = Balance_slb | Active_backup | Lacp -type fail_mode = Standalone | Secure +(** {2 API functions} *) -let string_of_kind = function - | Openvswitch -> "openvswitch" - | Bridge -> "bridge" - -module Bridge = struct - external get_all : debug_info -> unit -> bridge list = "" - external create : debug_info -> ?vlan:(bridge * int) -> - ?mac:string -> ?igmp_snooping:bool -> ?other_config:(string * string) list -> name:bridge -> unit -> unit = "" - external destroy : debug_info -> ?force:bool -> name:bridge -> unit -> unit = "" - external get_kind : debug_info -> unit -> kind = "" - external get_all_ports : debug_info -> ?from_cache:bool -> unit -> (port * iface list) list = "" - external get_all_bonds : debug_info -> ?from_cache:bool -> unit -> (port * iface list) list = "" - external set_persistent : debug_info -> name:bridge -> value:bool -> unit = "" - external add_port : debug_info -> ?bond_mac:string -> bridge:bridge -> name:port -> interfaces:iface list -> - ?bond_properties:(string * string) list -> ?kind:port_kind -> unit -> unit = "" - external remove_port : debug_info -> bridge:bridge -> name:port -> unit = "" - external get_interfaces : debug_info -> name:bridge -> iface list = "" - external get_physical_interfaces : debug_info -> name:bridge -> iface list = "" - external make_config : debug_info -> ?conservative:bool -> config:(bridge * bridge_config_t) list-> unit -> unit = "" +module Interface_API(R : RPC) = struct + open R + + (* Define this module here because we will reuse the name `Interface` *) + module Idl_Interface = Interface + + let description = Idl_Interface.{ + name = "Network"; + namespace = Some "Network"; + description = [ + "This interface is used by Xapi and networkd to manage "; + "Xenserver network bridges and devices ."; + ]; + version=(1,0,0); + } + + let implementation = implement description + + let debug_info_p = Param.mk ~description:[ + "an uninterpreted string to associate with the operation." + ] Types.string + + let unit_p = Param.mk Types.unit + + let clear_state = declare + "clear_state" + ["Clear configuration state"] + (unit_p @-> returning unit_p err) + + let reset_state = declare + "reset_state" + ["Reset configuration state"] + (unit_p @-> returning unit_p err) + + let set_gateway_interface = + let name_p = Param.mk ~name:"name" ~description:["gateway name"] iface in + declare + "set_gateway_interface" + ["Set gateway interface"] + (debug_info_p @-> name_p @-> returning unit_p err) + + let set_dns_interface = + let name_p = Param.mk ~name:"name" ~description:["gateway name"] iface in + declare + "set_dns_interface" + ["Set dns interface"] + (debug_info_p @-> name_p @-> returning unit_p err) + + module Interface = struct + let iface_name_p = Param.mk ~name:"name" ~description:["interface name"] iface + + let get_all = + let module T = struct + type _iface_list_t = iface list [@@deriving rpcty] + end in + let iface_list_p = Param.mk ~description:["interface list"] T._iface_list_t in + declare + "Interface.get_all" + ["Get list of all interface names"] + (debug_info_p @-> unit_p @-> returning iface_list_p err) + + let exists = + let result = Param.mk ~description:["existence"] Types.bool in + declare + "Interface.exists" + ["Check interface existence"] + (debug_info_p @-> iface_name_p @-> returning result err) + + let get_mac = + let result = Param.mk ~description:["MAC address"] Types.string in + declare + "Interface.get_mac" + ["Get Mac address of the interface"] + (debug_info_p @-> iface_name_p @-> returning result err) + + let is_up = + let result = Param.mk ~description:["interface is up"] Types.bool in + declare + "Interface.is_up" + ["Check whether the interface is up"] + (debug_info_p @-> iface_name_p @-> returning result err) + + let get_ipv4_addr = + let module T = struct + type _ip_addr_list_t = (Unix.inet_addr * int) list [@@deriving rpcty] + end in + let result = Param.mk ~description:["list of interface IPv4 addresses"] T._ip_addr_list_t in + declare + "Interface.get_ipv4_addr" + ["Get list of IPv4 addresses of the interface"] + (debug_info_p @-> iface_name_p @-> returning result err) + + let set_ipv4_conf = + let conf_p = Param.mk ~description:["IPv4 configuration type"] ipv4 in + declare + "Interface.set_ipv4_conf" + ["Set IPv4 configuration"] + (debug_info_p @-> iface_name_p @-> conf_p @-> returning unit_p err) + + let get_ipv4_gateway = + let module T = struct + type _inet_addr_opt_t = Unix.inet_addr option [@@deriving rpcty] + end in + let result = Param.mk ~description:["gateway address if exists"] T._inet_addr_opt_t in + declare + "Interface.get_ipv4_gateway" + ["Get IPv4 gateway"] + (debug_info_p @-> iface_name_p @-> returning result err) + + let get_ipv6_addr = + let module T = struct + type _ip_addr_list_t = (Unix.inet_addr * int) list [@@deriving rpcty] + end in + let result = Param.mk ~description:["list of interface IPv6 addresses"] T._ip_addr_list_t in + declare + "Interface.get_ipv6_addr" + ["Get IPv6 address"] + (debug_info_p @-> iface_name_p @-> returning result err) + + let get_dns = + let module T = struct + type _dns_info_t = Unix.inet_addr list * string list [@@deriving rpcty] + end in + let result = Param.mk ~description:["DNS servers information"] T._dns_info_t in + declare + "Interface.get_dns" + ["Get DNS"] + (debug_info_p @-> iface_name_p @-> returning result err) + + let get_mtu = + let result = Param.mk ~description:["MTU"] Types.int in + declare + "Interface.get_mtu" + ["Get MTU"] + (debug_info_p @-> iface_name_p @-> returning result err) + + let get_capabilities = + let module T = struct + type _capabilities_t = string list [@@deriving rpcty] + end in + let result = Param.mk ~description:["capabilities"] T._capabilities_t in + declare + "Interface.get_capabilities" + ["Get capabilities on the interface"] + (debug_info_p @-> iface_name_p @-> returning result err) + + let is_connected = + let result = Param.mk ~description:["whether interface is connected"] Types.bool in + declare + "Interface.is_connected" + ["Check whether interface is connected"] + (debug_info_p @-> iface_name_p @-> returning result err) + + let is_physical = + let result = Param.mk ~description:["whether interface is physical"] Types.bool in + declare + "Interface.is_physical" + ["Check whether interface is physical"] + (debug_info_p @-> iface_name_p @-> returning result err) + + let has_vlan = + let vlan_p = Param.mk ~name:"vlan" ~description:["vlan id"] Types.int in + let result = Param.mk ~description:["whether interface has vlan"] Types.bool in + declare + "Interface.has_vlan" + ["Check whether interface has vlan"] + (debug_info_p @-> iface_name_p @-> vlan_p @-> returning result err) + + let bring_down = + declare + "Interface.bring_down" + ["Bring PIF down"] + (debug_info_p @-> iface_name_p @-> returning unit_p err) + + let set_persistent = + let value_p = Param.mk ~name:"value" ~description:["persistent or not"] Types.bool in + declare + "Interface.set_persistent" + ["Make PIF to persistent or not"] + (debug_info_p @-> iface_name_p @-> value_p @-> returning unit_p err) + + let make_config = + let module T = struct + type _conservative_t = bool [@@deriving rpcty] + type _iface_config_list_t = (iface * interface_config_t) list [@@deriving rpcty] + end in + let conservative_p = Param.mk ~name:"conservative" ~description:["conservative"] T._conservative_t in + let config_p = Param.mk ~name:"config" ~description:["list of interface configuration"] T._iface_config_list_t in + declare + "Interface.make_config" + ["Make interface configuration"] + (debug_info_p @-> conservative_p @-> config_p @-> returning unit_p err) + end + + module Bridge = struct + let get_all = + let module T = struct + type _bridge_list_t = bridge list [@@deriving rpcty] + end in + let result = Param.mk ~description:["bridge list"] T._bridge_list_t in + declare + "Bridge.get_all" + ["Get all bridges"] + (debug_info_p @-> unit_p @-> returning result err) + + let create = + let module T = struct + type _vlan_opt_t = (bridge * int) option [@@deriving rpcty] + type _mac_opt_t = string option [@@deriving rpcty] + type _igmp_snooping_opt_t = bool option [@@deriving rpcty] + type _other_config_opt_t = (string * string) list option [@@deriving rpcty] + end in + let vlan_p = Param.mk ~name:"vlan" ~description:["vlan"] T._vlan_opt_t in + let mac_p = Param.mk ~name:"mac" ~description:["MAC"] T._mac_opt_t in + let igmp_snooping_p = Param.mk ~name:"igmp_snooping" T._igmp_snooping_opt_t in + let other_config_p = Param.mk ~name:"other_config" T._other_config_opt_t in + let name_p = Param.mk ~name:"name" ~description:["bridge name"] bridge in + declare + "Bridge.create" + ["Create bridge"] + (debug_info_p @-> vlan_p @-> mac_p @-> igmp_snooping_p @-> other_config_p @-> name_p @-> returning unit_p err) + + let destroy = + let module T = struct + type _force_t = bool [@@deriving rpcty] + end in + let force_p = Param.mk ~name:"force" ~description:["force"] T._force_t in + let name_p = Param.mk ~name:"name" ~description:["name"] bridge in + declare + "Bridge.destroy" + ["Destroy bridge"] + (debug_info_p @-> force_p @-> name_p @-> returning unit_p err) + + let get_kind = + let result = Param.mk ~description:["backend kind"] kind in + declare + "Bridge.get_kind" + ["Get backend kind"] + (debug_info_p @-> unit_p @-> returning result err) + + let get_all_ports = + let module T = struct + type _from_cache_t = bool [@@deriving rpcty] + type _all_ports_t = (port * iface list) list [@@deriving rpcty] + end in + let from_cache_p = Param.mk ~name:"from_cache" ~description:["whether from cache"] T._from_cache_t in + let result = Param.mk ~description:["all ports"] T._all_ports_t in + declare + "Bridge.get_all_ports" + ["Get all ports"] + (debug_info_p @-> from_cache_p @-> returning result err) + + let get_all_bonds = + let module T = struct + type _from_cache_t = bool [@@deriving rpcty] + type _all_bonds_t = (port * iface list) list [@@deriving rpcty] + end in + let from_cache_p = Param.mk ~name:"from_cache" ~description:["whether from cache"] T._from_cache_t in + let result = Param.mk ~description:["all bonds"] T._all_bonds_t in + declare + "Bridge.get_all_bonds" + ["get all bonds"] + (debug_info_p @-> from_cache_p @-> returning result err) + + let set_persistent = + let name_p = Param.mk ~name:"name" ~description:["bridge name"] bridge in + let value_p = Param.mk ~name:"value" ~description:["persistent value"] Types.bool in + declare + "Bridge.set_persistent" + ["Make bridge to persistent or not"] + (debug_info_p @-> name_p @-> value_p @-> returning unit_p err) + + let add_port = + let module T = struct + type _bond_mac_opt_t = string option [@@deriving rpcty] + type _interfaces_t = iface list [@@deriving rpcty] + type _bond_properties_opt_t = (string * string) list option [@@deriving rpcty] + type _kind_opt_t = port_kind option [@@deriving rpcty] + end in + let bond_mac_p = Param.mk ~name:"bond_mac" ~description:["bond MAC"] T._bond_mac_opt_t in + let bridge_p = Param.mk ~name:"bridge" ~description:["bridge name"] bridge in + let name_p = Param.mk ~name:"name" ~description:["port name"] port in + let interfaces_p = Param.mk ~name:"interfaces" ~description:["interfaces"] T._interfaces_t in + let bond_properties_p = Param.mk ~name:"bond_properties" ~description:["bond properties"] T._bond_properties_opt_t in + let kind_p = Param.mk ~name:"kind" ~description:["port kind"] T._kind_opt_t in + declare + "Bridge.add_port" + ["Add port"] + (debug_info_p @-> bond_mac_p @-> bridge_p @-> name_p @-> interfaces_p @-> bond_properties_p @-> kind_p @-> returning unit_p err) + + let remove_port = + let bridge_p = Param.mk ~name:"bridge" ~description:["bridge name"] bridge in + let name_p = Param.mk ~name:"name" ~description:["port name"] port in + declare + "Bridge.remove_port" + ["Remove port"] + (debug_info_p @-> bridge_p @-> name_p @-> returning unit_p err) + + let get_interfaces = + let module T = struct + type _iface_list_t = iface list [@@deriving rpcty] + end in + let name_p = Param.mk ~name:"name" ~description:["bridge name"] bridge in + let result = Param.mk ~description:["interface list"] T._iface_list_t in + declare + "Bridge.get_interfaces" + ["Get interfaces"] + (debug_info_p @-> name_p @-> returning result err) + + let get_physical_interfaces = + let module T = struct + type _iface_list_t = iface list [@@deriving rpcty] + end in + let name_p = Param.mk ~name:"name" ~description:["bridge name"] bridge in + let result = Param.mk ~description:["interface list"] T._iface_list_t in + declare + "Bridge.get_physical_interfaces" + ["Get physical interfaces"] + (debug_info_p @-> name_p @-> returning result err) + + let make_config = + let module T = struct + type _conservative_t = bool [@@deriving rpcty] + type _config_t = (bridge * bridge_config_t) list [@@deriving rpcty] + end in + let conservative_p = Param.mk ~name:"conservative" T._conservative_t in + let config_p = Param.mk ~name:"config" T._config_t in + declare + "Bridge.make_config" + ["Make bridge configuration"] + (debug_info_p @-> conservative_p @-> config_p @-> returning unit_p err) + end + + module PVS_proxy = struct + module Server = struct + type t = { + uuid: string; + addresses: Unix.inet_addr list; + first_port: int; + last_port: int; + } [@@deriving rpcty] + end + + module Client = struct + type t = { + uuid: string; + mac: string; + interface: string; + prepopulate: bool; + } [@@deriving rpcty] + end + + type t = { + site_uuid: string; + site_name: string; + servers: Server.t list; + clients: Client.t list; + vdi: string; + } [@@deriving rpcty] + + let configure_site = + let pvs_p = Param.mk ~description:["proxy"] t in + declare + "PVS_proxy.configure_site" + ["Configure site"] + (debug_info_p @-> pvs_p @-> returning unit_p err) + + let remove_site = + let site_p = Param.mk ~description:["site name"] Types.string in + declare + "PVS_proxy.remove_site" + ["Remove site"] + (debug_info_p @-> site_p @-> returning unit_p err) + end end -exception PVS_proxy_connection_error - -module PVS_proxy = struct - module Server = struct - type t = { - uuid: string; - addresses: Unix.inet_addr list; - first_port: int; - last_port: int; - } - end - - module Client = struct - type t = { - uuid: string; - mac: string; - interface: string; - prepopulate: bool; - } - end - - type t = { - site_uuid: string; - site_name: string; - servers: Server.t list; - clients: Client.t list; - vdi: string; - } - - external configure_site : debug_info -> PVS_proxy.t -> unit = "" - external remove_site : debug_info -> string -> unit = "" -end diff --git a/network/network_stats.ml b/network/network_stats.ml index 44d4b8a3..332d0e3c 100644 --- a/network/network_stats.ml +++ b/network/network_stats.ml @@ -29,42 +29,42 @@ let checksum_bytes = 32 let length_bytes = 8 type iface_stats = { - tx_bytes: int64; (* bytes emitted *) - tx_pkts: int64; (* packets emitted *) - tx_errors: int64; (* error emitted *) - rx_bytes: int64; (* bytes received *) - rx_pkts: int64; (* packets received *) - rx_errors: int64; (* error received *) - carrier: bool; - speed: int; - duplex: duplex; - pci_bus_path: string; - vendor_id: string; - device_id: string; - nb_links: int; - links_up: int; - interfaces: iface list; -} [@@deriving rpc] + tx_bytes: int64; (* bytes emitted *) + tx_pkts: int64; (* packets emitted *) + tx_errors: int64; (* error emitted *) + rx_bytes: int64; (* bytes received *) + rx_pkts: int64; (* packets received *) + rx_errors: int64; (* error received *) + carrier: bool; + speed: int; + duplex: duplex; + pci_bus_path: string; + vendor_id: string; + device_id: string; + nb_links: int; + links_up: int; + interfaces: iface list; +} [@@deriving rpcty] let default_stats = { - tx_bytes = 0L; - tx_pkts = 0L; - tx_errors = 0L; - rx_bytes = 0L; - rx_pkts = 0L; - rx_errors = 0L; - carrier = false; - speed = 0; - duplex = Duplex_unknown; - pci_bus_path = ""; - vendor_id = ""; - device_id = ""; - nb_links = 0; - links_up = 0; - interfaces = []; + tx_bytes = 0L; + tx_pkts = 0L; + tx_errors = 0L; + rx_bytes = 0L; + rx_pkts = 0L; + rx_errors = 0L; + carrier = false; + speed = 0; + duplex = Duplex_unknown; + pci_bus_path = ""; + vendor_id = ""; + device_id = ""; + nb_links = 0; + links_up = 0; + interfaces = []; } -type stats_t = (iface * iface_stats) list [@@deriving rpc] +type stats_t = (iface * iface_stats) list [@@deriving rpcty] exception Read_error exception Invalid_magic_string @@ -73,59 +73,61 @@ exception Invalid_length (* Shamelessly stolen from Unixext. *) module File_helpers = struct - (** open a file, and make sure the close is always done *) - let with_file file mode perms f = - let fd = Unix.openfile file mode perms in - let r = - try f fd - with exn -> Unix.close fd; raise exn - in - Unix.close fd; - r + (** open a file, and make sure the close is always done *) + let with_file file mode perms f = + let fd = Unix.openfile file mode perms in + let r = + try f fd + with exn -> Unix.close fd; raise exn + in + Unix.close fd; + r - (** [fd_blocks_fold block_size f start fd] folds [f] over blocks (strings) - from the fd [fd] with initial value [start] *) - let fd_blocks_fold block_size f start fd = - let block = Bytes.create block_size in - let rec fold acc = - let n = Unix.read fd block 0 block_size in - (* Consider making the interface explicitly use Substrings *) - let s = if n = block_size then block else String.sub block 0 n in - if n = 0 then acc else fold (f acc s) in - fold start + (** [fd_blocks_fold block_size f start fd] folds [f] over blocks (strings) + from the fd [fd] with initial value [start] *) + let fd_blocks_fold block_size f start fd = + let block = Bytes.create block_size in + let rec fold acc = + let n = Unix.read fd block 0 block_size in + (* Consider making the interface explicitly use Substrings *) + let s = if n = block_size then block else String.sub block 0 n in + if n = 0 then acc else fold (f acc s) in + fold start - let buffer_of_fd fd = - fd_blocks_fold 1024 (fun b s -> Buffer.add_string b s; b) (Buffer.create 1024) fd + let buffer_of_fd fd = + fd_blocks_fold 1024 (fun b s -> Buffer.add_string b s; b) (Buffer.create 1024) fd - let buffer_of_file file_path = with_file file_path [ Unix.O_RDONLY ] 0 buffer_of_fd + let buffer_of_file file_path = with_file file_path [ Unix.O_RDONLY ] 0 buffer_of_fd - let string_of_file file_path = Buffer.contents (buffer_of_file file_path) + let string_of_file file_path = Buffer.contents (buffer_of_file file_path) end let read_stats () = - let rec retry n = - try - let data = File_helpers.string_of_file stats_file in - if String.sub data 0 magic_bytes <> magic then - raise Invalid_magic_string; - let checksum = String.sub data magic_bytes checksum_bytes in - let length = - try int_of_string ("0x" ^ (String.sub data (magic_bytes + checksum_bytes) length_bytes)) - with _ -> raise Invalid_length - in - let payload = String.sub data (magic_bytes + checksum_bytes + length_bytes) length in - if payload |> Digest.string |> Digest.to_hex <> checksum then - raise Invalid_checksum - else - payload |> Jsonrpc.of_string |> stats_t_of_rpc - with e -> - if n > 0 then begin - Thread.delay retry_delay; - retry (n - 1) - end else - match e with - | Invalid_magic_string | Invalid_length | Invalid_checksum -> raise e - | _ -> raise Read_error - in - retry num_retries + let rec retry n = + try + let data = File_helpers.string_of_file stats_file in + if String.sub data 0 magic_bytes <> magic then + raise Invalid_magic_string; + let checksum = String.sub data magic_bytes checksum_bytes in + let length = + try int_of_string ("0x" ^ (String.sub data (magic_bytes + checksum_bytes) length_bytes)) + with _ -> raise Invalid_length + in + let payload = String.sub data (magic_bytes + checksum_bytes + length_bytes) length in + if payload |> Digest.string |> Digest.to_hex <> checksum then + raise Invalid_checksum + else + match payload |> Jsonrpc.of_string |> Rpcmarshal.unmarshal typ_of_stats_t with + | Result.Ok v -> v + | Result.Error _ -> raise Read_error + with e -> + if n > 0 then begin + Thread.delay retry_delay; + retry (n - 1) + end else + match e with + | Invalid_magic_string | Invalid_length | Invalid_checksum -> raise e + | _ -> raise Read_error + in + retry num_retries