blob: fc81c4b4a6604a42c2968f403effcec10814cb18 [file] [log] [blame]
#!/bin/bash
#
# Translate tool from bonding configuration to team.
#
# Copyright (C) 2013 Flavio Leitner <fbl@redhat.com>
#
# 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\|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