Skip to content

Commit b4d44c3

Browse files
Merge pull request #2596 from simonjbeaumont/ca-106754
CA-106754: Disallow bonding when more than one PIF has an IP config
2 parents 7cc611b + 9f11e83 commit b4d44c3

File tree

3 files changed

+48
-42
lines changed

3 files changed

+48
-42
lines changed

ocaml/idl/api_errors.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ let pif_device_not_found = "PIF_DEVICE_NOT_FOUND"
102102
let pif_already_bonded = "PIF_ALREADY_BONDED"
103103
let pif_cannot_bond_cross_host = "PIF_CANNOT_BOND_CROSS_HOST"
104104
let pif_bond_needs_more_members = "PIF_BOND_NEEDS_MORE_MEMBERS"
105+
let pif_bond_more_than_one_ip = "PIF_BOND_MORE_THAN_ONE_IP"
105106
let pif_configuration_error = "PIF_CONFIGURATION_ERROR"
106107
let pif_is_management_iface = "PIF_IS_MANAGEMENT_INTERFACE"
107108
let pif_incompatible_primary_address_type = "PIF_INCOMPATIBLE_PRIMARY_ADDRESS_TYPE"

ocaml/idl/datamodel.ml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,8 @@ let _ =
517517
~doc:"You cannot bond interfaces across different hosts." ();
518518
error Api_errors.pif_bond_needs_more_members []
519519
~doc:"A bond must consist of at least two member interfaces" ();
520+
error Api_errors.pif_bond_more_than_one_ip []
521+
~doc:"Only one PIF on a bond is allowed to have an IP configuration." ();
520522
error Api_errors.pif_configuration_error [ "PIF"; "msg" ]
521523
~doc:"An unknown error occurred while attempting to configure an interface." ();
522524
error Api_errors.invalid_ip_address_specified [ "parameter" ]

ocaml/xapi/xapi_bond.ml

Lines changed: 45 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -270,15 +270,53 @@ let create ~__context ~network ~members ~mAC ~mode ~properties =
270270
let bond = Ref.make () in
271271

272272
with_local_lock (fun () ->
273-
(* Validation constraints: *)
273+
(* Collect information *)
274+
let member_networks = List.map (fun pif -> Db.PIF.get_network ~__context ~self:pif) members in
275+
276+
let local_vifs = get_local_vifs ~__context host member_networks in
277+
let local_vlans = List.concat (List.map (fun pif -> Db.PIF.get_VLAN_slave_of ~__context ~self:pif) members) in
278+
let local_tunnels = List.concat (List.map (fun pif -> Db.PIF.get_tunnel_transport_PIF_of ~__context ~self:pif) members) in
279+
280+
let management_pif =
281+
match List.filter (fun p -> Db.PIF.get_management ~__context ~self:p) members with
282+
| management_pif :: _ -> Some management_pif
283+
| [] -> None
284+
in
285+
286+
let pifs_with_ip_conf =
287+
List.filter (fun self ->
288+
Db.PIF.get_ip_configuration_mode ~__context ~self <> `None
289+
) members in
290+
291+
(* The primary slave is the management PIF, or the first member with
292+
* IP configuration, or otherwise simply the first member in the list. *)
293+
let primary_slave =
294+
match management_pif, pifs_with_ip_conf, members with
295+
| Some management_pif, _, _ -> management_pif
296+
| None, pif_with_ip::_, _ -> pif_with_ip
297+
| None, [], pif::_ -> pif
298+
| None, [], [] ->
299+
raise (Api_errors.Server_error(Api_errors.pif_bond_needs_more_members, []))
300+
in
301+
let mAC =
302+
if mAC <> "" then
303+
mAC
304+
else
305+
Db.PIF.get_MAC ~__context ~self:primary_slave
306+
in
307+
let disallow_unplug =
308+
List.fold_left (fun a m -> Db.PIF.get_disallow_unplug ~__context ~self:m || a) false members
309+
in
310+
311+
(* Validate constraints: *)
274312
(* 1. Members must not be in a bond already *)
275313
(* 2. Members must not have a VLAN tag set *)
276314
(* 3. Members must not be tunnel access PIFs *)
277315
(* 4. Referenced PIFs must be on the same host *)
278-
(* 5. There must be more than one member for the bond ( ** disabled for now) *)
279-
(* 6. Members must not be the management interface if HA is enabled *)
280-
(* 7. Members must be PIFs that are managed by xapi *)
281-
(* 8. Members must have the same PIF properties *)
316+
(* 5. Members must not be the management interface if HA is enabled *)
317+
(* 6. Members must be PIFs that are managed by xapi *)
318+
(* 7. Members must have the same PIF properties *)
319+
(* 8. Only the primary PIF should have a non-None IP configuration *)
282320
List.iter (fun self ->
283321
let bond = Db.PIF.get_bond_slave_of ~__context ~self in
284322
let bonded = try ignore(Db.Bond.get_uuid ~__context ~self:bond); true with _ -> false in
@@ -297,10 +335,6 @@ let create ~__context ~network ~members ~mAC ~mode ~properties =
297335
let hosts = List.map (fun self -> Db.PIF.get_host ~__context ~self) members in
298336
if List.length (List.setify hosts) <> 1
299337
then raise (Api_errors.Server_error (Api_errors.pif_cannot_bond_cross_host, []));
300-
(*
301-
if List.length members < 2
302-
then raise (Api_errors.Server_error (Api_errors.pif_bond_needs_more_members, []));
303-
*)
304338
let pif_properties =
305339
if members = [] then
306340
[]
@@ -313,39 +347,8 @@ let create ~__context ~network ~members ~mAC ~mode ~properties =
313347
else
314348
p
315349
in
316-
317-
(* Collect information *)
318-
let member_networks = List.map (fun pif -> Db.PIF.get_network ~__context ~self:pif) members in
319-
320-
let local_vifs = get_local_vifs ~__context host member_networks in
321-
let local_vlans = List.concat (List.map (fun pif -> Db.PIF.get_VLAN_slave_of ~__context ~self:pif) members) in
322-
let local_tunnels = List.concat (List.map (fun pif -> Db.PIF.get_tunnel_transport_PIF_of ~__context ~self:pif) members) in
323-
324-
let management_pif =
325-
match List.filter (fun p -> Db.PIF.get_management ~__context ~self:p) members with
326-
| management_pif :: _ -> Some management_pif
327-
| [] -> None
328-
in
329-
let primary_slave =
330-
(* The primary slave is the management PIF, or the first member with IP configuration,
331-
* or otherwise simply the first member in the list. *)
332-
match management_pif with
333-
| Some management_pif -> management_pif
334-
| None ->
335-
try
336-
List.hd (List.filter (fun pif -> Db.PIF.get_ip_configuration_mode ~__context ~self:pif <> `None) members)
337-
with _ ->
338-
List.hd members
339-
in
340-
let mAC =
341-
if mAC <> "" then
342-
mAC
343-
else
344-
Db.PIF.get_MAC ~__context ~self:primary_slave
345-
in
346-
let disallow_unplug =
347-
List.fold_left (fun a m -> Db.PIF.get_disallow_unplug ~__context ~self:m || a) false members
348-
in
350+
if List.length pifs_with_ip_conf > 1
351+
then raise Api_errors.(Server_error (pif_bond_more_than_one_ip, []));
349352

350353
(* Create master PIF and Bond objects *)
351354
let device = choose_bond_device_name ~__context ~host in

0 commit comments

Comments
 (0)