X-Git-Url: http://git.annexia.org/?p=virt-mem.git;a=blobdiff_plain;f=lib%2Fvirt_mem_net_devices.ml;h=8ce8eb30eebdcf22f83a812eaf246efd59d5a409;hp=d792d0de327e42850261b2f5b11c3d27dd7e8efe;hb=2e1de51e35bea53ebece1a6fd6d6970534f4cbe9;hpb=14c916e5692f6d1986a10b88d03b41349dcb729a diff --git a/lib/virt_mem_net_devices.ml b/lib/virt_mem_net_devices.ml index d792d0d..8ce8eb3 100644 --- a/lib/virt_mem_net_devices.ml +++ b/lib/virt_mem_net_devices.ml @@ -24,8 +24,9 @@ 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 ( @@ -36,100 +37,101 @@ supported Linux distribution, see this page about adding support: 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_dev_addr = netdev.net_device_dev_addr } + ) 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 = @@ -138,13 +140,14 @@ and do_next image kernel_version 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 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