Recompile with full set of kernels.
[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 (*
27 open Kernel_net_device
28 open Kernel_net
29
30 let max_net_devices = 10000
31
32 let rec find_net_devices debug image ksymmap kernel_version =
33   if not (net_device_known kernel_version) then (
34     eprintf (f_"%s: %s: unknown kernel version
35 Try a newer version of virt-mem, or if the guest is not from a
36 supported Linux distribution, see this page about adding support:
37   http://et.redhat.com/~rjones/virt-mem/faq.html\n")
38       image.domname kernel_version;
39     image, None
40   ) else (
41     (* In kernels < ~ 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 map =
47       let { field_available = available } =
48         field_signature_of_net_device_next kernel_version in
49       if available then
50         Some map_next
51       else (
52         let { field_available = available } =
53           field_signature_of_net_device_dev_list'next kernel_version in
54         if available then
55           Some map_dev_list
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
62     match map with
63     | None -> image, None
64
65     | Some map ->
66         (* What is the starting point for iteration?  In older kernels
67          * it was the symbol 'dev_base'.  Then briefly (2.6.22-2.6.24)
68          * it became 'struct list_head dev_base_head'.  Then when net
69          * namespaces were introduced (>= 2.6.25) it became 'struct
70          * list_head init_net.dev_base_head'.
71          *)
72         let addr =
73           try Some (Ksymmap.find "dev_base" ksymmap)
74           with Not_found ->
75             try
76               let addr = Ksymmap.find "dev_base_head" ksymmap in
77               Some addr
78             with Not_found ->
79               try
80                 let addr = Ksymmap.find "init_net" ksymmap in
81                 if not (net_known kernel_version) then (
82                   eprintf (f_"%s: struct net not available in this kernel version.\n") image.domname;
83                   raise Not_found
84                 );
85                 let { field_offset = offset } =
86                   field_signature_of_net_dev_base_head'next kernel_version in
87                 let addr = addr +^ Int64.of_int offset in
88                 Some addr
89               with Not_found ->
90                 eprintf (f_"%s: cannot find dev_base, dev_base_head or init_net symbols in kernel image.\n") image.domname;
91                 None in
92
93         match addr with
94         | None -> image, None
95
96         | Some addr ->
97             (* Map over the structure using previously defined map function. *)
98             let image, netdevs =
99               map kernel_version image addr (
100                 fun netdev ->
101                   { netdev_name = truncate_c_string netdev.net_device_name;
102                     netdev_flags = netdev.net_device_flags;
103                     netdev_operstate = netdev.net_device_operstate;
104                     netdev_mtu = netdev.net_device_mtu;
105                     netdev_perm_addr = netdev.net_device_perm_addr;
106                     netdev_addr_len = netdev.net_device_addr_len;
107                   }
108               ) in
109
110             image, Some netdevs
111   )
112
113 (* Map dev_base_head -> list_head dev_list -> ... *)
114 and map_dev_list kernel_version image lh_addr f =
115   let { field_offset = offset } =
116     field_signature_of_net_device_dev_list'next kernel_version in
117   let lh = Virt_mem_list_head.create image lh_addr offset in
118
119   let size = net_device_size kernel_version in
120   let image, lh = Virt_mem_list_head.load_all lh size in
121
122   let net_devices, _ =
123     Virt_mem_list_head.fold lh ([], 0) (
124       fun (net_devices, i) addr ->
125         if i > max_net_devices then
126           failwith (sprintf (f_"%s: too many network devices") image.domname);
127
128         let net_device = get_net_device kernel_version image.mem addr in
129         let net_devices = f net_device :: net_devices in
130         (net_devices, i+1)
131     ) in
132
133   image, net_devices
134
135 (* Iterate dev_base -> next -> next ... *)
136 and map_next kernel_version image addr f =
137   let size = net_device_size kernel_version in
138
139   let rec loop i image acc addr =
140     if i <= max_net_devices then (
141       if addr <> 0L then (
142         let mapped = Virt_mem_mmap.is_mapped_range image.mem addr size in
143         let image =
144           if not mapped then
145             Virt_mem_types.load_memory image addr size
146           else
147             image in
148         let dev = get_net_device kernel_version image.mem addr in
149         let acc = f dev :: acc in
150         let addr =
151           match dev.net_device_next with
152           | None -> assert false | Some addr -> addr in
153         loop (i+1) image acc addr
154       ) else
155         image, acc
156     ) else
157       failwith (sprintf (f_"%s: too many network devices") image.domname);
158   in
159   loop 0 image [] addr
160 *)