1 (* Memory info command for virtual domains.
2 (C) Copyright 2008 Richard W.M. Jones, Red Hat Inc.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 open Virt_mem_gettext.Gettext
26 open Kernel_net_device
29 let max_net_devices = 10000
31 let rec find_net_devices debug image ksymmap kernel_version =
32 if not (net_device_known kernel_version) then (
33 eprintf (f_"%s: %s: unknown kernel version
34 Try a newer version of virt-mem, or if the guest is not from a
35 supported Linux distribution, see this page about adding support:
36 http://et.redhat.com/~rjones/virt-mem/faq.html\n")
37 image.domname kernel_version;
40 let size = net_device_size kernel_version in
42 (* In kernels < ~ 2.6.22, this is a simple linked list:
43 * dev_base -> next -> next
44 * In kernels >= 2.6.23, this is a list_head:
45 * dev_base_head -> list_head dev_list -> ...
48 let { field_available = available } =
49 field_signature_of_net_device_next kernel_version in
53 let { field_available = available; field_offset = offset } =
54 field_signature_of_net_device_dev_list'next kernel_version in
56 Some (map_dev_list offset)
58 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;
67 (* What is the starting point for iteration? In older kernels
68 * it was the symbol 'dev_base'. Then briefly (2.6.22-2.6.24)
69 * it became 'sruct list_head dev_base_head'. Then when net
70 * namespaces were introduced (>= 2.6.25) it became 'struct
71 * list_head init_net.dev_base_head'.
74 try Some (Ksymmap.find "dev_base" ksymmap)
77 let addr = Ksymmap.find "dev_base_head" ksymmap in
78 let addr = Virt_mem_mmap.follow_pointer image.mem addr in
82 let addr = Ksymmap.find "init_net" ksymmap in
83 if not (net_known kernel_version) then (
84 eprintf (f_"%s: struct net not available in this kernel version.\n") image.domname;
87 let init_net = get_net kernel_version image.mem addr in
88 let addr = init_net.net_dev_base_head'next in
91 eprintf (f_"%s: cannot find dev_base, dev_base_head or init_net symbols in kernel image.\n") image.domname;
98 (* Map over the structure using previously defined map function. *)
100 map image kernel_version addr size (
102 { netdev_name = truncate_c_string netdev.net_device_name;
103 netdev_dev_addr = netdev.net_device_dev_addr }
109 (* Map dev_base_head -> list_head dev_list -> ... *)
110 and map_dev_list offset image kernel_version first_addr size f =
111 eprintf "map_dev_list: first_addr is %Lx\n" first_addr;
113 (* The list_head points into the middle of the structure.
114 * Adjust this address to point to the start of the
117 let addr = Int64.sub first_addr (Int64.of_int offset) in
118 eprintf "map_dev_list: after subtracting, addr is %Lx\n" addr;
120 let rec loop i image acc addr =
121 if i <= max_net_devices then (
122 eprintf "map_dev_list: called at %Lx\n" addr;
123 let mapped = Virt_mem_mmap.is_mapped_range image.mem addr size in
126 Virt_mem_types.load_memory image addr size
129 let dev = get_net_device kernel_version image.mem addr in
130 eprintf "map_dev_list: %Lx %S\n" addr dev.net_device_name;
131 let acc = f dev :: acc in
132 let addr = Option.get dev.net_device_dev_list'next in
133 if addr <> first_addr then
134 loop (i+1) image acc addr
138 failwith (sprintf (f_"%s: too many network devices") image.domname);
142 (* Iterate dev_base -> next -> next ... *)
143 and map_next image kernel_version addr size f =
144 let rec loop i image acc addr =
145 if i <= max_net_devices then (
147 let mapped = Virt_mem_mmap.is_mapped_range image.mem addr size in
150 Virt_mem_types.load_memory image addr size
153 let dev = get_net_device kernel_version image.mem addr in
154 eprintf "map_next: %S\n" dev.net_device_name;
155 let acc = f dev :: acc in
157 match dev.net_device_next with
158 | None -> assert false | Some addr -> addr in
159 loop (i+1) image acc addr
163 failwith (sprintf (f_"%s: too many network devices") image.domname);