# #
###############################################################################
-function devicify() {
- local device=${1}
-
- assert isset device
-
- if device_exists ${device}; then
- echo "${device}"
- return ${EXIT_OK}
- fi
-
- local d
- for d in $(devices_get_all); do
- if [ "$(device_get_address ${d})" = "${device}" ]; then
- echo "${d}"
- return ${EXIT_OK}
- fi
- done
-
- return ${EXIT_ERROR}
-}
-
-function macify() {
- local device=${1}
+device_list() {
+ local devices
- assert isset device
+ # Add all interfaces
+ list_append devices $(devices_get_all)
- if mac_is_valid ${device}; then
- echo "${device}"
- return ${EXIT_OK}
- fi
+ # Add all PHYs
+ list_append devices $(phy_list)
- if device_exists ${device}; then
- device_get_address ${device}
- return ${EXIT_OK}
- fi
+ # Add all serial devices
+ list_append devices $(serial_list)
- return ${EXIT_ERROR}
+ # Return a sorted result
+ list_sort ${devices}
}
# Check if the device exists
-function device_exists() {
+device_exists() {
local device=${1}
# If device name was not found, exit.
# Check for a normal network device.
[ -d "${SYS_CLASS_NET}/${device}" ] && return ${EXIT_OK}
- # If the check above, did not find a result,
+ # If the check above did not find a result,
+ # we check for PHYs.
+ phy_exists "${device}" && return ${EXIT_OK}
+
+ # If the check above did not find a result,
# we check for serial devices.
serial_exists ${device}
}
-function device_delete() {
+device_matches_pattern() {
+ local device="${1}"
+ assert isset device
+
+ local pattern="${2}"
+ assert isset pattern
+
+ pattern="^${pattern//N/[[:digit:]]+}$"
+
+ [[ ${device} =~ ${pattern} ]] \
+ && return ${EXIT_TRUE} || return ${EXIT_FALSE}
+}
+
+device_delete() {
local device=${1}
assert isset device
return ${ret}
}
-function device_has_flag() {
+device_has_flag() {
local device=${1}
local flag=${2}
}
# Check if the device is up
-function device_is_up() {
+device_is_up() {
local device=${1}
device_exists ${device} || return ${EXIT_ERROR}
device_has_flag ${device} 0x1
}
-function device_ifindex_to_name() {
+device_ifindex_to_name() {
local idx=${1}
assert isset idx
return ${EXIT_ERROR}
}
-function device_get_ifindex() {
+device_get_ifindex() {
local device=${1}
assert isset device
}
# Check if the device is a batman-adv bridge
-function device_is_batman_adv() {
+device_is_batman_adv() {
[ -d "${SYS_CLASS_NET}/${1}/mesh" ]
}
-# Check if the device is a batman-adv bridge port
-function device_is_batman_adv_port() {
- [ -d "${SYS_CLASS_NET}/${1}/batman_adv" ]
+# Check if the device is a batman-adv slave port
+device_is_batman_adv_slave() {
+ local device="${1}"
+
+ if [ -d "${SYS_CLASS_NET}/${device}/batman_adv" ]; then
+ local status="$(<${SYS_CLASS_NET}/${device}/batman_adv/iface_status)"
+
+ case "${status}" in
+ "active")
+ return ${EXIT_TRUE}
+ ;;
+ *)
+ return ${EXIT_FALSE}
+ ;;
+ esac
+ fi
+
+ return ${EXIT_FALSE}
}
# Check if the device is a bonding device
-function device_is_bonding() {
+device_is_bonding() {
[ -d "/sys/class/net/${1}/bonding" ]
}
# Check if the device bonded in a bonding device
-function device_is_bonded() {
+device_is_bonded() {
local device=${1}
- [ -d "${SYS_CLASS_NET}/${device}/master" ]
+ [ -d "${SYS_CLASS_NET}/${device}/bonding_slave" ]
}
# Check if the device is a bridge
-function device_is_bridge() {
+device_is_bridge() {
[ -d "/sys/class/net/${1}/bridge" ]
}
-function device_is_bridge_attached() {
+device_is_bridge_attached() {
local device=${1}
[ -d "${SYS_CLASS_NET}/${device}/brport" ]
}
-function device_get_bridge() {
+device_is_wireless_monitor() {
+ local device="${1}"
+ assert isset device
+
+ device_is_wireless "${device}" && \
+ device_matches_pattern "${device}" "${PORT_PATTERN_WIRELESS_MONITOR}"
+}
+
+device_is_wireless_adhoc() {
+ local device="${1}"
+ assert isset device
+
+ device_is_wireless "${device}" && \
+ device_matches_pattern "${device}" "${PORT_PATTERN_WIRELESS_ADHOC}"
+}
+
+device_get_bridge() {
local device=${1}
assert isset device
}
# Check if the device is a vlan device
-function device_is_vlan() {
+device_is_vlan() {
local device=${1}
assert isset device
}
# Check if the device has vlan devices
-function device_has_vlans() {
+device_has_vlans() {
local device=${1}
assert isset device
[ -n "${vlans}" ] && return ${EXIT_OK} || return ${EXIT_ERROR}
}
-function device_get_vlans() {
+device_get_vlans() {
local device=${1}
assert isset device
}
# Check if the device is a ppp device
-function device_is_ppp() {
+device_is_ppp() {
local device=${1}
local type=$(__device_get_file ${device} type)
}
# Check if the device is a pointopoint device.
-function device_is_ptp() {
+device_is_ptp() {
local device=${1}
device_has_flag ${device} 0x10
}
# Check if the device is a loopback device
-function device_is_loopback() {
+device_is_loopback() {
local device=${1}
[ "${device}" = "lo" ]
}
+# Check if the device is a dummy device
+# This is the worst possible check, but all I could come up with
+device_is_dummy() {
+ local device="${1}"
+
+ [[ ${device} =~ ^dummy[0-9]+$ ]]
+}
+
# Check if the device is a wireless device
-function device_is_wireless() {
+device_is_wireless() {
local device=${1}
[ -d "${SYS_CLASS_NET}/${device}/phy80211" ]
}
-function device_get_phy() {
+device_get_phy() {
local device="${1}"
if device_is_wireless "${device}"; then
return ${EXIT_ERROR}
}
-function device_is_serial() {
+device_is_phy() {
+ phy_exists $@
+}
+
+device_is_serial() {
serial_exists $@
}
+# Returns true if a device is a tun device
+device_is_tun() {
+ local device="${1}"
+
+ [ -e "${SYS_CLASS_NET}/${device}/tun_flags" ]
+}
+
# Check if the device is a physical network interface
-function device_is_ethernet() {
+device_is_ethernet() {
local device=${1}
+ device_is_ethernet_compatible "${device}" || \
+ return ${EXIT_ERROR}
+
device_is_loopback ${device} && \
return ${EXIT_ERROR}
device_is_vlan ${device} && \
return ${EXIT_ERROR}
- [ "$(__device_get_file ${device} type)" != "1" ] && \
+ device_is_dummy ${device} && \
+ return ${EXIT_ERROR}
+
+ device_is_tun ${device} && \
return ${EXIT_ERROR}
return ${EXIT_OK}
}
# Get the device type
-function device_get_type() {
+device_get_type() {
local device=${1}
- if device_is_vlan ${device}; then
+ # If the device does not exist (happens on udev remove events),
+ # we do not bother to run all checks.
+ if ! device_exists "${device}"; then
+ echo "unknown"
+
+ elif device_is_vlan ${device}; then
echo "vlan"
elif device_is_bonding ${device}; then
elif device_is_batman_adv ${device}; then
echo "batman-adv"
- elif device_is_batman_adv_port ${device}; then
- echo "batman-adv-port"
-
elif device_is_loopback ${device}; then
echo "loopback"
+ elif device_is_wireless_adhoc ${device}; then
+ echo "wireless-adhoc"
+
elif device_is_wireless ${device}; then
echo "wireless"
+ elif device_is_dummy ${device}; then
+ echo "dummy"
+
+ elif device_is_tun ${device}; then
+ echo "tun"
+
elif device_is_ethernet ${device}; then
echo "ethernet"
elif device_is_serial ${device}; then
echo "serial"
+ elif device_is_phy ${device}; then
+ echo "phy"
+
else
echo "unknown"
fi
}
-function device_get_status() {
+device_is_ethernet_compatible() {
+ local device="${1}"
+
+ # /sys/class/net/*/type must equal 1 for ethernet compatible devices
+ local type="$(__device_get_file "${device}" "type")"
+ [[ "${type}" = "1" ]]
+}
+
+device_get_status() {
local device=${1}
assert isset device
echo "${status}"
}
-function device_get_address() {
+device_get_address() {
local device=${1}
cat ${SYS_CLASS_NET}/${device}/address 2>/dev/null
}
-function device_set_address() {
- local device=${1}
- local addr=${2}
+device_set_address() {
+ assert [ $# -eq 2 ]
+
+ local device="${1}"
+ local addr="${2}"
- if ! device_exists ${device}; then
+ if ! device_exists "${device}"; then
error "Device '${device}' does not exist."
return ${EXIT_ERROR}
fi
- log INFO "Setting address of '${device}' to '${addr}' - was $(device_get_address ${device})."
+ # Do nothing if the address has not changed
+ local old_addr="$(device_get_address "${device}")"
+ if [ -n "${old_addr}" -a "${addr}" = "${old_addr}" ]; then
+ return ${EXIT_OK}
+ fi
+
+ log DEBUG "Setting address of '${device}' from '${old_addr}' to '${addr}'"
local up
- if device_is_up ${device}; then
- device_set_down ${device}
+ if device_is_up "${device}"; then
+ device_set_down "${device}"
up=1
fi
- ip link set ${device} address ${addr}
+ ip link set "${device}" address "${addr}"
local ret=$?
if [ "${up}" = "1" ]; then
- device_set_up ${device}
+ device_set_up "${device}"
fi
if [ "${ret}" != "0" ]; then
- error_log "Could not set address '${addr}' on device '${device}'."
+ error_log "Could not set address '${addr}' on device '${device}'"
fi
return ${ret}
}
-function device_get() {
+device_get() {
local device
local devices
return ${EXIT_OK}
}
-function devices_get_all() {
+devices_get_all() {
device_get
}
# Check if a device has a cable plugged in
-function device_has_carrier() {
+device_has_carrier() {
local device=${1}
assert isset device
[ "${carrier}" = "1" ]
}
-function device_is_promisc() {
+device_is_promisc() {
local device=${1}
device_has_flag ${device} 0x200
}
-function device_set_promisc() {
+device_set_promisc() {
local device=${1}
local state=${2}
}
# Check if the device is free
-function device_is_free() {
+device_is_free() {
! device_is_used $@
}
# Check if the device is used
-function device_is_used() {
+device_is_used() {
local device=${1}
device_has_vlans ${device} && \
return ${EXIT_ERROR}
}
-function device_hash() {
- local device=${1}
-
- # Get mac address of device and remove all colons (:)
- # that will result in a hash.
- device=$(macify ${device})
-
- echo "${device//:/}"
-}
-
# Give the device a new name
-function device_set_name() {
+device_set_name() {
local source=$1
local destination=${2}
}
# Set device up
-function device_set_up() {
- local device=${1}
+device_set_up() {
+ assert [ $# -eq 1 ]
- # Silently fail if device was not found
- [ -z "${device}" ] && return ${EXIT_ERROR}
+ local device=${1}
# Do nothing if device is already up
device_is_up ${device} && return ${EXIT_OK}
+ log INFO "Bringing up ${device}"
+
device_set_parent_up ${device}
+ if ! cmd ip link set ${device} up; then
+ return ${EXIT_ERROR}
+ fi
- log DEBUG "Setting up device '${device}'"
+ # Set SMP affinity
+ if interrupt_use_smp_affinity; then
+ device_auto_configure_smp_affinity "${port}"
+ fi
- ip link set ${device} up
+ return ${EXIT_OK}
}
-function device_set_parent_up() {
+device_set_parent_up() {
local device=${1}
local parent
}
# Set device down
-function device_set_down() {
- local device=${1}
- assert isset device
+device_set_down() {
+ assert [ $# -eq 1 ]
+ local device=${1}
local ret=${EXIT_OK}
if device_is_up ${device}; then
- log DEBUG "Tearing down device '${device}'"
+ log INFO "Bringing down ${device}"
- ip link set ${device} down
+ cmd ip link set ${device} down
ret=$?
fi
return ${ret}
}
-function device_set_parent_down() {
+device_set_parent_down() {
local device=${1}
local parent
return ${EXIT_OK}
}
-function device_get_mtu() {
+device_get_mtu() {
local device=${1}
- if ! device_exists ${device}; then
- error "Device '${device}' does not exist."
- return ${EXIT_ERROR}
- fi
+ # Return an error if the device does not exist
+ device_exists ${device} || return ${EXIT_ERROR}
echo $(<${SYS_CLASS_NET}/${device}/mtu)
}
# Set mtu to a device
-function device_set_mtu() {
+device_set_mtu() {
local device=${1}
local mtu=${2}
- if ! device_exists ${device}; then
- error "Device '${device}' does not exist."
- return ${EXIT_ERROR}
- fi
-
- local oldmtu=$(device_get_mtu ${device})
-
- if [ "${oldmtu}" = "${mtu}" ]; then
- # No need to set mtu.
- return ${EXIT_OK}
- fi
+ assert device_exists ${device}
- log INFO "Setting mtu of '${device}' to '${mtu}' - was ${oldmtu}."
+ log INFO "Setting MTU of ${device} to ${mtu}"
local up
if device_is_up ${device}; then
up=1
fi
- ip link set ${device} mtu ${mtu}
- local ret=$?
+ local ret=${EXIT_OK}
+ if ! cmd ip link set ${device} mtu ${mtu}; then
+ ret=${EXIT_ERROR}
- if [ "${up}" = "1" ]; then
- device_set_up ${device}
+ log ERROR "Could not set MTU ${mtu} on ${device}"
fi
- if [ "${ret}" != "0" ]; then
- error_log "Could not set mtu '${mtu}' on device '${device}'."
+ if [ "${up}" = "1" ]; then
+ device_set_up ${device}
fi
return ${ret}
}
-function device_discover() {
+device_adjust_mtu() {
+ assert [ $# -eq 2 ]
+
+ local device="${1}"
+ local other_device="${2}"
+
+ local mtu="$(device_get_mtu "${other_device}")"
+ device_set_mtu "${device}" "${mtu}"
+}
+
+device_discover() {
local device=${1}
log INFO "Running discovery process on device '${device}'."
done
}
-function device_has_ip() {
+device_identify() {
+ assert [ $# -ge 1 ]
+
+ local device="${1}"
+
+ # Flash for ten seconds by default
+ local seconds="10"
+
+ # Run in background?
+ local background="false"
+
+ local arg
+ while read arg; do
+ case "${arg}" in
+ --background)
+ background="true"
+ ;;
+ --seconds=*)
+ seconds="$(cli_get_val "${arg}")"
+ ;;
+ esac
+ done <<< "$(args $@)"
+
+ assert isinteger seconds
+
+ if ! device_exists "${device}"; then
+ log ERROR "Cannot identify device ${device}: Does not exist"
+ return ${EXIT_ERROR}
+ fi
+
+ if ! device_is_ethernet "${device}"; then
+ log DEBUG "Cannot identify device ${device}: Not an ethernet device"
+ return ${EXIT_NOT_SUPPORTED}
+ fi
+
+ log DEBUG "Identifying device ${device}"
+
+ local command="ethtool --identify ${device} ${seconds}"
+ local ret=0
+
+ if enabled background; then
+ cmd_background "${command}"
+ else
+ cmd_quiet "${command}"
+ ret=$?
+ fi
+
+ return ${ret}
+}
+
+device_has_ip() {
local device=${1}
local addr=${2}
local protocol=$(ip_detect_protocol ${addr})
case "${protocol}" in
ipv6)
- addr=$(ipv6_implode ${addr})
+ addr=$(ipv6_format "${addr}")
;;
esac
listmatch ${addr} $(device_get_addresses ${device})
}
-function device_get_addresses() {
+device_get_addresses() {
local device=${1}
assert device_exists ${device}
done
}
-function __device_get_file() {
+__device_get_file() {
local device=${1}
local file=${2}
echo "$(<${path})"
}
-function device_get_rx_bytes() {
+__device_set_file() {
+ assert [ $# -eq 3 ]
+
+ local device="${1}"
+ local file="${2}"
+ local value="${3}"
+
+ local path="${SYS_CLASS_NET}/${device}/${file}"
+ if [ ! -w "${path}" ]; then
+ log DEBUG "Cannot write to file '${file}' (${value})"
+ return ${EXIT_ERROR}
+ fi
+
+ echo "${value}" > "${path}"
+}
+
+device_get_rx_bytes() {
local device=${1}
__device_get_file ${device} statistics/rx_bytes
}
-function device_get_tx_bytes() {
+device_get_tx_bytes() {
local device=${1}
__device_get_file ${device} statistics/tx_bytes
}
-function device_get_rx_packets() {
+device_get_rx_packets() {
local device=${1}
__device_get_file ${device} statistics/rx_packets
}
-function device_get_tx_packets() {
+device_get_tx_packets() {
local device=${1}
__device_get_file ${device} statistics/tx_packets
}
-function device_get_rx_errors() {
+device_get_rx_errors() {
local device=${1}
__device_get_file ${device} statistics/rx_errors
}
-function device_get_tx_errors() {
+device_get_tx_errors() {
local device=${1}
__device_get_file ${device} statistics/tx_errors
}
-function device_get_speed() {
+device_get_speed() {
local device=${1}
__device_get_file ${device} speed
}
-function device_get_duplex() {
+device_get_duplex() {
local device=${1}
__device_get_file ${device} duplex
}
+
+device_get_link_string() {
+ local device="${1}"
+ assert isset device
+
+ local s
+
+ local speed="$(device_get_speed "${device}")"
+ if isset speed; then
+ list_append s "${speed} MBit/s"
+ fi
+
+ local duplex="$(device_get_duplex "${device}")"
+ if isset duplex; then
+ list_append s "${duplex} duplex"
+ fi
+
+ print "${s}"
+}
+
+device_auto_configure_smp_affinity() {
+ assert [ $# -eq 1 ]
+
+ local device=${1}
+
+ if lock_acquire "smp-affinity"; then
+ device_set_smp_affinity "${port}" auto
+
+ lock_release "smp-affinity"
+ fi
+}
+
+device_set_smp_affinity() {
+ assert [ $# -eq 2 ]
+
+ local device=${1}
+ local mode=${2}
+
+ # mode can be auto which will automatically try to find
+ # the least busy processor, or an integer for the desired
+ # processor that should handle this device
+
+ local num_processors=$(system_get_processors)
+
+ if [ "${mode}" = "auto" ]; then
+ local processor=$(interrupt_choose_least_busy_processor)
+ else
+ assert isinteger mode
+ local processor=${mode}
+
+ if [ ${processor} -gt ${num_processors} ]; then
+ log ERROR "Processor ${processor} does not exist"
+ return ${EXIT_ERROR}
+ fi
+ fi
+
+ local interrupts=$(interrupts_for_device ${device})
+ if ! isset interrupts; then
+ log DEBUG "${device} has no interrupts. Not changing SMP affinity"
+ return ${EXIT_OK}
+ fi
+
+ # Set SMP affinity
+ local interrupt
+ for interrupt in ${interrupts}; do
+ interrupt_set_smp_affinity ${interrupt} ${processor}
+ done
+
+ # Find all queues and assign them to the next processor
+ local queue
+ for queue in $(device_get_queues ${device}); do
+ case "${queue}" in
+ # Only handle receive queues
+ rx-*)
+ for interrupt in $(interrupts_for_device_queue ${device} ${queue}); do
+ interrupt_set_smp_affinity ${interrupt} ${processor}
+ done
+
+ device_queue_set_smp_affinity ${device} ${queue} ${processor}
+ ;;
+
+ # Ignore the rest
+ *)
+ continue
+ ;;
+ esac
+
+ # Get the next available processor if in auto mode
+ [ "${mode}" = "auto" ] && processor=$(system_get_next_processor ${processor})
+ done
+
+ return ${EXIT_OK}
+}
+
+device_get_queues() {
+ assert [ $# -eq 1 ]
+
+ local device=${1}
+
+ local queue
+ for queue in ${SYS_CLASS_NET}/${device}/queues/*; do
+ basename "${queue}"
+ done
+}
+
+device_queue_set_smp_affinity() {
+ assert [ $# -eq 3 ]
+
+ local device=${1}
+ local queue=${2}
+ local processor=${3}
+
+ local path="${SYS_CLASS_NET}/${device}/queues/${queue}/rps_cpus"
+ assert [ -w "${path}" ]
+
+ log DEBUG "Setting SMP affinity of ${device} (${queue}) to processor ${processor}"
+
+ __processor_id_to_bitmap ${processor} > ${path}
+}