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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
|
---
schema: pegleg/Script/v1
metadata:
schema: metadata/Document/v1
name: i40e-dkms-install
storagePolicy: cleartext
layeringDefinition:
abstract: false
layer: type
substitutions:
- src:
schema: pegleg/SoftwareVersions/v1
name: software-versions
path: .kernel_drivers.i40e_driver.location
dest:
path: .
pattern: I40E_DRVURL
data: |-
#!/bin/bash
set -ex
# defaults
DRVURL="I40E_DRVURL"
REBOOT=1
ERR=0
DRV=i40e
apt_install(){
for pkg in $@; do
dpkg -s $pkg 2> /dev/null | grep 'Status:.*install' || DEBIAN_FRONTEND=noninteractive apt -y -o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--force-confold install $pkg
done
}
function usage() {
cat <<EOF >&2
Usage: $(basename $0) [-h] [-u driver-url] [-p http://proxy.to.use:port] [ -T ] [ -x ] [ -s ]
-h help
-u specified URL location of driver to fetch (default: 2.9.21 at sourceforge)
-p proxy string to use; sets both http_proxy and https_proxy (default: nothing set)
-r mark the operating system for deferred reboot (default: reboot immediately)
EOF
exit 1
}
# ###########################################################################
while getopts ":Thp:su:xr" opt; do
case ${opt} in
h )
usage;
;;
u )
DRVURL=$OPTARG
;;
p )
export http_proxy=$OPTARG
export https_proxy=$OPTARG
;;
r )
REBOOT=0
;;
\?)
echo "Invalid: $OPTARG" 1>&2
ERR=1
;;
: )
echo "Invalid: $OPTARG requires an argument" 1>&2
ERR=1
;;
esac
done
[ $ERR -ne 0 ] && exit 1
echo "URL: $DRVURL"
echo "PROXY: ${https_proxy:-(not set)}"
echo "Install necessary packages"
apt_install wget build-essential dkms curl rsync linux-headers-$(uname -r)
tmpdir=$(mktemp -d /tmp/i40-install.XXXXXX)
function cleanup {
rm -rf "$tmpdir"
}
trap cleanup EXIT
cd $tmpdir
# Add some retry in case this gets flaky
trycount=1
while : ; do
if curl -L --silent $DRVURL | tar -xz ; then
break
fi
if [ $trycount -ge 3 ] ; then
echo 1>&2
echo "Fetching $DRVURL failed after $trycount attempts" 1>&2
exit 1
fi
sleep 10
trycount=$(($trycount+1))
done
# base dir (name)
bdir=$(ls|grep ${DRV})
if [ "$(echo $bdir | wc -w)" -ne 1 ] ; then
echo "Unable to determine correct module directory, I see $bdir" 2>&1
exit 1
fi
# i40e.spec contains the driver version; get it from there
DRVVER="$(find . -name ${DRV}.spec | xargs grep Version | awk '{print $2}' | head -1)"
# target dir
tdir="/usr/src/${bdir}"
echo "VERSION: $DRVVER"
echo "TARGET: $tdir"
add_dkms_moudle() {
# add dkms modules only if they are not alreay added.
is_added="$(dkms status -m $DRV -v $DRVVER -k null | wc -l)"
if [[ ${is_added} == 0 ]]; then
# We have seen some cases where the is_added dkms check above
# gives a false-positive, so as an added layer we check here
# for an error message the the module is already added, and
# ignore the error if that happens.
dkms_add_output="$(dkms add -m ${DRV} -v "${DRVVER}" 2>&1)" || \
echo "$dkms_add_output" | grep 'Error! DKMS tree already contains:' || \
(echo "$dkms_add_output" 1>&2 && exit 1)
else
echo "The target dkms module is already loaded to the dkms tree."
fi
}
install_dkms_module() {
# install dkms modules only if they are not alreay installed for this kernel.
is_installed="$(dkms status -m $DRV -v $DRVVER -k $krel | grep installed | wc -l)"
if [[ ${is_installed} == 0 ]]; then
dkms_install_output="$(dkms install ${DRV}/${DRVVER} -k $krel 2>&1)" || \
echo "$dkms_install_output" | grep 'Error! This module/version combo is already installed' || \
(echo "$dkms_install_output" 1>&2 && exit 1)
else
echo "The target dkms module is already installed."
fi
}
# if there are exising kernel modules for this driver, repalce them with
# module from dkms tree
replace_driver_module() {
for file in $(find /lib/modules/$(uname -r) -type f -name '${DRV}.ko'); do
cp /var/lib/dkms/${DRV}/${DRVVER}/$(uname -r)/$(uname -p)/module/${DRV}.ko $file
done
}
# DO NOT remove or rename the directory under /usr/src, as this completes breaks DKMS.
# For a simple idempotent solution, just rsync the files to the target and only move
# in files that do not exist at the dest.
rsync -a --ignore-existing "${bdir}/src"/ "${tdir}"/
cat <<EOF > "${tdir}/dkms.conf"
PACKAGE_NAME="${DRV}"
PACKAGE_VERSION="${DRVVER}"
BUILT_MODULE_NAME[0]="${DRV}"
DEST_MODULE_LOCATION[0]="/updates/"
REMAKE_INITRD="yes"
AUTOINSTALL="yes"
EOF
add_dkms_moudle
install_dkms_module
replace_driver_module
# make sure modprobe sees the 'right' module version
pver=$(modinfo ${DRV} | grep ^version | awk '{print $2}')
if [[ "${DRVVER}" != ${pver} ]] ; then
# not really sure if this can ever happen
echo "ERROR: Module system does not see the version we just built" 2>&1
exit 1
fi
# If we've already installed this driver version, we don't need to reboot or mark for reboot.
# We still run the idempotent steps above, because there is the possibility that someone will
# have installed a new kernel version (possibly without the needed headers), in which case this
# script should run again for that new kernel version even though the i40e version has not changed.
# In the case of a newly installed/staged kernel that is pending reboot, that kernel will have
# already marked the node for reboot, so we can skip doing that here.
[ -e /var/lib/${DRV}.done ] && [ "$(cat /var/lib/${DRV}.done)" = "$DRVVER" ] && cleanup && exit 0
# Marker the driver version installation as done to avoid flagging the node for needing reboots
# on this same driver version again (unless they are because a different kernel version was
# installed with no change in the driver version, in which case the kernel update will have
# marked the node for needing reboot).
touch /var/lib/${DRV}.done
# save the driver version in the i40e.done file for the verify driver
# script to read and validate the expected against the actual driver
# version
echo "${pver}" | tee /var/lib/${DRV}.done
sync
if [ $REBOOT -ne 0 ]; then
# we can't rely on rmmod/insmod; the driver may not be robust or the
# interface is in use in complicated ways
wall "${DRV} driver updated - rebooting"
/sbin/reboot
# don't exit successfully, doing that would allow prom to start a few
# seconds before reboot takes effect
sleep infinity
exit 1
fi
...
|