Current File : //usr/bin/bond2team
#!/bin/bash
#
# Translate tool from bonding configuration to team.
#
# Copyright (C) 2013 Flavio Leitner <[email protected]>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2,
# as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
#

VERSION="0.97"

PR_QUIET=0
PR_ERR=1
PR_WARN=2
PR_INFO=3
PR_DBG=4

#defaults
ARGC=$#

FORMAT_IFCFG=0
FORMAT_JANSSON=1
OUTPUT_FORMAT=${FORMAT_IFCFG}

MODE_IFCFG=0
MODE_NOIFCFG=1
MODE=${MODE_IFCFG}

OUTPUT_FILE=
RENAME=
DEVICE=
BOND_MASTER=
STDOUT=1
BONDING_OPTS=
CONFIGDIR="/etc/sysconfig/network-scripts"
PR_LVL=3
OUTPUT_DIR=
OUTPUT_TMP_DIR=
TMP_FILES=()
RUNNER_OPTS=()
LWATCH_OPTS=()
# array: ( 'port ifname', 'opt1', 'opt2', 'optn', 'opt4', 'port ifname', ... )
PORT_LIST=
PORTS_OPTS=()
PRIMARY=
PRIMARY_RESELECT=

# building file scratch memory area
VFILE=

show_examples()
{
	cat << EOF

The following commands will deliver the ifcfg files into a temporary
directory. You can review the files and copy to the right location.

Add the following argument to the commands below to print the output
to the screen instead of writing to files.
  --stdout

Add the following arguments to the commands below to set the
destination directory for the output files.
  --outputdir </path/to/dir>

Add the following argument to the commands below to output the
files in teamd format (JSON) instead of the default ifcfg format.
  --json

To convert the current "bond0" ifcfg configuration to team ifcfg:
# $0 --master bond0

To convert the current "bond0" ifcfg configuration out of the
standard ifcfg-:
# $0 --master bond0 --configdir </path/to/ifcfg>

To convert the current "bond0" ifcfg configuration to team ifcfg
renaming the interface name to "team0". (carefull: firewall rules,
aliases interfaces, etc., will break after the renaming because the
tool will only change the ifcfg file, nothing else)
# $0 --master bond0 --rename team0

To convert given bonding parameters without any ifcfg:
# $0 --bonding_opts "mode=1 miimon=500"

To convert given bonding parameters without any ifcfg with ports:
# $0 --bonding_opts "mode=1 miimon=500 primary=eth1 primary_reselect-0" \\
     --port eth1 --port eth2 --port eth3 --port eth4

EOF
}
usage()
{
	cat << EOF
usage: $0 [options]

This tool translates bonding configuration to team.
See bond2team(1) for detailed information.

OPTIONS:

  --master <interface>	set the master interface name or ifcfg

  --rename <iface>	rename the master interface to <iface>

  --ifcfg		set the output format to ifcfg style

  --json		set the output format to teamd style

  --bonding_opts	pass the bonding options instead of reading
			from the ifcfg- file

  --port <iface>	add the interface to the port's list

  --configdir <dir>	set where the ifcfg- files are
			default: /etc/sysconfig/network-scripts

  --outputdir <dir>	set the output diretory
			default: temporary diretory

  --stdout		print to stdout instead of
			modify the system's files.

  --debug		increase debug level

  --quiet		no messages

  --version		show the tool version

  --help		this screen

  --examples		show command examples

EOF
}

# Output Functions
pr()
{
	if [ $1 -le $PR_LVL ]; then
		shift;
		echo "$*" > /dev/stderr
	fi
}

pr_error()
{
	pr ${PR_ERR} "ERROR: " $*
}

pr_warn()
{
	pr ${PR_WARN} "WARNING: " $*
}

pr_info()
{
	pr ${PR_INFO} "INFO: " $*
}

pr_dbg()
{
	pr ${PR_DBG} "DEBUG: " $*
}

to_stdout()
{
	return ${STDOUT}
}

create_output_file()
{
	local f=$1

	if [ ! -d "${OUTPUT_TMP_DIR}" ]; then
		OUTPUT_TMP_DIR=$(LANG=C mktemp -d /tmp/bond2team.XXXXXX)
	fi

	if [ ! -d "${OUTPUT_TMP_DIR}" ]; then
		pr_error "${FUNCNAME} can't create dir ${OUTPUT_TMP_DIR}"
		return 1
	fi

	local tmpfile=${OUTPUT_TMP_DIR}/${f}
	touch ${tmpfile}
	if [ ! -f ${tmpfile} ]; then
		pr_error "${FUNCNAME} can't create file ${tmpfile}"
		return 1
	fi

	local pos=${#TMP_FILES[*]}
	TMP_FILES[${pos}]="${tmpfile}"
	OUTPUT_FILE=${tmpfile}
}

show_output_files()
{
	echo ""
	echo "Resulted files:"
	for tmpf in $(seq 0 $((${#TMP_FILES[@]} - 1)))
	do
		echo "  ${TMP_FILES[$tmpf]}"
	done
}

clean_up()
{
	pr_dbg "${FUNCNAME} $*"
	for tmpf in $(seq 0 $((${#TMP_FILES[@]} - 1)))
	do
		pr_dbg "rm -f ${TMP_FILES[$tmpf]}"
		rm -f ${TMP_FILES[$tmpf]}
	done

	if [ -d "{OUTPUT_TMP_DIR}" ]; then
		rmdir ${OUTPUT_TMP_DIR}
	fi
}

ifcfg_get_device()
{
	local ifcfg=$1
	if [ ! -f ${ifcfg} ]; then
		pr_error "file not found: ${ifcfg}"
		return 1
	fi

	DEVICE=`LANG=C sed -n \
		"s@^[[:space:]]*DEVICE=[\"]*\(.*\)\([[:space:]#]\|\"\|$\)@\1@p" \
		$ifcfg`

	if [ -z "${DEVICE}" ]; then
		pr_error "ifcfg file not supported: ${ifcfg}"
		return 1
	fi
}

ifcfg_get_master_file()
{
	local dev=${1}
	MASTER="${dev}"

	if [ "${MODE}" -eq "${MODE_NOIFCFG}" ]; then
		return 0
	fi

	if [ ! -f ${MASTER} ]; then
		MASTER="${CONFIGDIR}/ifcfg-${dev}"
		if [ -f ${MASTER} ]; then
			return 0
		fi

		if [ -n "${BONDING_OPTS}" ]; then
			# options provided, set noifcfg
			MODE=${MODE_NOIFCFG}
			MASTER=${dev}
			return 0
		fi

		pr_error "Can't find ifcfg file for ${dev}"
		return 1
	fi

	return 0
}

ifcfg_overwrite_files()
{
	pr_dbg "${FUNCNAME} $*"

	/bin/cp -f ${OUTPUT_TMP_DIR}/ifcfg* ${OUTPUT_DIR}
}

ifcfg_get_bond_opts()
{
	pr_dbg "${FUNCNAME} $*"
	local ifcfg=$1

	if [ -n "${BONDING_OPTS}" ]; then
		pr_dbg "${FUNCNAME} bonding_opts=${BONDING_OPTS}"
		return 0
	fi

	if [ ! -f ${ifcfg} ]; then
		pr_error "File not found: ${ifcfg}"
		return 1
	fi

	BONDING_OPTS=`LANG=C sed -n \
		"s@^[[:space:]]*BONDING_OPTS=[\"]*\(.*\)\([[:space:]#]\|\"\|$\)@\1@p" \
		$ifcfg`

	if [ -z "${BONDING_OPTS}" ]; then
		pr_error "ifcfg file not supported: ${MASTER}"
		return 1
	fi

	pr_dbg "${FUNCNAME} bonding_opts=${BONDING_OPTS}"
	return 0
}

vfile_reset()
{
	VFILE=()
}

vfile_load_ifcfg()
{
	pr_dbg "${FUNCNAME} $*"
	local ifcfg=$1

	vfile_reset

	if [ ${MODE} -eq ${MODE_NOIFCFG} ]; then
		return 0
	fi

	# filter out bonding and team options and
	#  don't break lines with spaces
	oIFS="$IFS"
	IFS=$'\n'
	VFILE=( $(LANG=C \
		grep -iv 'BONDING_OPTS\|SLAVE\|MASTER\|TYPE\|DEVICETYPE\|TEAM' \
		$ifcfg ))
	IFS="$oIFS"
}

vfile_write_to_file()
{
	pr_dbg "${FUNCNAME} $*"
	local output=$1
	for ln in $(seq 0 $((${#VFILE[@]} - 1)))
	do
		echo "${VFILE[$ln]}" >> $output
	done

	return 0
}

ifcfg_dump_stdout()
{
	local dev="${1}"
	local ifcfg="ifcfg-${dev}"
	if [ -z "${dev}" ]; then
		ifcfg="ifcfg-<interface name>"
	fi

	for ln in $(seq 0 $((${#VFILE[@]} - 1)))
	do
		[ $ln -eq 0 ] && echo "---8<--- ${ifcfg} ---8<---"
		echo "${VFILE[$ln]}"
	done

	echo "---8<--- ${ifcfg} ---8<---"
	echo ""

	return 0
}

vfile_get_device()
{
	pr_dbg "${FUNCNAME} $*"
	if [ ${MODE} -eq ${MODE_NOIFCFG} ]; then
		pr_dbg "${FUNCNAME} using DEVICE=${MASTER}"
		DEVICE=${MASTER}
		return 0
	fi

	for ln in $(seq 0 $((${#VFILE[@]} - 1)))
	do
		local line=${VFILE[$ln]}
		if [ "${line%%=*}" = "DEVICE" ]; then
			local name_line="${line##*=}"
			local name="${name_line%%[ #	]*}"
			DEVICE=${name}
			pr_dbg "${FUNCNAME} from file: DEVICE=${DEVICE}"
			return 0
		fi
	done

	pr_error "Failed to find the device's name"
	return 1
}

vfile_get_ipaddr()
{
	for ln in $(seq 0 $((${#VFILE[@]} - 1)))
	do
		local line=${VFILE[$ln]}
		if [ "${line%%=*}" = "IPADDR" ]; then
			local ipaddr_line="${line##*=}"
			local ipaddr="${ipaddr_line%%[ #	]*}"
			echo "${ipaddr}"
		fi
	done
}

vfile_add_line()
{
	pr_dbg "${FUNCNAME} $*"
	local pos=${#VFILE[*]}
	VFILE[${pos}]="$1"
}

ifcfg_device_rename()
{
	local device=$1
	local rename=$2

	# neither device nor rename was provided
	if [ -z "${rename}" ]; then
		return 0
	fi

	# renaming with no ifcfg?
	if [ ${MODE} -eq ${MODE_NOIFCFG} ]; then
		return 0
	fi

	for ln in $(seq 0 $((${#VFILE[@]} - 1)))
	do
		local line=${VFILE[$ln]}
		if [ "${line%%=*}" = "DEVICE" ]; then
			newdev="${line/${device}/${rename}}"
			VFILE[$ln]="$newdev"
			TEAM_MASTER=${rename}
			return 0
		fi
	done
	pr_error "Failed to rename $device to $rename"
	return 1
}

team_port_set_devtype()
{
	pr_dbg "${FUNCNAME} $*"
	local master=$1
	vfile_add_line "DEVICETYPE=\"TeamPort\""
	vfile_add_line "TEAM_MASTER=\"$master\""
}

team_port_set_config()
{
	pr_dbg "${FUNCNAME} $*"
	local port=$1
	local team_port_config=""

	if [ "${PRIMARY}" ==  "$port" ]; then
		team_port_config="'{ \"prio\" : -10"
	else
		team_port_config="'{ \"prio\" : -100"
	fi

	if [ -n "${PRIMARY_RESELECT}" ]; then
		if [ "${PRIMARY}" ==  "$port" ]; then
			if [ -z "${team_port_config}" ]; then
				team_port_config="'{ \"sticky\" : true }'"
			else
				team_port_config="${team_port_config}, \"sticky\" : true }'"
			fi
		else
			if [ -z "${team_port_config}" ]; then
				team_port_config="{ \"sticky\" : false }'"
			else
				team_port_config="${team_port_config}, \"sticky\" : false }'"
			fi
		fi
	else
		if [ -n "${team_port_config}" ]; then
			team_port_config="${team_port_config} }'"
		fi

	fi

	if [ -n "$team_port_config" ]; then
		vfile_add_line "TEAM_PORT_CONFIG=$team_port_config"
	fi
}

team_port_ifcfg_create()
{
	local dev=$1
	vfile_load_ifcfg $dev

	if ! vfile_get_device; then
		return  1
	fi

	team_port_set_devtype ${TEAM_MASTER}
	team_port_set_config ${DEVICE}
	return 0
}

team_master_set_devtype()
{
	pr_dbg "${FUNCNAME} $*"
	vfile_add_line "DEVICETYPE=\"Team\""
}

team_master_set_config()
{
	pr_dbg "${FUNCNAME} $*"
	local team_config="'{ \"runner\" : { "
	local nr_opt=0

	nr_opt=${#RUNNER_OPTS[@]}
	if [ $nr_opt -eq 0 ]; then
		# default to miimon/ethtool
		team_config="${team_config} \"name\" : \"roundrobin\" }"
	else
		# add runner options
		for pos in $(seq 0 $((${#RUNNER_OPTS[@]} - 1)))
		do
			if [ $pos -ne 0 ]; then
				team_config="${team_config}, "
			fi

			team_config="${team_config} ${RUNNER_OPTS[$pos]}"
		done

		team_config="${team_config} }"
	fi

	nr_opt=${#LWATCH_OPTS[@]}
	if [ $nr_opt -eq 0 ]; then
		# default to miimon/ethtool
		team_config="${team_config}, \"link_watch\" : { \"name\" : \"ethtool\" }"
	else
		team_config="${team_config}, \"link_watch\" : { "
		# add linkwatch options
		for pos in $(seq 0 $(($nr_opt - 1)))
		do
			if [ $pos -ne 0 ]; then
				team_config="${team_config}, "
			fi

			team_config="${team_config} ${LWATCH_OPTS[$pos]}"
		done

		team_config="${team_config} }"

	fi

	team_config="${team_config} }'"
	pr_dbg "built team_config=${team_config}"
	vfile_add_line "TEAM_CONFIG=${team_config}"
	return 0
}

team_ifcfg_dump_stdout()
{
	pr_dbg "${FUNCNAME} $*"
	local dev=$1
	if ! ifcfg_dump_stdout ${dev}; then
		return 1
	fi

	return 0
}

team_ifcfg_write_file()
{
	pr_dbg "${FUNCNAME} $*"
	local dev=$1
	OUTPUT_FILE=

	local filenm="ifcfg-${dev}"
	if [ -z "${dev}" ]; then
		filenm="ifcfg"
	fi

	create_output_file ${filenm}
	if [ ! -f "${OUTPUT_FILE}" ]; then
		return 1
	fi

	if ! vfile_write_to_file ${OUTPUT_FILE}; then
		return 1
	fi

	return 0
}

team_master_ifcfg_create()
{
	pr_dbg "${FUNCNAME} $*"
	if ! team_master_set_devtype; then
		return 1
	fi

	if ! team_master_set_config; then
		return 1
	fi

	return 0
}

team_ifcfg_write()
{
	pr_dbg "${FUNCNAME} $*"
	local dev=${1}

	if to_stdout; then
		team_ifcfg_dump_stdout ${dev} || return 1
	else
		team_ifcfg_write_file ${dev} || return 1
	fi

	return 0
}

team_ifcfg_deliver()
{
	pr_dbg "${FUNCNAME} $*"
	if to_stdout; then
		return 0
	fi

	if [ -z "${OUTPUT_DIR}" ]; then
		show_output_files
	else
		ifcfg_overwrite_files
		clean_up
	fi

	return 0
}

teamd_config_create()
{
	vfile_reset
	vfile_add_line "{"
	# add runner options
	vfile_add_line "  \"device\" : \"${DEVICE}\","
	vfile_add_line "  \"runner\" : {"
	local runner_nr=${#RUNNER_OPTS[@]}
	if [ ${runner_nr} -eq 0 ]; then
		# default roundrobin
		vfile_add_line "     \"runner\" : \"roundrobin\" "
	else
		local last_pos=$((${runner_nr} - 1))
		for pos in $(seq 0 ${last_pos})
		do
			if [ $pos -eq ${last_pos} ]; then
				vfile_add_line "     ${RUNNER_OPTS[$pos]}"
			else
				vfile_add_line "     ${RUNNER_OPTS[$pos]},"
			fi
		done
	fi

	vfile_add_line "  },"
	vfile_add_line "  \"link_watch\" : {"

	local lwatch_nr=${#LWATCH_OPTS[@]}
	if [ ${lwatch_nr} -eq 0 ]; then
		# default to miimon
		lwatch_add_opt "\"name\" : \"ethtool\""
	else
		for pos in $(seq 0 ${last_pos})
		do
			last_pos=$((${lwatch_nr} - 1))
			if [ $pos -eq ${last_pos} ]; then
				vfile_add_line "     ${LWATCH_OPTS[$pos]}"
			else
				vfile_add_line "     ${LWATCH_OPTS[$pos]},"
			fi
		done
	fi

	vfile_add_line "  },"
	return 0
}

teamd_config_close()
{
	vfile_add_line "}"
	return 0
}

teamd_dump_stdout()
{
	for ln in $(seq 0 $((${#VFILE[@]} - 1)))
	do
		[ $ln -eq 0 ] && echo "---8<--- teamd.conf ---8<---"
		echo "${VFILE[$ln]}"
	done

	echo "---8<--- teamd.conf ---8<---"
	echo ""

	return 0
}

teamd_write_file()
{
	pr_dbg "${FUNCNAME} $*"
	local dev=$1
	OUTPUT_FILE=

	create_output_file "teamd.conf"
	if [ ! -f "${OUTPUT_FILE}" ]; then
		return 1
	fi

	if ! vfile_write_to_file ${OUTPUT_FILE}; then
		return 1
	fi

	return 0
}


teamd_config_write()
{
	pr_dbg "${FUNCNAME} $*"

	if to_stdout; then
		teamd_dump_stdout || return 1
	else
		teamd_write_file ${dev} || return 1
		show_output_files
	fi

	return 0
}

teamd_port_create()
{
	vfile_add_line "  \"ports\" : {"
	return 0
}

teamd_port_close()
{
	vfile_add_line "  }"
	return 0
}

teamd_port_add()
{
	pr_dbg "${FUNCNAME} $*"
	local dev=${1}
	local lastone=${2}

	if [ -n "${PORT_LIST}" ]; then
		DEVICE=${dev}
	else
		if ! ifcfg_get_device ${dev}; then
			return  1
		fi
	fi

	vfile_add_line "    \"${DEVICE}\" : {"
	if [ "${PRIMARY}" ==  "${DEVICE}" ]; then
		vfile_add_line "        \"prio\" : -10,"
	else
		vfile_add_line "        \"prio\" : -100,"
	fi

	if [ -n "${PRIMARY_RESELECT}" ]; then
		if [ "${PRIMARY}" ==  "$port" ]; then
			vfile_add_line "        \"sticky\" : true "
		else
			vfile_add_line "        \"sticky\" : false "
		fi
	else
		vfile_add_line "        \"sticky\" : false "
	fi

	if [ ${lastone} -eq 1 ]; then
		vfile_add_line "    }"
	else
		vfile_add_line "    },"
	fi

	return 0
}

# Runner Functions
runner_add_opt()
{
	pr_dbg "${FUNCNAME} $*"
	local pos=${#RUNNER_OPTS[*]}
	RUNNER_OPTS[${pos}]="$1"
}

runner_parse_adselect()
{
	pr_dbg "${FUNCNAME} $*"
	local value=$1

	case $value in
	"0"|"stable")
		runner_add_opt "\"agg_select_policy\" : \"bandwidth\"" || return 1
		;;
	"1"|"bandwidth")
		runner_add_opt "\"agg_select_policy\" : \"bandwidth\"" || return 1
		;;
	"2"|"count")
		runner_add_opt "\"agg_select_policy\" : \"count\"" || return 1
		;;
	*)
		pr_error "parameter ad_select=$value is not supported"
		return 1
		esac
}

runner_parse_failovermac()
{
	pr_dbg "${FUNCNAME} $*"
	local value=$1

	case $value in
	"0")
		runner_add_opt "\"hwaddr_policy\" : \"same_all\"" || return 1
		;;
	"1"|"active")
		runner_add_opt "\"hwaddr_policy\" : \"by_active\"" || return 1
		;;
	"2"|"follow")
		runner_add_opt "\"hwaddr_policy\" : \"only_active\"" || return 1
		;;
	*)
		pr_error "parameter fail_over_mac $value is not supported"
		return 1
		;;
	esac

}

runner_parse_lacprate()
{
	pr_dbg "${FUNCNAME} $*"
	local value=$1

	case $value in
	"slow"|"0")
		runner_add_opt "\"fast_rate\" : 0" || return 1
		;;
	"fast"|"1")
		runner_add_opt "\"fast_rate\" : 1" || return 1
		;;
	*)
		pr_error "parameter lacp_rate=$value is not supported"
		return 1
		;;
	esac
}

runner_parse_xmit_policy()
{
	pr_dbg "${FUNCNAME} $*"
	local value=$1

	case $value in
	"layer2")
		runner_add_opt "\"tx_hash\" : [ \"eth\" ]" || return 1
		;;
	"layer2+3")
		runner_add_opt "\"tx_hash\" : [ \"eth\", \"l3\" ]" || return 1
		;;
	"layer3+4")
		runner_add_opt "\"tx_hash\" : [ \"l3\", \"l4\" ]" || return 1
		;;
	*)
		pr_error "parameter xmit_hash_policy=$value is not supported"
		return 1
	esac
}

runner_parse_mode()
{
	pr_dbg "${FUNCNAME} $*"
	local value=$1

	case $value in
	"0"|"balance-rr")
		runner_add_opt "\"name\" : \"roundrobin\"" || return 1
		;;
	"1"|"active-backup")
		runner_add_opt "\"name\" : \"activebackup\"" || return 1
		;;
	"2"|"balance-xor")
		# FIXME
		runner_add_opt "\"name\" : \"loadbalance\"" || return 1
		;;
	"3"|"broadcast")
		runner_add_opt "\"name\" : \"broadcast\"" || return 1
		;;
	"4"|"802.3ad")
		runner_add_opt "\"name\" : \"lacp\"" || return 1
		;;
	"5"|"balance-tlb")
		runner_add_opt "\"name\" : \"loadbalance\"" || return 1
		;;
	"6"|"balance-alb")
		pr_error "parameter mode=$value is not supported"
		return 1
		;;
	*)
		pr_error "parameter mode=$value is not supported"
		return 1
		;;
	esac
}

runner_parse_opt()
{
	pr_dbg "${FUNCNAME} $*"
	local param=$1
	local value=$2

	case $param in
	"ad_select")
		runner_parse_adselect $value || return 1
		;;
	"fail_over_mac")
		runner_parse_failovermac $value || return 1
		;;
	"lacp_rate")
		runner_parse_lacprate $value || return 1
		;;
	"min_links")
		runner_add_opt "\"min_ports\" : $value" || return 1
		;;
	"mode")
		runner_parse_mode $value || return 1
		;;
	"xmit_hash_policy")
		runner_parse_xmit_policy $value || return 1
		;;
	esac
}

# Link Watch functions
lwatch_add_opt()
{
	pr_dbg "${FUNCNAME} $*"
	local pos=${#LWATCH_OPTS[*]}
	LWATCH_OPTS[${pos}]="$1"
}

lwatch_parse_arp_validate()
{
	pr_dbg "${FUNCNAME} $*"
	local value=$1

	case $value in
	"0"|"none")
		;;
	"1"|"active")
		lwatch_add_opt "\"validate_active\" : 1" || return 1
		;;
	"2"|"backup")
		lwatch_add_opt "\"validate_inactive\" : 1" || return 1
		;;
	"3"|"all")
		lwatch_add_opt "\"validate_active\" : 1" || return 1
		lwatch_add_opt "\"validate_inactive\" : 1" || return 1
		;;
	*)
		pr_error "parameter arp_validate=$value is not supported"
		return 1
	;;
	esac

}

lwatch_parse_arpiptarget()
{
	#FIXME: supports only one arp_ip_target address.
	# otherwise a new linkwatch section must be create
	pr_dbg "${FUNCNAME} $*"
	local ip_addrs=$1
	local ip_list=${ip_addrs//,/ }
	local ip_array=($ip_list)
	if [ ${#ip_array[*]} -ne 1 ]; then
		pr_error "parameter arp_ip_target= with multiple IP addresses is not supported"
		return 1
	fi

	for addr in ${ip_list}
	do
		lwatch_add_opt "\"target_host\" : \"$addr\""
	done
}

lwatch_parse_opt()
{
	pr_dbg "${FUNCNAME} $*"
	local param=$1
	local value=$2

	case $param in
	"arp_interval")
		lwatch_add_opt "\"interval\" : $value"
		;;
	"arp_ip_target")
		lwatch_add_opt "\"name\" : \"arp_ping\""
		if ! lwatch_parse_arpiptarget $value; then
			return 1
		fi
		;;
	"arp_validate")
		lwatch_parse_arp_validate $value
		;;
	"downdelay")
		lwatch_add_opt "\"delay_down\" : $value"
		;;
	"miimon")
		lwatch_add_opt "\"name\" : \"ethtool\""
		;;
	"updelay")
		lwatch_add_opt "\"delay_up\" : $value"
		;;
	*)
		pr_error "parameter $param=$value is not supported"
		return 1
		;;
	esac
}

port_parse_opt()
{
	pr_dbg "${FUNCNAME} $*"
	local param=$1
	local value=$2

	case $param in
	"primary")
		PRIMARY="$value"
		;;
	"primary_reselect")
		case $value in
		"0"|"always")
			PRIMARY_RESELECT=1
			;;
		"1"|"better")
			;;
		"2"|"failure")
			;;
		*)
			pr_error "parameter $param=$value is not supported"
			return 1
		esac
		;;
	*)
		pr_error "parameter $param=$value is not supported"
		return 1
		;;
	esac

}

convert_bond_opts()
{
	local bonding_opts=$1
	pr_dbg "${FUNCNAME} $*"

	for arg in $bonding_opts
	do
		key=${arg%%=*};
		value=${arg##*=};
		pr_dbg "parsing $key=$value"
		case "$key" in
			"active_slave"|"max_bonds"|"use_carrier")
				pr_info "parameter $key not supported, ignoring"
				continue
				;;
			"all_slaves_active"|"resend_igmp"|"num_grat_arp"|"num_unsol_na")
				pr_error "parameter $key not supported, aborting"
				return 1
				;;
			"ad_select"|"fail_over_mac"|"lacp_rate"|"min_links"|"mode"|"xmit_hash_policy")
				runner_parse_opt $key $value || return 1
				;;
			"arp_interval"|"arp_ip_target"|"arp_validate"|"downdelay"|"miimon"|"updelay")
				lwatch_parse_opt $key $value || return 1
				;;
			"primary"|"primary_reselect")
				port_parse_opt $key $value || return 1
				;;
			*)
				pr_error "unknown parameter $key=$value, aborting"
				return 1
				;;
		esac
	done
}



# Parse command line options
while :;
do
	case "$1" in
	"--master")
		MASTER="$2"
		shift 2
		;;
	"--bonding_opts")
		BONDING_OPTS="$2"
		shift 2
		;;
	"--ifcfg")
		OUTPUT_FORMAT=${FORMAT_IFCFG}
		shift
		;;
	"--json")
		OUTPUT_FORMAT=${FORMAT_JANSSON}
		shift
		;;
        "--quiet")
		PR_LVL=${PR_QUIET}
		shift
		;;
        "--debug")
		PR_LVL=`expr ${PR_LVL} + 1`
		shift
		;;
	"--outputdir")
		OUTPUT_DIR="$2"
		shift 2
		;;
	"--configdir")
		CONFIGDIR="$2"
		shift 2
		;;
	"--rename")
		[ -n "${RENAME}" ] && usage && exit 1
		RENAME="$2"
		shift 2
		;;
	"--stdout")
		STDOUT=0
		shift
		;;
	"--port")
		PORT_LIST="${PORT_LIST} $2"
		shift 2
		;;
	"--version")
		echo "$VERSION"
		exit 0
		;;
	"--help")
		usage
		exit 0
		;;
	"--examples")
		show_examples
		exit 0
		;;
	*)
		if [ -z "$1" ]; then
			break
		fi
		pr_error "unknown parameter: $1"
		usage
		exit 1
		;;
	esac
done

if [ -n "${OUTPUT_DIR}" -a ! -d "${OUTPUT_DIR}" ]; then
	pr_error "Invalid output diretory: ${OUTPUT_DIR}"
	usage
	exit 1
fi

if [ -z "${MASTER}" -a -z "${BONDING_OPTS}" ]; then
	pr_error "No master interface or bonding options specified"
	usage
	exit 1
fi

# no master means no ifcfg to read
if [ -z "${MASTER}" ]; then
	MODE=${MODE_NOIFCFG}
fi

if [ ${OUTPUT_FORMAT} -eq ${FORMAT_JANSSON} -a -z "${MASTER}" ]; then
	MASTER="team0"
fi

if ! ifcfg_get_master_file ${MASTER}; then
	exit 1
fi

# load the ifcfg file
if ! vfile_load_ifcfg ${MASTER}; then
	exit 1
fi

# get the bonding options
if ! ifcfg_get_bond_opts ${MASTER}; then
	exit 1
fi

if ! convert_bond_opts "${BONDING_OPTS}"; then
	exit 1
fi

if ! vfile_get_device; then
	exit 1
fi

TEAM_MASTER=${DEVICE}
if ! ifcfg_device_rename ${DEVICE} ${RENAME}; then
	exit 1
fi

BOND_MASTER=${DEVICE}

if [ ${OUTPUT_FORMAT} -eq ${FORMAT_IFCFG} ]; then
	if ! team_master_ifcfg_create; then
		exit 1
	fi

	if ! team_ifcfg_write ${TEAM_MASTER}; then
		clean_up
		exit 1
	fi

	# process all ports
	for portcfg in $(LANG=C grep -s -l "^[[:space:]]*MASTER=\"\?${BOND_MASTER}\"\?\([[:space:]#]\|$\)" ${CONFIGDIR}/ifcfg-*)
	do
		if ! team_port_ifcfg_create $portcfg; then
			clean_up
			exit 1
		fi

		if ! team_ifcfg_write ${DEVICE}; then
			clean_up
			exit 1
		fi

	done

	team_ifcfg_deliver
else
	if ! teamd_config_create; then
		exit 1
	fi

	if ! teamd_port_create; then
		exit 1
	fi

	if [ -n "${PORT_LIST}" ]; then
		portcfg_list=${PORT_LIST}
	else
		portcfg_list=$(LANG=C grep -s -l "^[[:space:]]*MASTER=\"\?${BOND_MASTER}\"\?\([[:space:]#]\|$\)" ${CONFIGDIR}/ifcfg-*)
	fi
	# count number of ports
	portcfg_total=0
	for portcfg in ${portcfg_list}
	do
		portcfg_total=$((${portcfg_total} + 1))
	done
	# process all ports
	portcfg_nr=0
	lastone=0
	for portcfg in ${portcfg_list}
	do
		portcfg_nr=$((${portcfg_nr} + 1))
		if [ ${portcfg_nr} -eq ${portcfg_total} ]; then
			lastone=1
		fi

		if ! teamd_port_add ${portcfg} ${lastone}; then
			exit 1
		fi
	done

	if ! teamd_port_close; then
		exit 1
	fi

	if ! teamd_config_close; then
		exit 1
	fi

	if ! teamd_config_write; then
		exit 1
	fi

fi
No se encontró la página – Alquiler de Limusinas, Autos Clásicos y Microbuses

Alquiler de Autos Clásicos para Sesiones Fotográficas: Estilo y Elegancia en Cada Toma

Si buscas darle un toque auténtico, elegante o retro a tus fotos, el alquiler de autos clásicos para sesiones fotográficas es la opción ideal. Este tipo de vehículos no solo son íconos del diseño automotriz, sino que se convierten en un elemento visual impactante que transforma cualquier sesión en una experiencia única.


¿Por Qué Usar Autos Clásicos en Sesiones Fotográficas?

1. Estética Visual Única

Un auto clásico aporta personalidad, historia y carácter a tus imágenes. Desde tomas urbanas hasta escenarios naturales, estos vehículos se adaptan a diferentes estilos visuales.

2. Ideal para Diversos Usos

  • Sesiones de boda y pre-boda
  • Campañas publicitarias
  • Editoriales de moda
  • Proyectos cinematográficos
  • Contenido para redes sociales

3. Variedad de Modelos

Desde convertibles vintage hasta muscle cars de los años 60 y 70, puedes elegir el modelo que mejor se ajuste a la estética de tu sesión.


Beneficios del Alquiler Profesional

  • Vehículos en excelente estado estético y mecánico
  • Choferes disponibles si se requiere movilidad
  • Asesoría para elegir el modelo adecuado
  • Posibilidad de ambientación adicional (flores, letreros, decoración retro)

Conclusión: Captura Momentos con Estilo

Un auto clásico puede transformar tu sesión fotográfica en una obra de arte visual. No importa el propósito: el estilo, la elegancia y el impacto están garantizados.


📸 ¡Reserva tu auto clásico y crea fotos memorables!

Consulta disponibilidad y haz de tu sesión algo realmente especial. ¡Llama la atención con cada toma!

Not Found

404

Sorry, the page you’re looking for doesn’t exist.