+
+device_auto_configure_smp_affinity() {
+ assert [ $# -eq 1 ]
+
+ local device=${1}
+
+ if lock_acquire "smp-affinity" 60; then
+ device_set_smp_affinity ${device} 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}
+
+ list_directory "${SYS_CLASS_NET}/${device}/queues"
+}
+
+device_supports_multiqueue() {
+ local device=${1}
+
+ local num_queues=$(device_num_queues ${device})
+
+ if isset num_queues && [ ${num_queues} -gt 2 ]; then
+ return ${EXIT_TRUE}
+ fi
+
+ return ${EXIT_FALSE}
+}
+
+device_num_queues() {
+ local device=${1}
+ local type=${2}
+
+ isset type && assert isoneof type rx tx
+
+ local i=0
+
+ local q
+ for q in $(device_get_queues ${device}); do
+ case "${type},${q}" in
+ rx,rx-*)
+ (( i++ ))
+ ;;
+ tx,tx-*)
+ (( i++ ))
+ ;;
+ *,*)
+ (( i++ ))
+ ;;
+ esac
+ done
+
+ print ${i}
+}
+
+device_queue_get_smp_affinity() {
+ assert [ $# -eq 2 ]
+
+ local device=${1}
+ local queue=${2}
+
+ local path="${SYS_CLASS_NET}/${device}/queues/${queue}"
+
+ case "${queue}" in
+ rx-*)
+ path="${path}/rps_cpus"
+ ;;
+ tx-*)
+ path="${path}/xps_cpus"
+ ;;
+ esac
+ assert [ -r "${path}" ]
+
+ __bitmap_to_processor_ids $(<${path})
+}
+
+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}
+}
+
+# Tries to find a device which has the given IP address assigned
+device_get_by_assigned_ip_address() {
+ local ip=${1}
+
+ assert isset ip
+
+ local device
+
+ # Read the first line of ip addr show to
+ read -r device <<< $(ip addr show to "${ip}")
+
+ # If we did not found a device we return with ${EXIT_ERROR}
+ if ! isset device; then
+ return ${EXIT_ERROR}
+ fi
+
+ # We get something like:
+ # 3: upl0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
+ # and we want upl0 so we take the second word and removing the :
+ device=(${device})
+ device=${device[1]}
+ device=${device%:}
+
+ print "${device}"
+ return ${EXIT_OK}
+}
+
+device_get_by_mac_address() {
+ local mac=${1}
+
+ assert isset mac
+
+ local device
+
+ for device in $(device_list); do
+ if [ "${mac}" = "$(device_get_address ${device})" ]; then
+ print "${device}"
+ return ${EXIT_OK}
+ fi
+ done
+
+ # We could not found a port to the given mac address so we return exit error
+ return ${EXIT_ERROR}
+}