summaryrefslogtreecommitdiffstats
path: root/type/cntt/scripts/i40e-dkms-install.yaml
blob: 4e32ddcf21779937b1aaef5c6114024cb3bf8295 (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
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
...