open Virt_mem_utils
open Virt_mem_types
+(*
open Kernel_net_device
+open Kernel_net
-type linkage = Next | DevList of int
+let max_net_devices = 10000
let rec find_net_devices debug image ksymmap kernel_version =
if not (net_device_known kernel_version) then (
image.domname kernel_version;
image, None
) else (
- let size = net_device_size kernel_version in
-
- (* In kernels < around 2.6.22, this is a simple linked list:
+ (* In kernels < ~ 2.6.22, this is a simple linked list:
* dev_base -> next -> next
* In kernels >= 2.6.23, this is a list_head:
* dev_base_head -> list_head dev_list -> ...
*)
- let linkage =
+ let map =
let { field_available = available } =
field_signature_of_net_device_next kernel_version in
if available then
- Some Next
+ Some map_next
else (
- let { field_available = available; field_offset = offset } =
+ let { field_available = available } =
field_signature_of_net_device_dev_list'next kernel_version in
if available then
- Some (DevList offset)
+ Some map_dev_list
else (
eprintf (f_"%s: kernel net_device table is not linked through either next pointer or dev_list list_head. Cannot read net devices.\n") image.domname;
None
)
) in
- match linkage with
- | None -> image, None
- | Some Next ->
- printf "linkage = Next\n%!";
+ match map with
+ | None -> image, None
- (* Linkage through old-style chain of next pointers. *)
- let dev_base =
+ | Some map ->
+ (* What is the starting point for iteration? In older kernels
+ * it was the symbol 'dev_base'. Then briefly (2.6.22-2.6.24)
+ * it became 'struct list_head dev_base_head'. Then when net
+ * namespaces were introduced (>= 2.6.25) it became 'struct
+ * list_head init_net.dev_base_head'.
+ *)
+ let addr =
try Some (Ksymmap.find "dev_base" ksymmap)
with Not_found ->
- eprintf (f_"%s: could not find dev_base symbol in kernel image\n") image.domname;
- None in
- (match dev_base with
- | None -> image, None
- | Some dev_base ->
- do_next image kernel_version dev_base size
- );
-
- | Some (DevList offset) ->
- printf "linkage = DevList %d\n%!" offset;
-
- (* Linkage through new-style list_head dev_list. *)
- let dev_base_head =
- try Some (Ksymmap.find "dev_base_head" ksymmap)
- with Not_found ->
- eprintf (f_"%s: could not find dev_base_head symbol in kernel image\n") image.domname;
- None in
- (match dev_base_head with
- | None -> image, None
- | Some dev_base_head ->
- let dev_base_head =
- Virt_mem_mmap.follow_pointer image.mem dev_base_head in
-
- do_dev_list image kernel_version dev_base_head offset size
- );
+ try
+ let addr = Ksymmap.find "dev_base_head" ksymmap in
+ Some addr
+ with Not_found ->
+ try
+ let addr = Ksymmap.find "init_net" ksymmap in
+ if not (net_known kernel_version) then (
+ eprintf (f_"%s: struct net not available in this kernel version.\n") image.domname;
+ raise Not_found
+ );
+ let { field_offset = offset } =
+ field_signature_of_net_dev_base_head'next kernel_version in
+ let addr = addr +^ Int64.of_int offset in
+ Some addr
+ with Not_found ->
+ eprintf (f_"%s: cannot find dev_base, dev_base_head or init_net symbols in kernel image.\n") image.domname;
+ None in
+
+ match addr with
+ | None -> image, None
+
+ | Some addr ->
+ (* Map over the structure using previously defined map function. *)
+ let image, netdevs =
+ map kernel_version image addr (
+ fun netdev ->
+ { netdev_name = truncate_c_string netdev.net_device_name;
+ netdev_flags = netdev.net_device_flags;
+ netdev_operstate = netdev.net_device_operstate;
+ netdev_mtu = netdev.net_device_mtu;
+ netdev_perm_addr = netdev.net_device_perm_addr;
+ netdev_addr_len = netdev.net_device_addr_len;
+ }
+ ) in
+
+ image, Some netdevs
)
-(* Iterate dev_base_head -> list_head dev_list -> ... *)
-and do_dev_list image kernel_version dev_base_head offset size =
- (* The list_head points into the middle of the structure.
- * Adjust this address to point to the start of the
- * structure.
- *)
- let addr = Int64.sub dev_base_head (Int64.of_int offset) in
-
- printf "do_dev_list, size = %d\n" size;
-
- let image =
- let rec loop image addr =
- let mapped = Virt_mem_mmap.is_mapped_range image.mem addr size in
- let image =
- if not mapped then
- Virt_mem_types.load_memory image addr size
- else
- image in
- let dev = get_net_device kernel_version image.mem addr in
- printf "net_device_name = %S\n" dev.net_device_name;
- let addr = Option.get dev.net_device_dev_list'next in
- if addr <> dev_base_head then
- loop image addr
- else
- image
- in
- loop image addr in
- image, Some dev_base_head
+(* Map dev_base_head -> list_head dev_list -> ... *)
+and map_dev_list kernel_version image lh_addr f =
+ let { field_offset = offset } =
+ field_signature_of_net_device_dev_list'next kernel_version in
+ let lh = Virt_mem_list_head.create image lh_addr offset in
+
+ let size = net_device_size kernel_version in
+ let image, lh = Virt_mem_list_head.load_all lh size in
+
+ let net_devices, _ =
+ Virt_mem_list_head.fold lh ([], 0) (
+ fun (net_devices, i) addr ->
+ if i > max_net_devices then
+ failwith (sprintf (f_"%s: too many network devices") image.domname);
+
+ let net_device = get_net_device kernel_version image.mem addr in
+ let net_devices = f net_device :: net_devices in
+ (net_devices, i+1)
+ ) in
+
+ image, net_devices
(* Iterate dev_base -> next -> next ... *)
-and do_next image kernel_version addr size =
- printf "do_next, size = %d\n" size;
+and map_next kernel_version image addr f =
+ let size = net_device_size kernel_version in
- let image =
- let rec loop image addr =
+ let rec loop i image acc addr =
+ if i <= max_net_devices then (
if addr <> 0L then (
let mapped = Virt_mem_mmap.is_mapped_range image.mem addr size in
let image =
else
image in
let dev = get_net_device kernel_version image.mem addr in
- printf "net_device_name = %S\n" dev.net_device_name;
+ let acc = f dev :: acc in
let addr =
match dev.net_device_next with
| None -> assert false | Some addr -> addr in
- loop image addr
+ loop (i+1) image acc addr
) else
- image
- in
- loop image addr in
- image, Some addr
+ image, acc
+ ) else
+ failwith (sprintf (f_"%s: too many network devices") image.domname);
+ in
+ loop 0 image [] addr
+*)