# #
###############################################################################
-IP_TUNNEL_MODES="sit vti"
+IP_TUNNEL_MODES="gre gretap sit vti"
+
+ip_tunnel_protocol_to_name() {
+ local protocol="${1}"
+
+ case "${protocol}" in
+ gre)
+ print "Generic Routing Encapsulation"
+ ;;
+ sit)
+ print "Simple Internet Transition"
+ ;;
+ vti)
+ print "Virtual Tunnel Interface"
+ ;;
+ *)
+ print "${protocol}"
+ ;;
+ esac
+}
+
+# This function converts our modes into the type
+# the iproute2 tool uses
+ip_tunnel_convert_mode_to_iproute2_mode() {
+ local mode=${1}
+ local protocol=${2}
+
+ if ! isset mode || ! isset protocol; then
+ log ERROR "Did not get mode and/or protocol"
+ return ${EXIT_ERROR}
+ fi
+
+ if [[ "${protocol}" = "ipv4" ]]; then
+ # When we use IPv4 we can use our modes
+ echo "${mode}"
+ fi
+
+ if [[ "${protocol}" = "ipv6" ]]; then
+ # When we use IPv6 we have to convert
+ case "${mode}" in
+ "vti")
+ echo "vti6"
+ ;;
+ "gre")
+ echo "ip6gre"
+ ;;
+ "gretap")
+ echo "ip6gretap"
+ ;;
+ esac
+ fi
+}
ip_tunnel_add() {
- local device=${1}
+ local device="${1}"
shift
local mode
- local ttl
+ local ttl=255
+ local address
local remote_address
local local_address
while [ $# -gt 0 ]; do
case "${1}" in
+ --address=*)
+ address="$(cli_get_val "${1}")"
+
+ # Validate input
+ if ! isset address || ! mac_is_valid "${address}"; then
+ error "Invalid MAC address: ${address}"
+ return ${EXIT_ERROR}
+ fi
+ ;;
--mode=*)
- mode="$(cli_get_val ${1})"
+ mode="$(cli_get_val "${1}")"
;;
--ttl=*)
- ttl="$(cli_get_val ${1})"
+ ttl="$(cli_get_val "${1}")"
;;
--remote-address=*)
- remote_address="$(cli_get_val ${1})"
+ remote_address="$(cli_get_val "${1}")"
;;
--local-address=*)
- local_address="$(cli_get_val ${1})"
+ local_address="$(cli_get_val "${1}")"
;;
# Keys for VTI
--ikey=*)
- ikey="$(cli_get_val ${1})"
+ ikey="$(cli_get_val "${1}")"
;;
--okey=*)
- okey="$(cli_get_val ${1})"
+ okey="$(cli_get_val "${1}")"
;;
esac
shift
return ${EXIT_ERROR}
fi
+ # We cannot mix IPv6 and IPv4
+ if isset local_address && ! ip_protocol_match "${remote_address}" "${local_address}"; then
+ log ERROR "Local and remote address are not of the same IP protocol"
+ return ${EXIT_ERROR}
+ fi
+
# ikey and okey must be set for VTI devices
if [ "${mode}" = "vti" ] && (! isset ikey || ! isset okey); then
error "--ikey= and --okey= must be set for VTI device"
return ${EXIT_ERROR}
fi
+ # Custom checks for certain modes
+ case "${mode}" in
+ gretap)
+ # Generate a random MAC address if none was passed
+ if ! isset address; then
+ address="$(mac_generate)"
+ fi
+ ;;
+ esac
+
# If TTL is set, make sure it is an integer.
if isset ttl && ! isinteger ttl; then
error "TTL must be an integer: ${ttl}"
return ${EXIT_ERROR}
fi
- local cmd_args
+ # Determine the mode based on the IP protocol
+ local remote_address_protocol="$(ip_detect_protocol "${remote_address}")"
+ mode=$(ip_tunnel_convert_mode_to_iproute2_mode "${mode}" "${remote_address_protocol}")
+
+ local cmd_args=( name "${device}" )
+
+ if isset address; then
+ cmd_args=( "${cmd_args[@]}" "address" "${address}" )
+ fi
+
+ # Mode
+ cmd_args=( "${cmd_args[@]}" "type" "${mode}" )
# Apply TTL if a value has been set.
if isset ttl; then
- cmd_args="${cmd_args} ttl ${ttl}"
+ cmd_args=( "${cmd_args[@]}" "ttl" "${ttl}" )
fi
# Apply local address if a value has been set.
if isset local_address; then
- cmd_args="${cmd_args} local ${local_address}"
+ cmd_args=( "${cmd_args[@]}" "local" "${local_address}" )
fi
# Apply remote address if a value has been set.
if isset remote_address; then
- cmd_args="${cmd_args} remote ${remote_address}"
+ cmd_args=( "${cmd_args[@]}" "remote" "${remote_address}" )
fi
# Add ikey and okey for VTI devices
if [ "${mode}" = "vti" ]; then
- cmd_args="${cmd_args} ikey ${ikey} okey ${okey}"
+ cmd_args=( "${cmd_args[@]}" "ikey" "${ikey}" "okey" "${okey}" )
fi
log DEBUG "Creating tunnel device '${device}' (mode=${mode})..."
# Create the device.
- if ! cmd ip tunnel add ${device} mode ${mode} ${cmd_args}; then
+ if ! cmd ip link add "${cmd_args[@]}"; then
error "Could not create tunnel device ${device}"
return ${EXIT_ERROR}
fi
}
ip_tunnel_del() {
- local device=${1}
- assert device_exists ${device}
+ device_delete "$@"
+}
+
+ip_tunnel_change() {
+ local device="${1}"
+ shift
+
+ if ! device_exists "${device}"; then
+ log ERROR "No such device: ${device}"
+ return ${EXIT_ERROR}
+ fi
+
+ # Determine the device type
+ local type="$(device_tunnel_get_type ${device})"
+
+ local local
+ local remote
+
+ while [ $# -gt 0 ]; do
+ case "${1}" in
+ --local=*)
+ local="$(cli_get_val "${1}")"
+
+ if ! ip_is_valid "${local}"; then
+ error "Invalid IP address for --local: ${local}"
+ return ${EXIT_ERROR}
+ fi
+
+ if ! isoneof "type" gre gre6 vti vti6; then
+ log ERROR "Cannot change --local for devices of type ${type}"
+ return ${EXIT_ERROR}
+ fi
+ ;;
+ --remote=*)
+ remote="$(cli_get_val "${1}")"
- # Make sure the device has been shut down.
- device_set_down ${device}
+ if ! ip_is_valid "${remote}"; then
+ error "Invalid IP address for --remote: ${remote}"
+ return ${EXIT_ERROR}
+ fi
- log DEBUG "Removing tunnel device '${device}'..."
+ if ! isoneof "type" gre gre6 vti vti6; then
+ log ERROR "Cannot change --remote for devices of type ${type}"
+ return ${EXIT_ERROR}
+ fi
+ ;;
+ esac
+ shift
+ done
+
+ # XXX If a device is of an IP protocol and the protocol of remote and local
+ # have changed, we will need to destroy the interface and recreate it with
+ # the correct type
+
+ local cmd_args
+
+ if isset local; then
+ cmd_args="${cmd_args} local ${local}"
+ fi
+
+ if isset remote; then
+ cmd_args="${cmd_args} remote ${remote}"
+ fi
+
+ # Exit if there is nothing to do
+ if ! isset cmd_args; then
+ return ${EXIT_OK}
+ fi
- ip tunnel del ${device}
- assert [ $? -eq 0 ]
+ # Run ip command
+ cmd ip link change dev "${device}" type "${type}" ${cmd_args}
}