1#!/bin/bash
2#============================================================================
3# ${XEN_SCRIPT_DIR}/vif-nat
4#
5# Script for configuring a vif in routed-nat mode.
6#
7# Usage:
8# vif-nat (add|remove|online|offline)
9#
10# Environment vars:
11# dev         vif interface name (required).
12# XENBUS_PATH path to this device's details in the XenStore (required).
13#
14# Parameters:
15# dhcp        Whether to alter the local DHCP configuration to include this
16#             new host (default no).
17#
18# Read from the store:
19# ip      list of IP networks for the vif, space-separated (default given in
20#         this script).
21#============================================================================
22
23
24dir=$(dirname "$0")
25. "$dir/vif-common.sh"
26
27# turn on dhcp feature by default if dhcpd is installed
28if [ -f /etc/dhcpd.conf ]
29then
30	dhcp=${dhcp:-yes}
31else
32	dhcp=${dhcp:-no}
33fi
34
35if [ "$dhcp" != 'no' ]
36then
37  dhcpd_conf_file=$(find_dhcpd_conf_file)
38  dhcpd_init_file=$(find_dhcpd_init_file)
39  dhcpd_arg_file=$(find_dhcpd_arg_file)
40  if [ -z "$dhcpd_conf_file" ] || [ -z "$dhcpd_init_file" ] || [ -z "$dhcpd_arg_file" ]
41  then
42    echo 'Failed to find dhcpd configuration or init or args file.' >&2
43    exit 1
44  fi
45fi
46
47
48domid=$(xenstore_read "$XENBUS_PATH/frontend-id")
49vifid=$(xenstore_read "$XENBUS_PATH/handle")
50vifid=$(( $vifid + 1 ))
51
52
53ip_from_dom()
54{
55  local domid1=$(( $domid / 256 ))
56  local domid2=$(( $domid % 256 ))
57
58  echo "10.$domid1.$domid2.$vifid/16"
59}
60
61
62routing_ip()
63{
64  echo $(echo $1 | awk -F. '{print $1"."$2"."$3"."$4 + 127}')
65}
66
67
68dotted_quad()
69{
70 echo\
71 $(( ($1 & 0xFF000000) >> 24))\
72.$(( ($1 & 0x00FF0000) >> 16))\
73.$(( ($1 & 0x0000FF00) >> 8 ))\
74.$((  $1 & 0x000000FF       ))
75}
76
77
78if [ "$ip" = "" ]
79then
80  ip=$(ip_from_dom)
81fi
82
83router_ip=$(routing_ip "$ip")
84
85# Split the given IP/bits pair.
86vif_ip=`echo ${ip} | awk -F/ '{print $1}'`
87
88hostname=dom$domid
89if [ "$vifid" != "1" ]
90then
91  hostname="$hostname-$vifid"
92fi
93
94dhcparg_remove_entry()
95{
96  local tmpfile=$(mktemp)
97  sed -e "s/${dev} //" "$dhcpd_arg_file" >"$tmpfile"
98  if ! diff "$tmpfile" "$dhcpd_arg_file" >/dev/null
99  then
100    cp "$tmpfile" "$dhcpd_arg_file"
101  fi
102  rm "$tmpfile"
103}
104
105dhcparg_add_entry()
106{
107  dhcparg_remove_entry
108  local tmpfile=$(mktemp)
109  # handle Red Hat, SUSE, and Debian styles, with or without quotes
110  sed -e 's/^DHCPDARGS="*\([^"]*\)"*/DHCPDARGS="\1'"${dev} "'"/' \
111     "$dhcpd_arg_file" >"$tmpfile" && cp "$tmpfile" "$dhcpd_arg_file"
112  sed -e 's/^DHCPD_INTERFACE="*\([^"]*\)"*/DHCPD_INTERFACE="\1'"${dev} "'"/' \
113     "$dhcpd_arg_file" >"$tmpfile" && cp "$tmpfile" "$dhcpd_arg_file"
114  sed -e 's/^INTERFACES="*\([^"]*\)"*/INTERFACES="\1'"${dev} "'"/' \
115     "$dhcpd_arg_file" >"$tmpfile" && cp "$tmpfile" "$dhcpd_arg_file"
116  rm -f "$tmpfile"
117}
118
119dhcp_remove_entry()
120{
121  local tmpfile=$(mktemp)
122  grep -v "host $hostname" "$dhcpd_conf_file" >"$tmpfile"
123  if ! diff "$tmpfile" "$dhcpd_conf_file" >/dev/null
124  then
125    cp "$tmpfile" "$dhcpd_conf_file"
126  fi
127  rm "$tmpfile"
128  dhcparg_remove_entry
129}
130
131
132dhcp_up()
133{
134  claim_lock "vif-nat-dhcp"
135  dhcp_remove_entry
136  mac=$(xenstore_read "$XENBUS_PATH/mac")
137  echo >>"$dhcpd_conf_file" \
138"host $hostname { hardware ethernet $mac; fixed-address $vif_ip; option routers $router_ip; option host-name \"$hostname\"; }"
139  dhcparg_add_entry
140  release_lock "vif-nat-dhcp"
141  "$dhcpd_init_file" restart || true
142}
143
144
145dhcp_down()
146{
147  claim_lock "vif-nat-dhcp"
148  dhcp_remove_entry
149  release_lock "vif-nat-dhcp"
150  "$dhcpd_init_file" restart || true # We need to ignore failure because
151                                     # ISC dhcpd 3 borks if there is nothing
152                                     # for it to do, which is the case if
153                                     # the outgoing interface is not
154                                     # configured to offer leases and there
155                                     # are no vifs.
156}
157
158
159case "$command" in
160    online)
161        if ip route | grep -q "dev ${dev}"
162        then
163          log debug "${dev} already up"
164          exit 0
165        fi
166
167        do_or_die ip link set dev "${dev}" up arp on
168        do_or_die ip addr add "$router_ip" dev "${dev}"
169        do_or_die ip route add "$vif_ip" dev "${dev}" src "$router_ip"
170        echo 1 >/proc/sys/net/ipv4/conf/${dev}/proxy_arp
171        [ "$dhcp" != 'no' ] && dhcp_up
172        ;;
173    offline)
174        [ "$dhcp" != 'no' ] && dhcp_down
175        do_without_error ifconfig "${dev}" down
176        ;;
177esac
178
179
180handle_iptable
181
182call_hooks vif post
183
184log debug "Successful vif-nat $command for ${dev}."
185if [ "$command" = "online" ]
186then
187  success
188fi
189