| #!/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 |