Skip to content

Instantly share code, notes, and snippets.

@mzpqnxow
Created June 25, 2020 15:33
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save mzpqnxow/762eee200a70a1356a511813986e239c to your computer and use it in GitHub Desktop.
Save mzpqnxow/762eee200a70a1356a511813986e239c to your computer and use it in GitHub Desktop.
Shell script for setting up DPDK fail-safe PMD on Azure
#!/bin/sh
# Copyright (c) 2017 6WIND S.A.
version=20171003
[ "$0" != "bash" ] && self=$(readlink -f "$0")
[ "$self" ] && _self=${self##*/}
netvsc_id="{f8615163-df3e-46c5-913f-f2d2f965ed0e}"
# Setup display variables
TPUT=$(tput longname 2>/dev/null || true) # returns '' if $TERM is not known
if [ "$TPUT" ]; then
BLACK=$(tput op || true)
RED=$(tput setaf 1 || true)
# GREEN=$(tput setaf 2 || true)
YELLOW=$(tput setaf 3 || true)
BLUE=$(tput setaf 6 || true)
BOLD=$(tput bold || true)
NORMAL=$(tput sgr0 || true)
fi
if [ "$1" = "-v" -o "$1" = "--version" ]; then
printf 'version: %s\n' $version
exit 0
fi
[ "$1" = "-h" ] || \
[ "$1" = "help" ] || \
[ "$1" = "--help" ] && printf '%s\n' "Usage:
$_self [vdev|with <net1[ net2 ...]>|preferred|fallback|help] [MAC]
${BOLD}${YELLOW}$_self [vdev] <[MAC1[ MAC2 ...]]>${NORMAL}
Generates a vdev parameter for each VF-NetVSC pair found on the system.
If MAC is specified, restrict results to those matching such MAC address.
If the VF is not currently plugged-in and no bonding has been configured,
then MAC must be provided or using a specific NetVSC device using the
${BOLD}with${NORMAL} command instead.
You can use it as follows:
${BOLD}path/to/app \$(${BLUE}$self${BLACK})${NORMAL}
${BOLD}${YELLOW}$_self with <net1[ net2 ...]>${NORMAL}
Use the specified netdevices as fallback for fail-safe pairs.
One fail-safe instance will be created per netdevice.
Each such netdevice will seek a VF matching its MAC address, be it currently
plugged-in or not.
You can use it as follows:
${BOLD}path/to/app \$(${BLUE}$self ${RED}with eth1 eth2${BLACK})${NORMAL}
${BOLD}${YELLOW}$_self preferred [MAC]${NORMAL}
Generates a device definition for the preferred device.
The preferred device is detected following those rules:
* Detect any PCI device currently plugged in that could be part of a VF-NetVSC pair.
This PCI device has to share a MAC address with another non-PCI device having
the class_id \"${RED}$netvsc_id${NORMAL}\".
If a MAC address is specified, restrict results to those using such MAC address.
* If no such device is detected and if a MAC address is specified, any
other PCI device using this MAC address is then used instead. This allows
forcing the use of arbitrary PCI device.
This option is usually used within the ${BOLD}exec${NORMAL} device type of the fail-safe.
${BOLD}${YELLOW}$_self fallback [MAC]${NORMAL}
Generates a device definition for the fallback device.
The fallback device is a TAP device capturing the traffic from a NetVSC device.
It is detected using the following rules:
* Detect any VF-NetVSC pairs by listing all PCI device sharing a MAC address with
another device having the class_id \"${RED}$netvsc_id${NORMAL}\".
* If the VF is not currently plugged-in, detect any NetVSC device being
part of a bonding configuration.
* If a MAC address is specified, restrict results to those using such MAC address.
* If no such NetVSC device could be detected and a MAC address is specified, generate
a dummy TAP PMD command, then detect any possible non-PCI device on the system using
this MAC address, and use it as a remote.
This option is usually used within the ${BOLD}exec${NORMAL} device type of the fail-safe.
"
# printf, but to stderr
err_printf () {
(>&2 printf %s "${BOLD}${RED}" && printf "$@" && printf %s "${NORMAL}")
}
# Print the MAC of a netdev
# $1: netdev name
get_mac () {
local dev="$1"
local file="/sys/class/net/${dev}/address"
[ "$dev" ] && [ -f "$file" ] && cat "$file"
}
# Returns true if the device has the specified MAC
# $1: netdev name
# $2: MAC address
is_mac () {
local net="$1"
local mac="$2"
[ "$net" ] || return 1
[ -f "/sys/class/net/${net}/address" ] && \
[ "$(get_mac "$net")" = "$mac" ] && \
return 0
return 1
}
# Returns true if the device is a NetVSC device.
# $1: netdev name
is_netvsc () {
local net="$1"
[ "$net" ] || return 1
[ -f "/sys/class/net/${net}/device/class_id" ] && \
[ "$(cat "/sys/class/net/${net}/device/class_id")" = "$netvsc_id" ] && \
return 0
return 1
}
# Returns true if the device is a bonding device.
# $1: netdev name
is_bond () {
local net="$1"
[ "$net" ] || return 1
[ -d "/sys/class/net/${net}/bonding" ] || return 1
return 0
}
get_parent_bond () {
local net="$1"
[ "$net" ] || return 1
for dev in /sys/class/net/*; do
dev="${dev##*/}"
[ -f "/sys/class/net/${dev}/bonding/slaves" ] || continue
for slave in $(cat "/sys/class/net/${dev}/bonding/slaves"); do
[ "$slave" = "$net" ] && echo "$dev"
done
done
return 0
}
# Returns true if the device is a PCI device.
# $1: netdev name
is_pci () {
local net="$1"
local pci_addr
[ "$net" ] || return 1
[ -L "/sys/class/net/${net}/device" ] || return 1
pci_addr="$(readlink -f "/sys/class/net/${net}/device")"
pci_addr="${pci_addr##*/}"
[ -L "/sys/bus/pci/devices/${pci_addr}" ] && \
return 0
return 1
}
# Returns true if the device is a Mellanox device
# $1: netdev name
is_mlx () {
local net="$1"
[ "$net" ] || return 1
[ -f "/sys/class/net/${net}/device/vendor" ] && \
[ "$(cat "/sys/class/net/${net}/device/vendor")" = "0x15b3" ] && \
return 0
return 1
}
# Returns true if the device is a ConnectX-3 device.
# $1: netdev name
is_cx3 () {
local net="$1"
[ "$net" ] || return 1
[ -f "/sys/class/net/${net}/device/vendor" ] || return 1
[ "$(cat "/sys/class/net/${net}/device/device")" = "0x1003" ] || \
[ "$(cat "/sys/class/net/${net}/device/device")" = "0x1004" ] || \
[ "$(cat "/sys/class/net/${net}/device/device")" = "0x1007" ] && \
return 0
return 1
}
# Returns true if the device is a VF in a valid VF-NetVSC pair
# $1: netdev name
is_paired_vf () {
local net="$1"
[ "$net" ] || return 1
is_pci "$net" || return 1
for other in /sys/class/net/*; do
other="${other##*/}"
[ "$other" = "$net" ] && continue
is_pci "$other" && continue
[ "$(get_mac "$net")" = "$(get_mac "$other")" ] && \
return 0
done
return 1
}
# Returns true if the device is a NetVSC in a valid VF-NetVSC pair
# $1: netdev name
is_paired_netvsc () {
local net="$1"
[ "$net" ] || return 1
is_netvsc "$net" || return 1
for other in /sys/class/net/*; do
other="${other##*/}"
[ "$other" = "$net" ] && continue
is_netvsc "$other" && continue
[ "$(get_mac "$net")" = "$(get_mac "$other")" ] && \
return 0
done
return 1
}
# Yield functions template
yield_='yield_SUBST () {
local mac="$1"
for net in /sys/class/net/*; do
net="${net##*/}"
if is_SUBST "$net" "$mac"; then
if [ "$mac" ]; then
[ "$mac" = "$(get_mac "$net")" ] && \
printf '\''%s\n'\'' "$net"
else
printf '\''%s\n'\'' "$net"
fi
fi
done
}'
# Declare a new yield_* function
# $1: type of device to detect (netvsc, pci, mlx, cx3)
declare_yield () {
local pattern="$1"
[ "$pattern" ] || return 1
printf '%s' "$yield_" |sed "s:SUBST:${pattern}:g"
}
eval "$(declare_yield mac)"
eval "$(declare_yield netvsc)"
eval "$(declare_yield pci)"
eval "$(declare_yield mlx)"
eval "$(declare_yield cx3)"
eval "$(declare_yield paired_vf)"
eval "$(declare_yield paired_netvsc)"
# Prints a primary device description.
#[$1]: MAC address to restrict results to.
preferred () {
local mac="$1"
local devargs
local count=0
for dev in $(yield_paired_vf "$mac"); do
devargs="$(readlink -f "/sys/class/net/${dev}/device")"
devargs="${devargs##*/}"
is_cx3 "$dev" && devargs="$devargs,port=$(cat "/sys/class/net/${dev}/dev_port")"
[ "$devargs" ] && printf '%s\n' "$devargs"
count=$((count+1))
done
if [ "$mac" ] && [ "$count" = 0 ]; then
for dev in $(yield_mac "$mac"); do
is_pci "$dev" || continue
devargs="$(readlink -f "/sys/class/net/${dev}/device")"
devargs="${devargs##*/}"
is_cx3 "$dev" && devargs="$devargs,port=$(cat "/sys/class/net/${dev}/dev_port")"
[ "$devargs" ] && printf '%s\n' "$devargs"
done
fi
}
# Prints a secondary device description.
#[$1]: MAC address to match
#[$2]: starting tap index
fallback () {
local mac="$1"
local count="$2"
local devargs
local remote
local name
[ "$count" ] || count=0
local pairs=$(yield_paired_netvsc "$mac")
[ -z $(yield_mlx "$mac") ] && pairs=$(yield_netvsc "$mac")
for dev in "$pairs"; do
mac="$(get_mac "$dev")"
name="$count"
is_netvsc "$dev" && remote="$dev"
bond="$(get_parent_bond "$dev")"
[ "$bond" = "" ] || remote="$bond"
[ "$remote" ] && name="$remote"
printf "net_tap_%s,iface=tap_%s" "$name" "$name"
[ "$remote" ] && printf ",remote=%s" "$remote"
printf "\n"
count=$((count+1))
done
if [ "$count" = 0 ]; then
name="$count"
if [ "$mac" ]; then
for dev in $(yield_mac "$mac"); do
is_pci "$dev" && continue
remote="$dev"
break
done
fi
[ "$remote" ] && name="$remote"
printf "net_tap_%s,iface=tap_%s" "$name" "$name"
[ "$remote" ] && printf ",remote=%s" "$remote"
printf "\n"
fi
}
# Prints one DPDK fail-safe PMD description.
vdev_dev () {
local count="$1"
local mac="$2"
printf "%s=net_failsafe%d,mac=%s,exec(%s),exec(%s) " \
"--vdev" "$count" "$mac" \
"${self},preferred,${mac}" \
"${self},fallback,${mac},${count}"
}
# Prints one DPDK fail-safe PMD command line for each
# netdevice name supplied as parameter.
# $@: netdevices names
with () {
local count=0
local mac
for net in "$@"; do
#is_netvsc "$net" || err_printf "\n%s is not a NetVSC device\n" "$net"
mac="$(get_mac "$net")"
printf "%s " "$(vdev_dev "$count" "$mac")"
count=$((count+1))
done
printf "\n"
}
# Prints one or more DPDK fail-safe PMD command lines.
#[$1]: target MAC address. If none, generates one fail-safe per existing
# NetVSC pairs
vdev () {
local it=0
for mac in "$@"; do
local pairs=$(yield_paired_netvsc "$mac")
[ -z $(yield_mlx "$mac") ] && pairs=$(yield_netvsc "$mac")
[ -z "$pairs" ] && continue
for dev in "$pairs"; do
mac="$(get_mac "$dev")"
vdev_dev "$it" "$mac"
it=$((it+1))
done
done
printf " -w 0000:00:00.0 "
printf "\n"
}
[ "$0" != "bash" ] || return
if [ "$1" = "preferred" ]; then
shift
preferred "$@"
elif [ "$1" = "fallback" ]; then
shift
fallback "$@"
elif [ "$1" = "with" ]; then
shift
with "$@"
elif [ "$1" = "vdev" ]; then
shift
vdev "$@"
elif [ "$1" != "help" ]; then
vdev "$@"
fi
#exit $?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment