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=$(xenstore_read "$XENBUS_PATH/domain" | tr -- '_.:/+' '-----')
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    rm "$tmpfile"
101  else
102    mv "$tmpfile" "$dhcpd_arg_file"
103  fi
104}
105
106dhcparg_add_entry()
107{
108  dhcparg_remove_entry
109  local tmpfile=$(mktemp)
110  # handle Red Hat, SUSE, and Debian styles, with or without quotes
111  sed -e 's/^DHCPDARGS="*\([^"]*\)"*/DHCPDARGS="\1'"${dev} "'"/' \
112     "$dhcpd_arg_file" >"$tmpfile" && mv "$tmpfile" "$dhcpd_arg_file"
113  sed -e 's/^DHCPD_INTERFACE="*\([^"]*\)"*/DHCPD_INTERFACE="\1'"${dev} "'"/' \
114     "$dhcpd_arg_file" >"$tmpfile" && mv "$tmpfile" "$dhcpd_arg_file"
115  sed -e 's/^INTERFACES="*\([^"]*\)"*/INTERFACES="\1'"${dev} "'"/' \
116     "$dhcpd_arg_file" >"$tmpfile" && mv "$tmpfile" "$dhcpd_arg_file"
117  rm -f "$tmpfile"
118}
119
120dhcp_remove_entry()
121{
122  local tmpfile=$(mktemp)
123  grep -v "host $hostname" "$dhcpd_conf_file" >"$tmpfile"
124  if diff "$tmpfile" "$dhcpd_conf_file" >/dev/null
125  then
126    rm "$tmpfile"
127  else
128    mv "$tmpfile" "$dhcpd_conf_file"
129  fi
130  dhcparg_remove_entry
131}
132
133
134dhcp_up()
135{
136  claim_lock "vif-nat-dhcp"
137  dhcp_remove_entry
138  mac=$(xenstore_read "$XENBUS_PATH/mac")
139  echo >>"$dhcpd_conf_file" \
140"host $hostname { hardware ethernet $mac; fixed-address $vif_ip; option routers $router_ip; option host-name \"$hostname\"; }"
141  dhcparg_add_entry
142  release_lock "vif-nat-dhcp"
143  "$dhcpd_init_file" restart || true
144}
145
146
147dhcp_down()
148{
149  claim_lock "vif-nat-dhcp"
150  dhcp_remove_entry
151  release_lock "vif-nat-dhcp"
152  "$dhcpd_init_file" restart || true # We need to ignore failure because
153                                     # ISC dhcpd 3 borks if there is nothing
154                                     # for it to do, which is the case if
155                                     # the outgoing interface is not
156                                     # configured to offer leases and there
157                                     # are no vifs.
158}
159
160
161case "$command" in
162    online)
163        if ip route | grep -q "dev ${dev}"
164        then
165          log debug "${dev} already up"
166          exit 0
167        fi
168
169        do_or_die ip link set dev "${dev}" up arp on
170        do_or_die ip addr add "$router_ip" dev "${dev}"
171        do_or_die ip route add "$vif_ip" dev "${dev}" src "$router_ip"
172        echo 1 >/proc/sys/net/ipv4/conf/${dev}/proxy_arp
173        [ "$dhcp" != 'no' ] && dhcp_up
174        ;;
175    offline)
176        [ "$dhcp" != 'no' ] && dhcp_down
177        do_without_error ifconfig "${dev}" down
178        ;;
179esac
180
181
182handle_iptable
183
184call_hooks vif post
185
186log debug "Successful vif-nat $command for ${dev}."
187if [ "$command" = "online" ]
188then
189  success
190fi
191