Skip to content

Commit ed2f3e8

Browse files
committed
Merge pull request #40 from robhoes/ucs
CA-115557: networkd: implement enic workaround
2 parents 250b12b + c5ebbb8 commit ed2f3e8

File tree

2 files changed

+66
-29
lines changed

2 files changed

+66
-29
lines changed

lib/network_utils.ml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,13 @@ module Sysfs = struct
6666
let all = Array.to_list (Sys.readdir "/sys/class/net") in
6767
List.filter (fun name -> Sys.is_directory ("/sys/class/net/" ^ name)) all
6868

69+
let list_drivers () =
70+
try
71+
Array.to_list (Sys.readdir "/sys/bus/pci/drivers")
72+
with _ ->
73+
warn "Failed to obtain list of drivers from sysfs";
74+
[]
75+
6976
let getpath dev attr =
7077
Printf.sprintf "/sys/class/net/%s/%s" dev attr
7178

networkd/network_server.ml

Lines changed: 59 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ type context = unit
2626

2727
let network_conf = ref "/etc/xcp/network.conf"
2828
let config : config_t ref = ref empty_config
29+
let backend_kind = ref Openvswitch
2930

3031
let legacy_management_interface_start () =
3132
try
@@ -84,6 +85,13 @@ let set_dns_interface _ dbg ~name =
8485
debug "Setting DNS interface to %s" name;
8586
config := {!config with dns_interface = Some name}
8687

88+
(* The enic driver is for Cisco UCS devices. The current driver adds VLAN0 headers
89+
* to all incoming packets, which confuses certain guests OSes. The workaround
90+
* constitutes adding a VLAN0 Linux device to strip those headers again.
91+
*)
92+
let need_enic_workaround () =
93+
!backend_kind = Bridge && List.mem "enic" (Sysfs.list_drivers ())
94+
8795
module Interface = struct
8896
let get_config name =
8997
get_config !config.interface_config default_interface name
@@ -356,6 +364,17 @@ module Interface = struct
356364
end else
357365
config
358366
in
367+
let config =
368+
if need_enic_workaround () then
369+
List.fold_left (fun accu (name, interface) ->
370+
if (Sysfs.is_physical name && Linux_bonding.get_bond_master_of name = None) || Linux_bonding.is_bond_device name then
371+
(name, interface) :: (Ip.vlan_name name 0, interface) :: accu
372+
else
373+
(name, interface) :: accu
374+
) [] config
375+
else
376+
config
377+
in
359378
debug "** Configuring the following interfaces: %s" (String.concat ", " (List.map (fun (name, _) -> name) config));
360379
let exec f = if conservative then (try f () with _ -> ()) else f () in
361380
List.iter (function (name, ({ipv4_conf; ipv4_gateway; ipv6_conf; ipv6_gateway; ipv4_routes; dns=nameservers,domains; mtu;
@@ -378,7 +397,6 @@ module Interface = struct
378397
end
379398

380399
module Bridge = struct
381-
let kind = ref Openvswitch
382400
let add_default = ref []
383401

384402
let get_config name =
@@ -394,25 +412,25 @@ module Bridge = struct
394412
try
395413
let backend = String.strip String.isspace (Unixext.string_of_file !network_conf) in
396414
match backend with
397-
| "openvswitch" | "vswitch" -> kind := Openvswitch
398-
| "bridge" -> kind := Bridge
415+
| "openvswitch" | "vswitch" -> backend_kind := Openvswitch
416+
| "bridge" -> backend_kind := Bridge
399417
| backend ->
400418
warn "Network backend unknown (%s). Falling back to Open vSwitch." backend;
401-
kind := Openvswitch
419+
backend_kind := Openvswitch
402420
with _ ->
403421
warn "Network-conf file not found. Falling back to Open vSwitch.";
404-
kind := Openvswitch
422+
backend_kind := Openvswitch
405423

406424
let get_bond_links_up _ dbg ~name =
407425
Debug.with_thread_associated dbg (fun () ->
408-
match !kind with
426+
match !backend_kind with
409427
| Openvswitch -> Ovs.get_bond_links_up name
410428
| Bridge -> Proc.get_bond_links_up name
411429
) ()
412430

413431
let get_all _ dbg () =
414432
Debug.with_thread_associated dbg (fun () ->
415-
match !kind with
433+
match !backend_kind with
416434
| Openvswitch -> Ovs.list_bridges ()
417435
| Bridge -> Sysfs.get_all_bridges ()
418436
) ()
@@ -424,7 +442,7 @@ module Bridge = struct
424442
| Some (parent, vlan) -> Printf.sprintf " (VLAN %d on bridge %s)" vlan parent
425443
);
426444
update_config name {(get_config name) with vlan; bridge_mac=mac; other_config};
427-
begin match !kind with
445+
begin match !backend_kind with
428446
| Openvswitch ->
429447
let fail_mode =
430448
if not (List.mem_assoc "vswitch-controller-fail-mode" other_config) then
@@ -499,7 +517,7 @@ module Bridge = struct
499517
let destroy _ dbg ?(force=false) ~name () =
500518
Debug.with_thread_associated dbg (fun () ->
501519
Interface.bring_down () dbg ~name;
502-
match !kind with
520+
match !backend_kind with
503521
| Openvswitch ->
504522
if Ovs.get_vlans name = [] || force then begin
505523
debug "Destroying bridge %s" name;
@@ -532,8 +550,14 @@ module Bridge = struct
532550
Interface.bring_down () dbg ~name:dev;
533551
if Linux_bonding.is_bond_device dev then
534552
Linux_bonding.remove_bond_master dev;
535-
if String.startswith "eth" dev && String.contains dev '.' then
536-
ignore (Ip.destroy_vlan dev)
553+
if (String.startswith "eth" dev || String.startswith "bond" dev) && String.contains dev '.' then begin
554+
ignore (Ip.destroy_vlan dev);
555+
let n = String.length dev in
556+
if String.sub dev (n - 2) 2 = ".0" && need_enic_workaround () then
557+
let vlan_base = String.sub dev 0 (n - 2) in
558+
if Linux_bonding.is_bond_device vlan_base then
559+
Linux_bonding.remove_bond_master (String.sub dev 0 (n - 2))
560+
end;
537561
) ifs;
538562
Interface.set_ipv4_conf () dbg ~name ~conf:None4;
539563
ignore (Brctl.destroy_bridge name)
@@ -543,12 +567,12 @@ module Bridge = struct
543567

544568
let get_kind _ dbg () =
545569
Debug.with_thread_associated dbg (fun () ->
546-
!kind
570+
!backend_kind
547571
) ()
548572

549573
let get_ports _ dbg ~name =
550574
Debug.with_thread_associated dbg (fun () ->
551-
match !kind with
575+
match !backend_kind with
552576
| Openvswitch -> Ovs.bridge_to_ports name
553577
| Bridge -> raise Not_implemented
554578
) ()
@@ -559,14 +583,14 @@ module Bridge = struct
559583
let ports = List.concat (List.map (fun (_, {ports}) -> ports) !config.bridge_config) in
560584
List.map (fun (port, {interfaces}) -> port, interfaces) ports
561585
else
562-
match !kind with
586+
match !backend_kind with
563587
| Openvswitch -> List.concat (List.map Ovs.bridge_to_ports (Ovs.list_bridges ()))
564588
| Bridge -> raise Not_implemented
565589
) ()
566590

567591
let get_bonds _ dbg ~name =
568592
Debug.with_thread_associated dbg (fun () ->
569-
match !kind with
593+
match !backend_kind with
570594
| Openvswitch -> Ovs.bridge_to_ports name
571595
| Bridge -> raise Not_implemented
572596
) ()
@@ -578,21 +602,21 @@ module Bridge = struct
578602
let names = List.map (fun (port, {interfaces}) -> port, interfaces) ports in
579603
List.filter (fun (_, ifs) -> List.length ifs > 1) names
580604
else
581-
match !kind with
605+
match !backend_kind with
582606
| Openvswitch -> List.concat (List.map Ovs.bridge_to_ports (Ovs.list_bridges ()))
583607
| Bridge -> raise Not_implemented
584608
) ()
585609

586610
let get_vlan _ dbg ~name =
587611
Debug.with_thread_associated dbg (fun () ->
588-
match !kind with
612+
match !backend_kind with
589613
| Openvswitch -> Ovs.bridge_to_vlan name
590614
| Bridge -> raise Not_implemented
591615
) ()
592616

593617
let add_default_flows _ dbg bridge mac interfaces =
594618
Debug.with_thread_associated dbg (fun () ->
595-
match !kind with
619+
match !backend_kind with
596620
| Openvswitch -> Ovs.add_default_flows bridge mac interfaces
597621
| Bridge -> ()
598622
) ()
@@ -611,7 +635,7 @@ module Bridge = struct
611635
debug "Adding port %s to bridge %s with interfaces %s%s" name bridge
612636
(String.concat ", " interfaces)
613637
(match bond_mac with Some mac -> " and MAC " ^ mac | None -> "");
614-
match !kind with
638+
match !backend_kind with
615639
| Openvswitch ->
616640
if List.length interfaces = 1 then begin
617641
List.iter (fun name -> Interface.bring_up () dbg ~name) interfaces;
@@ -636,10 +660,9 @@ module Bridge = struct
636660
name bridge
637661
end
638662
| Bridge ->
639-
if List.length interfaces = 1 then begin
640-
List.iter (fun name -> Interface.bring_up () dbg ~name) interfaces;
641-
ignore (Brctl.create_port bridge name)
642-
end else begin
663+
if List.length interfaces = 1 then
664+
List.iter (fun name -> Interface.bring_up () dbg ~name) interfaces
665+
else begin
643666
if not (List.mem name (Sysfs.bridge_to_interfaces bridge)) then begin
644667
Linux_bonding.add_bond_master name;
645668
let bond_properties =
@@ -655,9 +678,16 @@ module Bridge = struct
655678
| None -> warn "No MAC address specified for the bond"
656679
end
657680
end;
658-
Interface.bring_up () dbg ~name;
681+
Interface.bring_up () dbg ~name
682+
end;
683+
if need_enic_workaround () then begin
684+
debug "Applying enic workaround: adding VLAN0 device to bridge";
685+
Ip.create_vlan name 0;
686+
let vlan0 = Ip.vlan_name name 0 in
687+
Interface.bring_up () dbg ~name:vlan0;
688+
ignore (Brctl.create_port bridge vlan0)
689+
end else
659690
ignore (Brctl.create_port bridge name)
660-
end
661691
) ()
662692

663693
let remove_port _ dbg ~bridge ~name =
@@ -668,7 +698,7 @@ module Bridge = struct
668698
let ports = List.remove_assoc name config.ports in
669699
update_config bridge {config with ports}
670700
end;
671-
match !kind with
701+
match !backend_kind with
672702
| Openvswitch ->
673703
ignore (Ovs.destroy_port name)
674704
| Bridge ->
@@ -677,7 +707,7 @@ module Bridge = struct
677707

678708
let get_interfaces _ dbg ~name =
679709
Debug.with_thread_associated dbg (fun () ->
680-
match !kind with
710+
match !backend_kind with
681711
| Openvswitch ->
682712
Ovs.bridge_to_interfaces name
683713
| Bridge ->
@@ -686,7 +716,7 @@ module Bridge = struct
686716

687717
let get_fail_mode _ dbg ~name =
688718
Debug.with_thread_associated dbg (fun () ->
689-
match !kind with
719+
match !backend_kind with
690720
| Openvswitch ->
691721
begin match Ovs.get_fail_mode name with
692722
| "standalone" -> Some Standalone
@@ -769,7 +799,7 @@ let on_startup () =
769799
(* the following is best-effort *)
770800
read_config ();
771801
remove_centos_config ();
772-
if !Bridge.kind = Openvswitch then
802+
if !backend_kind = Openvswitch then
773803
Ovs.set_max_idle 5000;
774804
Bridge.make_config () dbg ~conservative:true ~config:!config.bridge_config ();
775805
Interface.make_config () dbg ~conservative:true ~config:!config.interface_config ();

0 commit comments

Comments
 (0)