]> git.proxmox.com Git - ceph.git/blob - ceph/src/script/run_uml.sh
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / script / run_uml.sh
1 #!/bin/bash -norc
2
3 # Magic startup script for a UML instance. As long as unique
4 # instances are started, more than one of them can be concurrently
5 # in use on a single system. All their network interfaces are
6 # bridged together onto the virtual bridge "virbr0" which is
7 # supplied by the "libvirt" package.
8 #
9 # Note that a DHCP server is started for that interface. It's
10 # configured in this file:
11 # /etc/libvirt/qemu/networks/default.xml
12 # Unfortunately what I see there serves all possible DHCP addresses,
13 # so stealing them like we do here isn't really kosher. To fix
14 # it, that configuration should change to serve a smaller subset
15 # of the available address range.
16 #
17 # Each instance uses its own tun/tap device, created using the
18 # "tunctl" command. The assigned tap device will correspond with
19 # the guest id (a small integer representing the instance), i.e.,
20 # guest id 1 uses tap1, etc. The tap device is attached to the
21 # virtual bridge, which will have its own subnet associated with it.
22 # The guest side of that interface will have the same subnet as the
23 # bridge interface, with the bottom bits representing (normally) 100
24 # more than the guest id. So for subnet 192.168.122.0/24, guest
25 # id 1 will use ip 192.168.122.101, guest id 2 will use ip
26 # 192.168.122.102, and so on. Because these interfaces are bridged,
27 # they can all communicate with each other.
28
29 # You will want to override this by setting and exporting the
30 # "CEPH_TOP" environment variable to be the directory that contains
31 # the "ceph-client" source tree.
32 CEPH_TOP="${CEPH_TOP:-/home/elder/ceph}"
33
34 # You may want to change this too, if you want guest UML instances
35 # to have a diffeerent IP address range. The guest IP will be based
36 # on this plus GUEST_ID (defined below).
37 GUEST_IP_OFFSET="${GUEST_IP_OFFSET:-100}"
38
39 #############################
40
41 if [ $# -gt 1 ]; then
42 echo "" >&2
43 echo "Usage: $(basename $0) [guest_id]" >&2
44 echo "" >&2
45 echo " guest_id is a small integer (default 1)" >&2
46 echo " (each UML instance needs a distinct guest_id)" >&2
47 echo "" >&2
48 exit 1
49 elif [ $# -eq 1 ]; then
50 GUEST_ID="$1"
51 else
52 GUEST_ID=1
53 fi
54
55 # This will be what the guest host calls itself.
56 GUEST_HOSTNAME="uml-${GUEST_ID}"
57
58 # This is the path to the boot disk image used by UML.
59 DISK_IMAGE_A="${CEPH_TOP}/ceph-client/uml.${GUEST_ID}"
60 if [ ! -f "${DISK_IMAGE_A}" ]; then
61 echo "root disk image not found (or not a file)" >&2
62 exit 2
63 fi
64
65 # Hostid 1 uses tun/tap device tap1, hostid 2 uses tap2, etc.
66 TAP_ID="${GUEST_ID}"
67 # This is the tap device used for this UML instance
68 TAP="tap${TAP_ID}"
69
70 # This is just used to mount an image temporarily
71 TMP_MNT="/tmp/m$$"
72
73 # Where to put a config file generated for this tap device
74 TAP_IFUPDOWN_CONFIG="/tmp/interface-${TAP}"
75
76 # Compute the HOST_IP and BROADCAST address values to use,
77 # and assign shell variables with those names to their values.
78 # Also compute BITS, which is the network prefix length used.
79 # The NETMASK is then computed using that BITS value.
80 eval $(
81 ip addr show virbr0 | awk '
82 /inet/ {
83 split($2, a, "/")
84 printf("HOST_IP=%s\n", a[1]);
85 printf("BROADCAST=%s\n", $4);
86 printf("BITS=%s\n", a[2]);
87 exit(0);
88 }')
89
90 # Use bc to avoid 32-bit wrap when computing netmask
91 eval $(
92 echo -n "NETMASK="
93 bc <<! | fmt | sed 's/ /./g'
94 m = 2 ^ 32 - 2 ^ (32 - ${BITS})
95 for (p = 24; p >= 0; p = p - 8)
96 m / (2 ^ p) % 256
97 !
98 )
99
100 # Now use the netmask and the host IP to compute the subnet address
101 # and from that the guest IP address to use.
102 eval $(
103 awk '
104 function from_quad(addr, a, val, i) {
105 if (split(addr, a, ".") != 4)
106 exit(1); # address not in dotted quad format
107 val = 0;
108 for (i = 1; i <= 4; i++)
109 val = val * 256 + a[i];
110 return val;
111 }
112 function to_quad(val, addr, i) {
113 addr = "";
114 for (i = 1; i <= 4; i++) {
115 addr = sprintf("%u%s%s", val % 256, i > 1 ? "." : "", addr);
116 val = int(val / 256);
117 }
118 if ((val + 0) != 0)
119 exit(1); # value provided exceeded 32 bits
120 return addr;
121 }
122 BEGIN {
123 host_ip = from_quad("'${HOST_IP}'");
124 netmask = from_quad("'${NETMASK}'");
125 guest_net_ip = '${GUEST_IP_OFFSET}' + '${GUEST_ID}';
126 if (and(netmask, guest_net_ip))
127 exit(1); # address too big for subnet
128 subnet = and(host_ip, netmask);
129 guest_ip = or(subnet, guest_net_ip);
130 if (guest_ip == host_ip)
131 exit(1); # computed guest ip matches host ip
132
133 printf("SUBNET=%s\n", to_quad(subnet));
134 printf("GUEST_IP=%s\n", to_quad(guest_ip));
135 }
136 ' < /dev/null
137 )
138
139 ############## OK, we now know all our network parameters...
140
141 # There is a series of things that need to be done as superuser,
142 # so group them all into one big (and sort of nested!) sudo request.
143 sudo -s <<EnD_Of_sUdO
144 # Mount the boot disk for the UML and set up some configuration
145 # files there.
146 mkdir -p "${TMP_MNT}"
147 mount -o loop "${DISK_IMAGE_A}" "${TMP_MNT}"
148
149 # Arrange for loopback and eth0 to load automatically,
150 # and for eth0 to have our desired network parameters.
151 cat > "${TMP_MNT}/etc/network/interfaces" <<!
152 # Used by ifup(8) and ifdown(8). See the interfaces(5) manpage or
153 # /usr/share/doc/ifupdown/examples for more information.
154 auto lo
155 iface lo inet loopback
156 auto eth0
157 # iface eth0 inet dhcp
158 iface eth0 inet static
159 address ${GUEST_IP}
160 netmask ${NETMASK}
161 broadcast ${BROADCAST}
162 gateway ${HOST_IP}
163 !
164
165 # Have the guest start with an appropriate host name.
166 # Also record an entry for it in its own hosts file.
167 echo "${GUEST_HOSTNAME}" > "${TMP_MNT}/etc/hostname"
168 echo "${GUEST_IP} ${GUEST_HOSTNAME}" >> "${TMP_MNT}/etc/hosts"
169
170 # The host will serve as the name server also
171 cat > "${TMP_MNT}/etc/resolv.conf" <<!
172 nameserver ${HOST_IP}
173 !
174
175 # OK, done tweaking the boot image.
176 sync
177 umount "${DISK_IMAGE_A}"
178 rmdir "${TMP_MNT}"
179
180 # Set up a config file for "ifup" and "ifdown" (on the host) to use.
181 # All the backslashes below are needed because we're sitting inside
182 # a double here-document...
183 cat > "${TAP_IFUPDOWN_CONFIG}" <<!
184 iface ${TAP} inet manual
185 up brctl addif virbr0 "\\\${IFACE}"
186 up ip link set dev "\\\${IFACE}" up
187 pre-down brctl delif virbr0 "\\\${IFACE}"
188 pre-down ip link del dev "\\\${IFACE}"
189 tunctl_user $(whoami)
190 !
191
192 # OK, bring up the tap device using our config file
193 ifup -i "${TAP_IFUPDOWN_CONFIG}" "${TAP}"
194
195 EnD_Of_sUdO
196
197 # Finally ready to launch the UML instance.
198 ./linux \
199 umid="${GUEST_HOSTNAME}" \
200 ubda="${DISK_IMAGE_A}" \
201 eth0="tuntap,${TAP}" \
202 mem=1024M
203
204 # When we're done, clean up. Bring down the tap interface and
205 # delete the config file.
206 #
207 # Note that if the above "./linux" crashes, you'll need to run the
208 # following commands manually in order to clean up state.
209 sudo ifdown -i "${TAP_IFUPDOWN_CONFIG}" "${TAP}"
210 sudo rm -f "${TAP_IFUPDOWN_CONFIG}"
211
212 exit 0