# #
###############################################################################
+BONDING_ALLOWED_MODES="balance-rr active-backup balance-xor broadcast 802.3ad \
+ balance-tlb balance-alb"
+BONDING_MASTERS="/sys/class/net/bonding_masters"
+
function bonding_init() {
if ! grep -q "^bonding" /proc/modules; then
modprobe bonding
function bonding_create() {
local device=${1}
- local mac=${2}
+ assert isset device
+ shift
+
+ local address
+ local mode="balance-rr"
+
+ while [ $# -gt 0 ]; do
+ case "${1}" in
+ --address=*)
+ address=$(cli_get_val ${1})
+ ;;
+ --mode=*)
+ mode=$(cli_get_val ${1})
+ ;;
+ *)
+ error "Unrecognized argument: ${1}"
+ return ${EXIT_ERROR}
+ ;;
+ esac
+ shift
+ done
- [ -z "${mac}" ] && mac=$(mac_generate)
+ if isset address; then
+ if ! ismac address; then
+ log ERROR "Invalid mac address: ${address}"
+ return ${EXIT_ERROR}
+ fi
+ fi
+
+ if ! list_match "${mode}" ${BONDING_ALLOWED_MODES}; then
+ log ERROR "Bonding mode is not supported: ${mode}"
+ log ERROR "Valid modes are: ${BONDING_ALLOWED_MODES}"
+ return ${EXIT_ERROR}
+ fi
# Initialize the bonding driver just
# when we need it.
bonding_init
- log INFO "Creating bonding device '${device}' (${mac})."
+ # Create the bonding device.
+ print "+${device}" > ${BONDING_MASTERS}
+ local ret=$?
- echo "+${device}" > /sys/class/net/bonding_masters
- device_set_address ${device} ${mac}
+ if [ ${ret} -eq ${EXIT_OK} ]; then
+ log DEBUG "Successfully created bonding device '${device}'"
+ else
+ log ERROR "Could not create bonding device '${device}'"
+ return ${EXIT_ERROR}
+ fi
+
+ # Set the mode of the bonding device.
+ print "${mode}" > ${SYS_CLASS_NET}/${device}/bonding/mode
+ local ret=$?
+
+ if [ ${ret} -ne ${EXIT_OK} ]; then
+ log ERROR "Could not set mode of bonding device '${device}': ${Mmode}"
+ return ${EXIT_ERROR}
+ fi
+
+ if isset address; then
+ device_set_address ${device} ${address}
+ fi
+
+ return ${EXIT_OK}
}
function bonding_remove() {
local device=${1}
assert isset device
- log INFO "Remove bonding device '${device}'."
+ if ! device_exists ${device}; then
+ return ${EXIT_ERROR}
+ fi
+ # Set device down if not already done.
device_set_down ${device}
- echo "-${device}" > /sys/class/net/bonding_masters
-}
-function bonding_set_mode() {
- local device=${1}
- local mode=${2}
+ # Remove the device.
+ print "-${device}" > ${BONDING_MASTERS}
+ local ret=$?
- log INFO "Setting bonding mode on '${device}' '${mode}'."
+ if [ ${ret} -eq ${EXIT_OK} ]; then
+ log DEBUG "Successfully removed bonding device '${device}'"
+ else
+ log ERROR "Could not remove bonding device '${device}'"
+ return ${EXIT_ERROR}
+ fi
- echo "${mode}" > /sys/class/net/${device}/bonding/mode
+ return ${EXIT_OK}
}
function bonding_get_mode() {
local device=${1}
+ assert isset device
local mode mode_num
read mode mode_num < ${SYS_CLASS_NET}/${device}/bonding/mode
- echo "${mode}"
+ print "${mode}"
}
function bonding_enslave_device() {
local device=${1}
+ assert isset device
+
local slave=${2}
+ assert isset slave
+
shift 2
- assert isset device
- assert isset slave
+ # Slave must be down to be enslaved.
+ device_set_down ${device}
+
+ if device_is_up ${device}; then
+ log ERROR "Cannot enslave '${slave}' because it cannot be set down."
+ return ${EXIT_ERROR}
+ fi
- log INFO "Enslaving slave '${slave}' to '${device}'."
+ # Add it.
+ print "+${slave}" > ${SYS_CLASS_NET}/${device}/bonding/slaves
+ local ret=$?
- device_set_down ${slave}
- echo "+${slave}" > /sys/class/net/${device}/bonding/slaves
+ if [ ${ret} -eq ${EXIT_OK} ]; then
+ log DEBUG "Successfully enslaved '${slave}' to '${device}'."
+ else
+ log ERROR "Could not enslave '${slave}' to '${device}'."
+ return ${EXIT_ERROR}
+ fi
+
+ return ${EXIT_OK}
}
function bonding_get_slaves() {
local device=${1}
+ assert isset device
+ shift
+
+ local file="slaves"
+ while [ $# -gt 0 ]; do
+ case "${1}" in
+ --active)
+ file="active_slave"
+ ;;
+ *)
+ error "Unrecognized argument: ${1}"
+ return ${EXIT_ERROR}
+ ;;
+ esac
+ shift
+ done
- cat ${SYS_CLASS_NET}/${device}/bonding/slaves
+ fread ${SYS_CLASS_NET}/${device}/bonding/${file}
+
+ return ${EXIT_OK}
}
-function bonding_get_active_slave() {
+function bonding_get_lacp_rate() {
local device=${1}
+ assert isset device
- cat ${SYS_CLASS_NET}/${device}/bonding/active_slave
-}
+ local rate rateno
+ read -r rate rateno \
+ < ${SYS_CLASS_NET}/${device}/bonding/lacp_rate
-# XXX function bonding_get_lacp_rate?
+ print "${rate}"
+ return ${EXIT_OK}
+}
function bonding_get_miimon() {
local device=${1}
+ assert isset device
- cat ${SYS_CLASS_NET}/${device}/bonding/miimon
+ fread ${SYS_CLASS_NET}/${device}/bonding/miimon
}
function bonding_set_miimon() {
local device=${1}
- local miimon=${2}
-
- echo "${miimon}" > ${SYS_CLASS_NET}/${device}/bonding/miimon
-}
-
-function bonding_device_print() {
- local device=${1}
-
- ethernet_device_print ${device}
+ assert isset device
- echo # Empty line
+ local miimon=${2}
+ assert isset miimon
- printf "${DEVICE_PRINT_LINE1}" "Mode:" "$(bonding_get_mode ${device})"
- printf "${DEVICE_PRINT_LINE1}" "Slaves:" "$(bonding_get_slaves ${device})"
+ print "${miimon}" > ${SYS_CLASS_NET}/${device}/bonding/miimon
}
function bonding_slave_get_master() {
local slave=${1}
-
assert isset slave
- assert device_is_bonded ${slave}
- local device
- for device in $(devices_get_all); do
- if device_is_bonding ${device} && listmatch ${slave} $(bonding_get_slaves ${device}); then
- echo "${device}"
- return ${EXIT_OK}
- fi
- done
+ device_is_bonded ${slave} || return ${EXIT_ERROR}
+
+ local master=$(fread ${SYS_CLASS_NET}/${slave}/master/ifindex)
+ if isset master; then
+ device_ifindex_to_name ${master}
+ return ${EXIT_OK}
+ fi
return ${EXIT_ERROR}
}
local master=$(bonding_slave_get_master ${port})
cli_print_fmt1 2 "Master" "${master}"
- local active
- [ "$(bonding_get_active_slave ${master})" = "${port}" ]
- cli_print_fmt1 2 "Active slave" "$(cli_print_yesno $?)"
+ local mode=$(bonding_get_mode ${master})
+ if [ "${mode}" = "active-backup" ]; then
+ local active_slaves=$(bonding_get_slaves ${master} --active)
+ local active="false"
+ if list_match "${device}" ${active_slaves}; then
+ active="true"
+ fi
+ cli_print_fmt1 2 "Active slave" "$(cli_print_yesno ${active})"
+ fi
+
cli_space
}
function cli_device_bonding() {
local device=${1}
+ assert isset device
cli_headline 2 "Bonding information"
- cli_print_fmt1 2 "Mode" "$(bonding_get_mode ${port})"
- # XXX lacp rate
+ local mode=$(bonding_get_mode ${device})
+
+ cli_print_fmt1 2 "Mode" "${mode}"
+ if [ "${mode}" = "802.3ad" ]; then
+ local lacp_rate=$(bonding_get_lacp_rate ${device})
+ cli_print_fmt1 2 "LACP rate" "${lacp_rate}"
+ fi
cli_space
- local slave slave_prefix
- local slave_active=$(bonding_get_active_slave ${device})
+ local slave slave_suffix
+ local active_slaves=$(bonding_get_slaves ${device} --active)
for slave in $(bonding_get_slaves ${device}); do
- if [ "${slave_active}" = "${slave}" ]; then
- slave_prefix="Slave (active)"
+ # Print the device status.
+ local status
+ case "$(device_get_status ${slave})" in
+ ${STATUS_UP})
+ status=${MSG_DEVICE_STATUS_UP}
+ ;;
+ ${STATUS_DOWN})
+ status=${MSG_DEVICE_STATUS_DOWN}
+ ;;
+ ${STATUS_NOCARRIER})
+ status=${MSG_DEVICE_STATUS_NOCARRIER}
+ ;;
+ *)
+ status=${MSG_DEVICE_STATUS_UNKNOWN}
+ ;;
+ esac
+
+ if list_match "${slave}" ${active_slaves}; then
+ slave_suffix="(active)"
else
- slave_prefix="Slave"
+ slave_suffix=""
fi
- cli_print_fmt1 2 "${slave_prefix}" "${slave}"
+ cli_print_fmt1 2 "Slave ${slave}" "${status} ${slave_suffix}"
done
cli_space
}
. /usr/lib/network/header-port
-HOOK_SETTINGS="HOOK DEVICE_MAC MIIMON MODE SLAVES"
+HOOK_SETTINGS="HOOK ADDRESS MIIMON MODE SLAVES"
-PORT_CHILDREN_VAR="SLAVES"
-
-DEVICE_MAC=$(mac_generate)
+ADDRESS=$(mac_generate)
+SLAVES=""
MIIMON=100
function _check() {
- assert isset DEVICE_MAC
- assert ismac DEVICE_MAC
+ assert isset ADDRESS
+ assert ismac ADDRESS
#assert isset SLAVES
assert isinteger MIIMON
function _edit() {
local port=${1}
+ assert isset port
shift
while [ $# -gt 0 ]; do
case "${1}" in
- --mac=*)
- DEVICE_MAC=${1#--mac=}
+ --address=*)
+ ADDRESS=$(cli_get_val ${1})
;;
--miimon=*)
- MIIMON=${1#--miimon=}
+ MIIMON=$(cli_get_val ${1})
;;
--mode=*)
- MODE=${1#--mode=}
+ MODE=$(cli_get_val ${1})
;;
--slave=*)
- slave=${1#--slave=}
- SLAVES="${SLAVES} $(macify ${slave})"
+ slave=$(cli_get_val ${1})
+ SLAVES="${SLAVES} ${slave}"
;;
*)
warning "Unknown argument '${1}'"
fi
local slave
- for slave in ${SLAVES}; do
- if ! device_is_ethernet $(devicify ${slave}); then
+ for slave in $(unquote ${SLAVES}); do
+ if ! device_is_ethernet ${slave}; then
error "Slave device '${slave}' is not an ethernet device."
exit ${EXIT_ERROR}
fi
# Remove any whitespace
SLAVES=$(echo ${SLAVES})
- config_write $(port_file ${port}) ${HOOK_SETTINGS}
+ port_config_write ${port} ${HOOK_SETTINGS}
exit ${EXIT_OK}
}
function _up() {
local device=${1}
+ assert isset device
- config_read $(port_file ${device})
+ port_config_read ${device}
if device_exists ${device}; then
log DEBUG "Bonding device '${device}' does already exist."
- device_set_address ${DEVICE_MAC}
+ device_set_address ${device} ${ADDRESS}
device_set_up ${device}
exit ${EXIT_OK}
fi
- bonding_create ${device} ${DEVICE_MAC}
- assert device_exists ${device}
+ bonding_create ${device} --address="${ADDRESS}" --mode="${MODE}"
+ local ret=$?
- if [ -n "${MODE}" ]; then
- bonding_set_mode ${device} ${MODE}
- fi
+ [ ${ret} -eq ${EXIT_OK} ] || exit ${EXIT_ERROR}
bonding_set_miimon ${device} ${MIIMON}
device_set_up ${device}
local slave
- for slave in ${SLAVES}; do
- if ! device_exists $(devicify ${slave}); then
+ for slave in $(unquote ${SLAVES}); do
+ if ! device_exists ${slave}; then
warning_log "${device}: configured slave '${slave}' is not available."
continue
fi
-
- slave=$(devicify ${slave})
- assert isset slave
bonding_enslave_device ${device} ${slave}
done
+ # Bring up the device.
+ device_set_up ${device}
+
exit ${EXIT_OK}
}
exit ${EXIT_OK}
}
-
-function _status() {
- local port=${1}
- shift
-
- assert isset port
-
- echo "${port}"
-
- local status=$(device_get_status ${port})
- # XXX STATUS_COLOUR AND STATUS_TEXT DO NOT EXIST ANYMORE
- printf "${DEVICE_PRINT_LINE1}" "Status:" "$(echo -ne ${STATUS_COLOUR[${status}]}${STATUS_TEXT[${status}]}${COLOUR_NORMAL})"
-
- cli_headline " Ethernet information:"
- printf "${DEVICE_PRINT_LINE1}" "Address:" $(device_get_address ${port})
- printf "${DEVICE_PRINT_LINE1}" "MTU:" $(device_get_mtu ${port})
- printf "${DEVICE_PRINT_LINE1}" "Promisc mode:" $(device_is_promisc ${port} && echo "yes" || echo "no")
-
- if device_is_bonded ${port}; then
- cli_headline " Bonding information:"
-
- local master=$(bonding_slave_get_master ${port})
- printf "${DEVICE_PRINT_LINE1}" "Master:" "${master}"
-
- local active
- if [ "$(bonding_get_active_slave ${master})" = "${port}" ]; then
- active="yes"
- else
- active="no"
- fi
- printf "${DEVICE_PRINT_LINE1}" "Active slave:" "${active}"
- fi
-
- if device_is_bonding ${port}; then
- cli_headline " Bonding information:"
-
- printf "${DEVICE_PRINT_LINE1}" "Mode:" "$(bonding_get_mode ${port})"
- # XXX lacp rate
- echo
-
- local slave
- local slave_active=$(bonding_get_active_slave ${port})
- for slave in $(bonding_get_slaves ${port}); do
- printf "${DEVICE_PRINT_LINE1}" "Slave$([ "${slave}" = "${slave_active}" ] && echo " (active)"):" "${slave}"
- done
- fi
-
- cli_headline " Statistics:"
- printf "${DEVICE_PRINT_LINE1}" "Received:" \
- "$(beautify_bytes $(device_get_rx_bytes ${port})) ($(device_get_rx_packets ${port}) packets)"
- printf "${DEVICE_PRINT_LINE1}" "Sent:" \
- "$(beautify_bytes $(device_get_tx_bytes ${port})) ($(device_get_tx_packets ${port}) packets)"
-
- echo
-
- exit ${EXIT_OK}
-}