Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion ocaml/idl/datamodel.ml
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,17 @@ let _ =
error Api_errors.user_is_not_local_superuser [ "msg" ]
~doc:"Only the local superuser can execute this operation" ();

(* SR-IOV errors *)
error Api_errors.network_sriov_already_enabled ["PIF"]
~doc:"The PIF selected for the SR-IOV network is already enabled" ();
error Api_errors.network_sriov_enable_failed ["PIF"; "msg"]
~doc:"Failed to enable SR-IOV on PIF" ();
error Api_errors.network_sriov_disable_failed ["PIF"; "msg"]
~doc:"Failed to disable SR-IOV on PIF" ();
error Api_errors.network_has_incompatible_sriov_pifs ["PIF"; "network"]
~doc:"The PIF is not compatible with the selected SR-IOV network" ();
error Api_errors.network_is_not_sriov_compatible ["network"]
~doc:"The network is not compatible with sriov" ();
(* PIF/VIF/Network errors *)
error Api_errors.network_unmanaged [ "network" ]
~doc:"The network is not managed by xapi." ();
Expand All @@ -573,9 +584,12 @@ let _ =
~doc:"You tried to add a purpose to a network but the new purpose is not compatible with an existing purpose of the network or other networks." ();
error Api_errors.pif_is_physical ["PIF"]
~doc:"You tried to destroy a PIF, but it represents an aspect of the physical host configuration, and so cannot be destroyed. The parameter echoes the PIF handle you gave." ();
error Api_errors.pif_is_not_physical ["PIF"]
~doc:"You tried to perform an operation which is only available on physical PIF" ();
error Api_errors.pif_is_vlan ["PIF"]
~doc:"You tried to create a VLAN on top of another VLAN - use the underlying physical PIF/bond instead" ();

error Api_errors.pif_is_sriov_logical ["PIF"]
~doc:"You tried to create a bond on top of a network SR-IOV logical PIF - use the underlying physical PIF instead" ();
error Api_errors.pif_vlan_exists ["PIF"]
~doc:"You tried to create a PIF, but it already exists." ();
error Api_errors.pif_vlan_still_exists [ "PIF" ]
Expand Down Expand Up @@ -608,6 +622,8 @@ let _ =
~doc:"The operation you requested cannot be performed because the specified PIF has FCoE SR in use." ();
error Api_errors.pif_unmanaged [ "PIF" ]
~doc:"The operation you requested cannot be performed because the specified PIF is not managed by xapi." ();
error Api_errors.pif_is_not_sriov_capable [ "PIF" ]
~doc:"The selected PIF is not capable of network SR-IOV" ();
error Api_errors.pif_has_no_network_configuration [ "PIF" ]
~doc:"PIF has no IP configuration (mode currently set to 'none')" ();
error Api_errors.pif_has_no_v6_network_configuration [ "PIF" ]
Expand All @@ -620,6 +636,10 @@ let _ =
~doc:"This PIF is a bond slave and cannot have a VLAN on it." ();
error Api_errors.cannot_add_tunnel_to_bond_slave ["PIF"]
~doc:"This PIF is a bond slave and cannot have a tunnel on it." ();
error Api_errors.cannot_add_tunnel_to_sriov_logical ["PIF"]
~doc:"This is a network SR-IOV logical PIF and cannot have a tunnel on it." ();
error Api_errors.cannot_add_tunnel_to_vlan_on_sriov_logical ["PIF"]
~doc:"This is a vlan PIF on network SR-IOV and cannot have a tunnel on it." ();
error Api_errors.cannot_change_pif_properties ["PIF"]
~doc:"This properties of this PIF cannot be changed. Only the properties of non-bonded physical PIFs, or bond masters can be changed." ();
error Api_errors.incompatible_pif_properties []
Expand Down
10 changes: 10 additions & 0 deletions ocaml/xapi-consts/api_errors.ml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@ let device_attach_timeout = "DEVICE_ATTACH_TIMEOUT"
let device_detach_timeout = "DEVICE_DETACH_TIMEOUT"
let device_detach_rejected = "DEVICE_DETACH_REJECTED"

let network_sriov_already_enabled = "NETWORK_SRIOV_ALREADY_ENABLED"
let network_sriov_enable_failed = "NETWORK_SRIOV_ENABLE_FAILED"
let network_sriov_disable_failed = "NETWORK_SRIOV_DISABLE_FAILED"
let network_is_not_sriov_compatible = "NETWORK_IS_NOT_SRIOV_COMPATIBLE"
let network_has_incompatible_sriov_pifs = "NETWORK_HAS_INCOMPATIBLE_SRIOV_PIFS"
let operation_not_allowed = "OPERATION_NOT_ALLOWED"
let operation_blocked = "OPERATION_BLOCKED"
let network_already_connected = "NETWORK_ALREADY_CONNECTED"
Expand All @@ -103,7 +108,9 @@ let network_incompatible_purposes = "NETWORK_INCOMPATIBLE_PURPOSES"

let cannot_destroy_system_network = "CANNOT_DESTROY_SYSTEM_NETWORK"
let pif_is_physical = "PIF_IS_PHYSICAL"
let pif_is_not_physical = "PIF_IS_NOT_PHYSICAL"
let pif_is_vlan = "PIF_IS_VLAN"
let pif_is_sriov_logical = "PIF_IS_SRIOV_LOGICAL"
let pif_vlan_exists = "PIF_VLAN_EXISTS"
let pif_vlan_still_exists = "PIF_VLAN_STILL_EXISTS"
let vlan_in_use = "VLAN_IN_USE"
Expand All @@ -120,9 +127,12 @@ let pif_not_present = "PIF_NOT_PRESENT"
let pif_does_not_allow_unplug = "PIF_DOES_NOT_ALLOW_UNPLUG"
let pif_has_fcoe_sr_in_use = "PIF_HAS_FCOE_SR_IN_USE"
let pif_unmanaged = "PIF_UNMANAGED"
let pif_is_not_sriov_capable = "PIF_IS_NOT_SRIOV_CAPABLE"
let cannot_plug_bond_slave = "CANNOT_PLUG_BOND_SLAVE"
let cannot_add_vlan_to_bond_slave = "CANNOT_ADD_VLAN_TO_BOND_SLAVE"
let cannot_add_tunnel_to_bond_slave = "CANNOT_ADD_TUNNEL_TO_BOND_SLAVE"
let cannot_add_tunnel_to_sriov_logical = "CANNOT_ADD_TUNNEL_TO_SRIOV_LOGICAL"
let cannot_add_tunnel_to_vlan_on_sriov_logical = "CANNOT_ADD_TUNNEL_TO_VLAN_ON_SRIOV_LOGICAL"
let cannot_change_pif_properties = "CANNOT_CHANGE_PIF_PROPERTIES"
let incompatible_pif_properties = "INCOMPATIBLE_PIF_PROPERTIES"
let slave_requires_management_iface = "SLAVE_REQUIRES_MANAGEMENT_INTERFACE"
Expand Down
52 changes: 34 additions & 18 deletions ocaml/xapi/nm.ml
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,8 @@ let rec create_bridges ~__context pif_rc net_rc =
let other_config = determine_other_config ~__context pif_rc net_rc in
let persistent = is_dom0_interface pif_rc in
let igmp_snooping = Some (Db.Pool.get_igmp_snooping_enabled ~__context ~self:(Helpers.get_pool ~__context)) in
match Xapi_pif_helpers.get_pif_type pif_rc with
let open Xapi_pif_helpers in
match get_pif_type pif_rc with
| Tunnel_access _ ->
[],
[net_rc.API.network_bridge, {default_bridge with bridge_mac=(Some pif_rc.API.pIF_MAC);
Expand Down Expand Up @@ -276,10 +277,11 @@ let rec create_bridges ~__context pif_rc net_rc =
igmp_snooping; other_config; persistent_b=persistent}],
[pif_rc.API.pIF_device, {default_interface with mtu; ethtool_settings; ethtool_offload; persistent_i=persistent}]
| Network_sriov_logical _ ->
raise (Api_errors.Server_error (Api_errors.internal_error, ["Should not create bridge for SRIOV logical PIF"]))
raise Api_errors.(Server_error (internal_error, ["Should not create bridge for SRIOV logical PIF"]))

let rec destroy_bridges ~__context ~force pif_rc bridge =
match Xapi_pif_helpers.get_pif_type pif_rc with
let open Xapi_pif_helpers in
match get_pif_type pif_rc with
| Tunnel_access _ ->
[bridge, false]
| VLAN_untagged vlan ->
Expand All @@ -296,7 +298,7 @@ let rec destroy_bridges ~__context ~force pif_rc bridge =
| Physical _ ->
[bridge, false]
| Network_sriov_logical _ ->
raise (Api_errors.Server_error (Api_errors.internal_error, ["Should not destroy bridge for SRIOV logical PIF"]))
raise Api_errors.(Server_error (internal_error, ["Should not destroy bridge for SRIOV logical PIF"]))

let determine_static_routes net_rc =
if List.mem_assoc "static-routes" net_rc.API.network_other_config then
Expand All @@ -309,8 +311,17 @@ let determine_static_routes net_rc =

let bring_pif_up ~__context ?(management_interface=false) (pif: API.ref_PIF) =
with_local_lock (fun () ->
let dbg = Context.string_of_task __context in
let rc = Db.PIF.get_record ~__context ~self:pif in
let open Xapi_pif_helpers in
match get_pif_topo ~__context ~pif_rec:rc with
| Network_sriov_logical _ :: _ ->
Xapi_network_sriov_helpers.sriov_bring_up ~__context ~self:pif
| VLAN_untagged _ :: Network_sriov_logical sriov :: _ ->
let sriov_logical_pif = Db.Network_sriov.get_logical_PIF ~__context ~self:sriov in
let currently_attached = Db.PIF.get_currently_attached ~__context ~self:sriov_logical_pif in
Db.PIF.set_currently_attached ~__context ~self:pif ~value:currently_attached
| _ ->
let dbg = Context.string_of_task __context in
let net_rc = Db.Network.get_record ~__context ~self:rc.API.pIF_network in
let bridge = net_rc.API.network_bridge in

Expand Down Expand Up @@ -463,17 +474,22 @@ let bring_pif_up ~__context ?(management_interface=false) (pif: API.ref_PIF) =

let bring_pif_down ~__context ?(force=false) (pif: API.ref_PIF) =
with_local_lock (fun () ->
Network.transform_networkd_exn pif (fun () ->
let dbg = Context.string_of_task __context in
let rc = Db.PIF.get_record ~__context ~self:pif in
debug "Making sure that PIF %s down" rc.API.pIF_uuid;

let bridge = Db.Network.get_bridge ~__context ~self:rc.API.pIF_network in
let cleanup = destroy_bridges ~__context ~force rc bridge in
List.iter (fun (name, force) -> Net.Bridge.destroy dbg ~name ~force ()) cleanup;
Net.Interface.set_persistent dbg ~name:bridge ~value:false;

Db.PIF.set_currently_attached ~__context ~self:pif ~value:false
)
let rc = Db.PIF.get_record ~__context ~self:pif in
let open Xapi_pif_helpers in
match get_pif_topo ~__context ~pif_rec:rc with
| Network_sriov_logical _ :: _ ->
Xapi_network_sriov_helpers.sriov_bring_down ~__context ~self:pif
| VLAN_untagged _ :: Network_sriov_logical _ :: _ ->
Db.PIF.set_currently_attached ~__context ~self:pif ~value:false
| _ ->
Network.transform_networkd_exn pif (fun () ->
let dbg = Context.string_of_task __context in
debug "Making sure that PIF %s down" rc.API.pIF_uuid;

let bridge = Db.Network.get_bridge ~__context ~self:rc.API.pIF_network in
let cleanup = destroy_bridges ~__context ~force rc bridge in
List.iter (fun (name, force) -> Net.Bridge.destroy dbg ~name ~force ()) cleanup;
Net.Interface.set_persistent dbg ~name:bridge ~value:false;
Db.PIF.set_currently_attached ~__context ~self:pif ~value:false
)
)

3 changes: 3 additions & 0 deletions ocaml/xapi/suite.ml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ let base_suite =
Test_extauth_plugin_ADpbis.test;
Test_guest_agent.test;
Test_vlan.test;
Test_tunnel.test;
Test_bond.test;
Test_network_sriov.test;
Test_xapi_vbd_helpers.test;
Test_sr_update_vdis.test;
Test_network_event_loop.test;
Expand Down
125 changes: 125 additions & 0 deletions ocaml/xapi/test_bond.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
(*
* Copyright (C) Citrix Systems Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; version 2.1 only. with the special
* exception on linking described in file LICENSE.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*)

open OUnit
open Test_common

let gen_members = mknlist 2

let test_create_on_unmanaged_pif () =
let __context = make_test_database () in
let host = make_host ~__context () in
let create_member = create_physical_pif ~__context ~host ~managed:false in
let network = make_network ~__context () in
let members = gen_members create_member in
assert_raises_api_error
Api_errors.pif_unmanaged
~args:[Ref.string_of (List.hd members)]
(fun () -> Xapi_bond.create ~__context ~network ~members ~mAC:"ff:ff:ff:ff:ff:ff" ~mode:`activebackup ~properties:[])

let test_create_network_already_connected () =
let __context = make_test_database () in
let host = make_host ~__context () in
let network = make_network ~__context () in
let connected_pif = create_physical_pif ~__context ~network ~host () in
let create_member = create_physical_pif ~__context ~host in
let members = gen_members create_member in
assert_raises_api_error
Api_errors.network_already_connected
~args:[Ref.string_of host; Ref.string_of connected_pif]
(fun () -> Xapi_bond.create ~__context ~network ~members ~mAC:"ff:ff:ff:ff:ff:ff" ~mode:`activebackup ~properties:[])

let test_create_member_is_bond_slave () =
let __context = make_test_database () in
let host = make_host ~__context () in
let network = make_network ~__context () in
let create_member () =
let members = gen_members (create_physical_pif ~__context ~host) in
let _ = create_bond_pif ~__context ~host ~members () in
List.hd members
in
let members = gen_members create_member in
assert_raises_api_error
Api_errors.pif_already_bonded
~args:[Ref.string_of (List.hd members)]
(fun () -> Xapi_bond.create ~__context ~network ~members ~mAC:"ff:ff:ff:ff:ff:ff" ~mode:`activebackup ~properties:[])

let test_create_member_is_vlan_master_on_physical () =
let __context = make_test_database () in
let host = make_host ~__context () in
let network = make_network ~__context () in
let create_member () =
let physical_PIF = create_physical_pif ~__context ~host () in
create_vlan_pif ~__context ~host ~pif:physical_PIF ~vlan:1L ()
in
let members = gen_members create_member in
assert_raises_api_error
Api_errors.pif_vlan_exists
~args:[Db.PIF.get_device_name ~__context ~self:(List.hd members)]
(fun () -> Xapi_bond.create ~__context ~network ~members ~mAC:"ff:ff:ff:ff:ff:ff" ~mode:`activebackup ~properties:[])

let test_create_member_is_vlan_master_on_sriov () =
let __context = make_test_database () in
let host = make_host ~__context () in
let network = make_network ~__context () in
let create_member () =
let physical_PIF = create_physical_pif ~__context ~host () in
let sriov_logical_PIF = create_sriov_pif ~__context ~pif:physical_PIF () in
create_vlan_pif ~__context ~host ~pif:sriov_logical_PIF ~vlan:1L ()
in
let members = gen_members create_member in
assert_raises_api_error
Api_errors.pif_vlan_exists
~args:[Db.PIF.get_device_name ~__context ~self:(List.hd members)]
(fun () -> Xapi_bond.create ~__context ~network ~members ~mAC:"ff:ff:ff:ff:ff:ff" ~mode:`activebackup ~properties:[])

let test_create_member_is_sriov_logical () =
let __context = make_test_database () in
let host = make_host ~__context () in
let network = make_network ~__context () in
let create_member () =
let physical_PIF = create_physical_pif ~__context ~host () in
create_sriov_pif ~__context ~pif:physical_PIF ()
in
let members = gen_members create_member in
assert_raises_api_error
Api_errors.pif_is_sriov_logical
~args:[Ref.string_of (List.hd members)]
(fun () -> Xapi_bond.create ~__context ~network ~members ~mAC:"ff:ff:ff:ff:ff:ff" ~mode:`activebackup ~properties:[])

let test_create_member_is_tunnel_access () =
let __context = make_test_database () in
let host = make_host ~__context () in
let network = make_network ~__context () in
let create_member () =
let transport_PIF = create_physical_pif ~__context ~host () in
create_tunnel_pif ~__context ~host ~pif:transport_PIF ()
in
let members = gen_members create_member in
assert_raises_api_error
Api_errors.is_tunnel_access_pif
~args:[Ref.string_of (List.hd members)]
(fun () -> Xapi_bond.create ~__context ~network ~members ~mAC:"ff:ff:ff:ff:ff:ff" ~mode:`activebackup ~properties:[])

let test =
"test_bond" >:::
[
"test_create_on_unmanaged_pif" >:: test_create_on_unmanaged_pif;
"test_create_network_already_connected" >:: test_create_network_already_connected;
"test_create_member_is_bond_slave" >:: test_create_member_is_bond_slave;
"test_create_member_is_vlan_master_on_physical" >:: test_create_member_is_vlan_master_on_physical;
"test_create_member_is_vlan_master_on_sriov" >:: test_create_member_is_vlan_master_on_sriov;
"test_create_member_is_sriov_logical" >:: test_create_member_is_sriov_logical;
"test_create_member_is_tunnel_access" >:: test_create_member_is_tunnel_access;
]
53 changes: 53 additions & 0 deletions ocaml/xapi/test_common.ml
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,14 @@ let make_pif ~__context ~network ~host ?(device="eth0") ?(mAC="C0:FF:EE:C0:FF:EE
let make_vlan ~__context ~tagged_PIF ~untagged_PIF ~tag ?(other_config=[]) () =
Xapi_vlan.pool_introduce ~__context ~tagged_PIF ~untagged_PIF ~tag ~other_config

let make_network_sriov = Xapi_network_sriov.create_internal

let make_bond ~__context ?(ref=Ref.make ()) ?(uuid=make_uuid ()) ~master ?(other_config=[]) ?(primary_slave=Ref.null) ?(mode=`activebackup) ?(properties=[]) () =
Db.Bond.create ~__context ~ref ~uuid ~master ~other_config ~primary_slave ~mode ~properties ~links_up:0L;
ref

let make_tunnel = Xapi_tunnel.create_internal

let make_network ~__context ?(name_label="net") ?(name_description="description") ?(mTU=1500L)
?(other_config=[]) ?(bridge="xenbr0") ?(managed=true) ?(purpose=[]) () =
Xapi_network.pool_introduce ~__context ~name_label ~name_description ~mTU ~other_config ~bridge ~managed ~purpose
Expand Down Expand Up @@ -415,3 +423,48 @@ let make_client_params ~__context =
session_id
in
(rpc, session_id)

let create_physical_pif ~__context ~host ?network ?(bridge="xapi0") ?(managed=true) () =
let network = match network with
| Some network -> network
| None -> make_network ~__context ~bridge ()
in
make_pif ~__context ~network ~host ~managed ()

let create_vlan_pif ~__context ~host ~vlan ~pif ?(bridge="xapi0") ()=
let network = make_network ~__context ~bridge () in
let vlan_pif = make_pif ~__context ~network ~host ~vLAN:vlan ~physical:false () in
let _ = make_vlan ~__context ~tagged_PIF:pif ~untagged_PIF:vlan_pif ~tag:vlan () in
vlan_pif

let create_tunnel_pif ~__context ~host ~pif ?(bridge="xapi0") () =
let network = make_network ~__context ~bridge () in
let tunnel, access_pif = make_tunnel ~__context ~transport_PIF:pif ~network ~host in
access_pif

let create_sriov_pif ~__context ~pif ?network ?(bridge="xapi0") () =
let sriov_network = match network with
| Some network -> network
| None -> make_network ~__context ~bridge ()
in
let physical_rec = Db.PIF.get_record ~__context ~self:pif in
let sriov, sriov_logical_pif = make_network_sriov ~__context ~physical_PIF:pif ~physical_rec ~network:sriov_network in
sriov_logical_pif

let create_bond_pif ~__context ~host ~members ?(bridge="xapi0") () =
let network = make_network ~__context ~bridge () in
let bond_master = make_pif ~__context ~network ~host ~physical:false () in
let bond = make_bond ~__context ~master:bond_master () in
List.iter (fun member ->
Db.PIF.set_bond_slave_of ~__context ~self:member ~value:bond
) members;
bond_master

let mknlist n f =
let rec aux result = function
| 0 -> result
| n ->
let result = f () :: result in
aux result (n-1)
in
aux [] n
Loading