summaryrefslogtreecommitdiffstats
path: root/extras/scripts/vfctl
blob: 9fe6c8b02e76c76daaea38ef39d5f4fd4ffa2a60 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#!/bin/bash

function die() {
	echo "ERROR: $*" >&2
	exit 1
}
function pci-unbind() {
	echo $1 | sudo tee /sys/bus/pci/devices/$1/driver/unbind > /dev/null
}
function pci-bind() {
	pci-unbind $1
	echo $2 | sudo tee /sys/bus/pci/devices/$1/driver_override > /dev/null
	echo $1 | sudo tee /sys/bus/pci/drivers/$2/bind > /dev/null
	echo | sudo tee /sys/bus/pci/devices/$1/driver_override > /dev/null
}

function show_vfs() {
	path=$1
	netdev=$2
	printf "\nVirtual Functions:\n%-2s %-12s %-9s %-12s %-17s %s\n" \
	  "ID" "PCI Addr" "PCI ID" "Driver" "MAC Addr" "Config"
	for vf_path in ${path}/virtfn*; do
		vf=$(basename $(readlink ${vf_path}))
		vfid=$(basename ${vf_path//virtfn/})
		line=$(ip link show dev ${netdev} | grep "vf ${vfid}")
		driver=$(basename $(readlink ${vf_path}/driver))
		pciid="$(cat ${vf_path}/vendor | cut -dx -f2):$(cat ${vf_path}/device | cut -dx -f2)"
		mac=$(echo $line | sed -n -E -e 's/.*MAC ([0-9a-f:]+),.*/\1/p')
		cfg=$(echo $line | cut -d, -f2-)

		printf "%-2s %-12s %-9s %-12s %-17s%s\n" \
		  $vfid $vf $pciid $driver $mac "$cfg"
	done
}
function get_pci_addr() {
	local addr
	if [ -d /sys/class/net/$2/device ]; then
		addr=$(basename $(readlink /sys/class/net/${2}/device))
	else
		addr=$2
	fi
	if [ ! -d /sys/bus/pci/devices/${pci_addr} ]; then
		die "PCI device $2 doesn't exist"
	fi
	eval "$1=${addr}"
}

function show () {
	get_pci_addr pci_addr $1
	path="/sys/bus/pci/devices/${pci_addr}"

	if [ ! -f ${path}/sriov_numvfs ]; then
		die "PCI device $1 is not SR-IOV device"
	fi

	printf "%-20s: %s\n" "PCI Address" ${pci_addr}
	printf "%-20s: %s\n" "PCI ID" \
		"$(cat ${path}/vendor | cut -dx -f2):$(cat ${path}/device | cut -dx -f2)"
	printf "%-20s: %s\n" "Driver name" $(basename $(readlink ${path}/driver))
	printf "%-20s: %s\n" "Driver Version" $(cat ${path}/driver/module/version)
	printf "%-20s: %s\n" "PCI Link Speed (max)" "$(cat ${path}/current_link_speed) ($(cat ${path}/max_link_speed))"
	printf "%-20s: %s\n" "PCI Link Width (max)" "$(cat ${path}/current_link_width) ($(cat ${path}/max_link_width))"
	printf "%-20s: %s\n" "NUMA Node" $(cat ${path}/numa_node)
	printf "%-20s: %s\n" "Number of VFs" $(cat ${path}/sriov_numvfs)
	printf "%-20s: %s\n" "Total VFs" $(cat ${path}/sriov_totalvfs)
	if [ -d ${path}/net/* ] ; then
		netdev=$(basename ${path}/net/*)
		netdev_path=${path}/net/${netdev}
		printf "%-20s: %s\n" "Interface" ${netdev}
		printf "%-20s: %s\n" "MAC Address" $(cat ${netdev_path}/address)
		printf "%-20s: %s\n" "Speed" $(cat ${netdev_path}/speed)
		printf "%-20s: %s\n" "State" $(cat ${netdev_path}/operstate)
	fi

	[ $(cat ${path}/sriov_numvfs) -gt 0 ] && show_vfs ${path} ${netdev}
}

function remove_all () {
	get_pci_addr pci_addr $1
	path="/sys/bus/pci/devices/${pci_addr}"
	[ $(cat ${path}/sriov_numvfs) -gt 0 ] || die "No VFs configured on $1"
	echo 0 | sudo tee ${path}/sriov_numvfs > /dev/null
	echo "VFs removed..."
}

function create () {
	get_pci_addr pci_addr $1
	path="/sys/bus/pci/devices/${pci_addr}"
	[ $(cat ${path}/sriov_numvfs) -gt 0 ] && die "VFs already configured on $1"
	[ "0$2" -gt 0 ] || die "Please specify number of VFs to create"
	echo $2 | sudo tee ${path}/sriov_numvfs > /dev/null
	[ -d ${path}/net/* ] || die "No net device for $1"
	netdev=$(basename ${path}/net/*)
	netdev_path=${path}/net/${netdev}

	mac_prefix=$(cat ${netdev_path}/address | cut -d: -f1,3,4,5,6 )
	for vf_path in ${path}/virtfn*; do
		vf=$(basename $(readlink ${vf_path}))
		vfid=$(basename ${vf_path//virtfn/})
		mac="${mac_prefix}:$(printf "%02x" ${vfid})"
		sudo ip link set dev ${netdev} vf ${vfid} mac ${mac}
		sudo ip link set dev ${netdev} vf ${vfid} trust on
		sudo ip link set dev ${netdev} vf ${vfid} spoofchk off
		pci-bind ${vf} vfio-pci
	done

	[ $(cat ${path}/sriov_numvfs) -gt 0 ] && show_vfs ${path} ${netdev}
}

function help() {

cat << __EOF__

$0 show <dev>
  Displays information about <dev> where <dev> is PCI address
  or linux interface name.

$0 remove-all <dev>
  Remove all virtual functions from device <dev>.

$0 create <dev> <num>
  Create <num> virtual functions on device<dev>.
__EOF__
}

case $1 in
	show)
		show $2
		;;
	create)
		create $2 $3
		;;
	remove-all)
		remove_all $2
		;;
	help)
		help $2
		;;
	*)
		echo "Please specify command (show, create, remove-all)"
		help
		;;
esac
s="p">:] # Open the file and explore its contents... self.log.info("Siphoning from %s." % filename) directives = {} with open(filename) as fd: siphon = None close_siphon = None siphon_block = "" in_block = False line_num = 0 siphon_line = 0 for line in fd: line_num += 1 str = line[:-1] # filter \n """See if there is a block directive and if so extract it""" def process_block_directive(str, directives): m = self.siphon_block_directive.search(str) if m is not None: k = m.group(2) v = m.group(3).strip() directives[k] = v # Return only the parts we did not match return str[0:m.start(1)] + str[m.end(4):] return str def process_block_prefix(str): if str.startswith(" * "): str = str[3:] elif str == " *": str = "" return str if not in_block: # See if the line contains the start of a siphon doc block m = self.siphon_block_start.search(str) if m is not None: in_block = True t = m.group(1) # Now check if the block closes on the same line m = self.siphon_block_stop.search(t) if m is not None: t = m.group(1) in_block = False # Check for directives t = process_block_directive(t, directives) # Filter for normal comment prefixes t = process_block_prefix(t) # Add what is left siphon_block += t # Skip to next line continue else: # Check to see if we have an end block marker m = self.siphon_block_stop.search(str) if m is not None: in_block = False t = m.group(1) else: t = str # Check for directives t = process_block_directive(t, directives) # Filter for normal comment prefixes t = process_block_prefix(t) # Add what is left siphon_block += t + "\n" # Skip to next line continue if siphon is None: # Look for blocks we need to siphon for p in siphon_patterns: if p[0].match(str): siphon = [ p[1], str + "\n", 0 ] siphon_line = line_num # see if we have an initializer m = self.siphon_initializer.search(str) if m is not None: # count the braces on this line (count, index) = \ self.count_braces(str[m.start():]) siphon[2] = count # TODO - it's possible we have the # initializer all on the first line # we should check for it, but also # account for the possibility that # the open brace is on the next line #if count == 0: # # braces balanced # close_siphon = siphon # siphon = None else: # no initializer: close the siphon right now close_siphon = siphon siphon = None else: # See if we should end the siphon here - do we have # balanced braces? (count, index) = self.count_braces(str, count=siphon[2], found=True) if count == 0: # braces balanced - add the substring and # close the siphon siphon[1] += str[:index+1] + ";\n" close_siphon = siphon siphon = None else: # add the whole string, move on siphon[2] = count siphon[1] += str + "\n" if close_siphon is not None: # Write the siphoned contents to the right place siphon_name = close_siphon[0] # Copy directives for the file details = {} for key in directives: if ":" in key: (sn, label) = key.split(":") if sn == siphon_name: details[label] = directives[key] else: details[key] = directives[key] # Copy details for this block details['file'] = filename details['directory'] = directory details['line_start'] = siphon_line details['line_end'] = line_num details['siphon_block'] = siphon_block.strip() details["block"] = close_siphon[1] # Store the item self.output[siphon_name]['items'].append(details) # All done close_siphon = None siphon_block = "" # Update globals for key in directives.keys(): if ':' not in key: continue if filename.endswith("/dir.dox"): # very special! use the parent directory name l = directory else: l = filename (sn, label) = key.split(":") if sn not in self.output: self.output[sn] = {} if 'global' not in self.output[sn]: self.output[sn]['global'] = {} if l not in self.output[sn]['global']: self.output[sn]['global'][l] = {} self.output[sn]['global'][l][label] = directives[key] def deliver(self): # Write out the data for siphon in self.output.keys(): self.log.info("Saving siphon data %s." % siphon) s = self.output[siphon] with open(s['file'], "a") as fp: json.dump(s, fp, separators=(',', ': '), indent=4, sort_keys=True)