d792d0de327e42850261b2f5b11c3d27dd7e8efe
[virt-mem.git] / lib / virt_mem_net_devices.ml
1 (* Memory info command for virtual domains.
2    (C) Copyright 2008 Richard W.M. Jones, Red Hat Inc.
3    http://libvirt.org/
4
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.
9
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.
14
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.
18  *)
19
20 open Printf
21
22 open Virt_mem_gettext.Gettext
23 open Virt_mem_utils
24 open Virt_mem_types
25
26 open Kernel_net_device
27
28 type linkage = Next | DevList of int
29
30 let rec find_net_devices debug image ksymmap kernel_version =
31   if not (net_device_known kernel_version) then (
32     eprintf (f_"%s: %s: unknown kernel version
33 Try a newer version of virt-mem, or if the guest is not from a
34 supported Linux distribution, see this page about adding support:
35   http://et.redhat.com/~rjones/virt-mem/faq.html\n")
36       image.domname kernel_version;
37     image, None
38   ) else (
39     let size = net_device_size kernel_version in
40
41     (* In kernels < around 2.6.22, this is a simple linked list:
42      *   dev_base -> next -> next
43      * In kernels >= 2.6.23, this is a list_head:
44      *   dev_base_head -> list_head dev_list -> ...
45      *)
46     let linkage =
47       let { field_available = available } =
48         field_signature_of_net_device_next kernel_version in
49       if available then
50         Some Next
51       else (
52         let { field_available = available; field_offset = offset } =
53           field_signature_of_net_device_dev_list'next kernel_version in
54         if available then
55           Some (DevList offset)
56         else (
57           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;
58           None
59         )
60       ) in
61     match linkage with
62     | None -> image, None
63
64     | Some Next ->
65         printf "linkage = Next\n%!";
66
67         (* Linkage through old-style chain of next pointers. *)
68         let dev_base =
69           try Some (Ksymmap.find "dev_base" ksymmap)
70           with Not_found ->
71             eprintf (f_"%s: could not find dev_base symbol in kernel image\n") image.domname;
72             None in
73         (match dev_base with
74          | None -> image, None
75          | Some dev_base ->
76              do_next image kernel_version dev_base size
77         );
78
79     | Some (DevList offset) ->
80         printf "linkage = DevList %d\n%!" offset;
81
82         (* Linkage through new-style list_head dev_list. *)
83         let dev_base_head =
84           try Some (Ksymmap.find "dev_base_head" ksymmap)
85           with Not_found ->
86             eprintf (f_"%s: could not find dev_base_head symbol in kernel image\n") image.domname;
87             None in
88         (match dev_base_head with
89          | None -> image, None
90          | Some dev_base_head ->
91              let dev_base_head =
92                Virt_mem_mmap.follow_pointer image.mem dev_base_head in
93
94              do_dev_list image kernel_version dev_base_head offset size
95         );
96   )
97
98 (* Iterate dev_base_head -> list_head dev_list -> ... *)
99 and do_dev_list image kernel_version dev_base_head offset size =
100   (* The list_head points into the middle of the structure.
101    * Adjust this address to point to the start of the
102    * structure.
103    *)
104   let addr = Int64.sub dev_base_head (Int64.of_int offset) in
105
106   printf "do_dev_list, size = %d\n" size;
107
108   let image =
109     let rec loop image addr =
110       let mapped = Virt_mem_mmap.is_mapped_range image.mem addr size in
111       let image =
112         if not mapped then
113           Virt_mem_types.load_memory image addr size
114         else
115           image in
116       let dev = get_net_device kernel_version image.mem addr in
117       printf "net_device_name = %S\n" dev.net_device_name;
118       let addr = Option.get dev.net_device_dev_list'next in
119       if addr <> dev_base_head then
120         loop image addr
121       else
122         image
123     in
124     loop image addr in
125   image, Some dev_base_head
126
127 (* Iterate dev_base -> next -> next ... *)
128 and do_next image kernel_version addr size =
129   printf "do_next, size = %d\n" size;
130
131   let image =
132     let rec loop image addr =
133       if addr <> 0L then (
134         let mapped = Virt_mem_mmap.is_mapped_range image.mem addr size in
135         let image =
136           if not mapped then
137             Virt_mem_types.load_memory image addr size
138           else
139             image in
140         let dev = get_net_device kernel_version image.mem addr in
141       printf "net_device_name = %S\n" dev.net_device_name;
142         let addr =
143           match dev.net_device_next with
144           | None -> assert false | Some addr -> addr in
145         loop image addr
146       ) else
147         image
148     in
149     loop image addr in
150   image, Some addr