John DeNisco | 68b0ee3 | 2017-09-27 16:35:23 -0400 | [diff] [blame] | 1 | # Copyright (c) 2016 Cisco and/or its affiliates. |
| 2 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 3 | # you may not use this file except in compliance with the License. |
| 4 | # You may obtain a copy of the License at: |
| 5 | # |
| 6 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 7 | # |
| 8 | # Unless required by applicable law or agreed to in writing, software |
| 9 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 11 | # See the License for the specific language governing permissions and |
| 12 | # limitations under the License. |
| 13 | |
| 14 | """VPP Grub Utility Library.""" |
| 15 | |
| 16 | import re |
| 17 | |
| 18 | from vpplib.VPPUtil import VPPUtil |
| 19 | |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 20 | __all__ = ["VppGrubUtil"] |
John DeNisco | 68b0ee3 | 2017-09-27 16:35:23 -0400 | [diff] [blame] | 21 | |
| 22 | |
| 23 | class VppGrubUtil(object): |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 24 | """VPP Grub Utilities.""" |
John DeNisco | 68b0ee3 | 2017-09-27 16:35:23 -0400 | [diff] [blame] | 25 | |
| 26 | def _get_current_cmdline(self): |
| 27 | """ |
| 28 | Using /proc/cmdline return the current grub cmdline |
| 29 | |
| 30 | :returns: The current grub cmdline |
| 31 | :rtype: string |
| 32 | """ |
| 33 | |
| 34 | # Get the memory information using /proc/meminfo |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 35 | cmd = "sudo cat /proc/cmdline" |
John DeNisco | 68b0ee3 | 2017-09-27 16:35:23 -0400 | [diff] [blame] | 36 | (ret, stdout, stderr) = VPPUtil.exec_command(cmd) |
| 37 | if ret != 0: |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 38 | raise RuntimeError( |
| 39 | "{} on node {} {} {}".format(cmd, self._node["host"], stdout, stderr) |
| 40 | ) |
John DeNisco | 68b0ee3 | 2017-09-27 16:35:23 -0400 | [diff] [blame] | 41 | |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 42 | self._current_cmdline = stdout.strip("\n") |
John DeNisco | 68b0ee3 | 2017-09-27 16:35:23 -0400 | [diff] [blame] | 43 | |
| 44 | def _get_default_cmdline(self): |
| 45 | """ |
| 46 | Using /etc/default/grub return the default grub cmdline |
| 47 | |
| 48 | :returns: The default grub cmdline |
| 49 | :rtype: string |
| 50 | """ |
| 51 | |
| 52 | # Get the default grub cmdline |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 53 | rootdir = self._node["rootdir"] |
| 54 | gfile = self._node["cpu"]["grub_config_file"] |
| 55 | grubcmdline = self._node["cpu"]["grubcmdline"] |
| 56 | cmd = "cat {}".format(rootdir + gfile) |
John DeNisco | 68b0ee3 | 2017-09-27 16:35:23 -0400 | [diff] [blame] | 57 | (ret, stdout, stderr) = VPPUtil.exec_command(cmd) |
| 58 | if ret != 0: |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 59 | raise RuntimeError( |
| 60 | "{} Executing failed on node {} {}".format( |
| 61 | cmd, self._node["host"], stderr |
| 62 | ) |
| 63 | ) |
John DeNisco | 68b0ee3 | 2017-09-27 16:35:23 -0400 | [diff] [blame] | 64 | |
| 65 | # Get the Default Linux command line, ignoring commented lines |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 66 | lines = stdout.split("\n") |
John DeNisco | 68b0ee3 | 2017-09-27 16:35:23 -0400 | [diff] [blame] | 67 | for line in lines: |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 68 | if line == "" or line[0] == "#": |
John DeNisco | 68b0ee3 | 2017-09-27 16:35:23 -0400 | [diff] [blame] | 69 | continue |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 70 | ldefault = re.findall(r"{}=.+".format(grubcmdline), line) |
John DeNisco | 68b0ee3 | 2017-09-27 16:35:23 -0400 | [diff] [blame] | 71 | if ldefault: |
| 72 | self._default_cmdline = ldefault[0] |
| 73 | break |
| 74 | |
| 75 | def get_current_cmdline(self): |
| 76 | """ |
| 77 | Returns the saved grub cmdline |
| 78 | |
| 79 | :returns: The saved grub cmdline |
| 80 | :rtype: string |
| 81 | """ |
| 82 | return self._current_cmdline |
| 83 | |
| 84 | def get_default_cmdline(self): |
| 85 | """ |
| 86 | Returns the default grub cmdline |
| 87 | |
| 88 | :returns: The default grub cmdline |
| 89 | :rtype: string |
| 90 | """ |
| 91 | return self._default_cmdline |
| 92 | |
| 93 | def create_cmdline(self, isolated_cpus): |
| 94 | """ |
| 95 | Create the new grub cmdline |
| 96 | |
| 97 | :param isolated_cpus: The isolated cpu string |
| 98 | :type isolated_cpus: string |
| 99 | :returns: The command line |
| 100 | :rtype: string |
| 101 | """ |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 102 | grubcmdline = self._node["cpu"]["grubcmdline"] |
John DeNisco | 68b0ee3 | 2017-09-27 16:35:23 -0400 | [diff] [blame] | 103 | cmdline = self._default_cmdline |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 104 | value = cmdline.split("{}=".format(grubcmdline))[1] |
John DeNisco | 68b0ee3 | 2017-09-27 16:35:23 -0400 | [diff] [blame] | 105 | value = value.rstrip('"').lstrip('"') |
| 106 | |
Paul Vinciguerra | 339bc6b | 2018-12-19 02:05:25 -0800 | [diff] [blame] | 107 | # jadfix intel_pstate=disable sometimes cause networks to |
| 108 | # hang on reboot |
John DeNisco | c6b2a20 | 2017-11-01 12:37:47 -0400 | [diff] [blame] | 109 | # iommu = re.findall(r'iommu=\w+', value) |
| 110 | # pstate = re.findall(r'intel_pstate=\w+', value) |
John DeNisco | 68b0ee3 | 2017-09-27 16:35:23 -0400 | [diff] [blame] | 111 | # If there is already some iommu commands set, leave them, |
| 112 | # if not use ours |
John DeNisco | c6b2a20 | 2017-11-01 12:37:47 -0400 | [diff] [blame] | 113 | # if iommu == [] and pstate == []: |
| 114 | # value = '{} intel_pstate=disable'.format(value) |
John DeNisco | 68b0ee3 | 2017-09-27 16:35:23 -0400 | [diff] [blame] | 115 | |
| 116 | # Replace isolcpus with ours |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 117 | isolcpus = re.findall(r"isolcpus=[\w+\-,]+", value) |
John DeNisco | 68b0ee3 | 2017-09-27 16:35:23 -0400 | [diff] [blame] | 118 | if not isolcpus: |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 119 | if isolated_cpus != "": |
John DeNisco | 68b0ee3 | 2017-09-27 16:35:23 -0400 | [diff] [blame] | 120 | value = "{} isolcpus={}".format(value, isolated_cpus) |
| 121 | else: |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 122 | if isolated_cpus != "": |
| 123 | value = re.sub( |
| 124 | r"isolcpus=[\w+\-,]+", "isolcpus={}".format(isolated_cpus), value |
| 125 | ) |
John DeNisco | 68b0ee3 | 2017-09-27 16:35:23 -0400 | [diff] [blame] | 126 | else: |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 127 | value = re.sub(r"isolcpus=[\w+\-,]+", "", value) |
John DeNisco | 68b0ee3 | 2017-09-27 16:35:23 -0400 | [diff] [blame] | 128 | |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 129 | nohz = re.findall(r"nohz_full=[\w+\-,]+", value) |
John DeNisco | 68b0ee3 | 2017-09-27 16:35:23 -0400 | [diff] [blame] | 130 | if not nohz: |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 131 | if isolated_cpus != "": |
John DeNisco | 68b0ee3 | 2017-09-27 16:35:23 -0400 | [diff] [blame] | 132 | value = "{} nohz_full={}".format(value, isolated_cpus) |
| 133 | else: |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 134 | if isolated_cpus != "": |
| 135 | value = re.sub( |
| 136 | r"nohz_full=[\w+\-,]+", "nohz_full={}".format(isolated_cpus), value |
| 137 | ) |
John DeNisco | 68b0ee3 | 2017-09-27 16:35:23 -0400 | [diff] [blame] | 138 | else: |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 139 | value = re.sub(r"nohz_full=[\w+\-,]+", "", value) |
John DeNisco | 68b0ee3 | 2017-09-27 16:35:23 -0400 | [diff] [blame] | 140 | |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 141 | rcu = re.findall(r"rcu_nocbs=[\w+\-,]+", value) |
John DeNisco | 68b0ee3 | 2017-09-27 16:35:23 -0400 | [diff] [blame] | 142 | if not rcu: |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 143 | if isolated_cpus != "": |
John DeNisco | 68b0ee3 | 2017-09-27 16:35:23 -0400 | [diff] [blame] | 144 | value = "{} rcu_nocbs={}".format(value, isolated_cpus) |
| 145 | else: |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 146 | if isolated_cpus != "": |
| 147 | value = re.sub( |
| 148 | r"rcu_nocbs=[\w+\-,]+", "rcu_nocbs={}".format(isolated_cpus), value |
| 149 | ) |
John DeNisco | 68b0ee3 | 2017-09-27 16:35:23 -0400 | [diff] [blame] | 150 | else: |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 151 | value = re.sub(r"rcu_nocbs=[\w+\-,]+", "", value) |
John DeNisco | 68b0ee3 | 2017-09-27 16:35:23 -0400 | [diff] [blame] | 152 | |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 153 | value = value.lstrip(" ").rstrip(" ") |
John DeNisco | 68b0ee3 | 2017-09-27 16:35:23 -0400 | [diff] [blame] | 154 | cmdline = '{}="{}"'.format(grubcmdline, value) |
| 155 | return cmdline |
| 156 | |
| 157 | def apply_cmdline(self, node, isolated_cpus): |
| 158 | """ |
| 159 | Apply cmdline to the default grub file |
| 160 | |
| 161 | :param node: Node dictionary with cpuinfo. |
| 162 | :param isolated_cpus: The isolated cpu string |
| 163 | :type node: dict |
| 164 | :type isolated_cpus: string |
| 165 | :return The vpp cmdline |
| 166 | :rtype string |
| 167 | """ |
| 168 | |
| 169 | vpp_cmdline = self.create_cmdline(isolated_cpus) |
Paul Vinciguerra | 582eac5 | 2020-04-03 12:18:40 -0400 | [diff] [blame] | 170 | if len(vpp_cmdline): |
| 171 | # Update grub |
| 172 | # Save the original file |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 173 | rootdir = node["rootdir"] |
| 174 | grubcmdline = node["cpu"]["grubcmdline"] |
| 175 | ofilename = rootdir + node["cpu"]["grub_config_file"] + ".orig" |
| 176 | filename = rootdir + node["cpu"]["grub_config_file"] |
John DeNisco | 68b0ee3 | 2017-09-27 16:35:23 -0400 | [diff] [blame] | 177 | |
Paul Vinciguerra | 582eac5 | 2020-04-03 12:18:40 -0400 | [diff] [blame] | 178 | # Write the output file |
| 179 | # Does a copy of the original file exist, if not create one |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 180 | (ret, stdout, stderr) = VPPUtil.exec_command("ls {}".format(ofilename)) |
Paul Vinciguerra | 582eac5 | 2020-04-03 12:18:40 -0400 | [diff] [blame] | 181 | if ret != 0: |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 182 | if stdout.strip("\n") != ofilename: |
| 183 | cmd = "sudo cp {} {}".format(filename, ofilename) |
Paul Vinciguerra | 582eac5 | 2020-04-03 12:18:40 -0400 | [diff] [blame] | 184 | (ret, stdout, stderr) = VPPUtil.exec_command(cmd) |
| 185 | if ret != 0: |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 186 | raise RuntimeError( |
| 187 | "{} failed on node {} {}".format( |
| 188 | cmd, self._node["host"], stderr |
| 189 | ) |
| 190 | ) |
John DeNisco | 68b0ee3 | 2017-09-27 16:35:23 -0400 | [diff] [blame] | 191 | |
Paul Vinciguerra | 582eac5 | 2020-04-03 12:18:40 -0400 | [diff] [blame] | 192 | # Get the contents of the current grub config file |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 193 | cmd = "cat {}".format(filename) |
Paul Vinciguerra | 582eac5 | 2020-04-03 12:18:40 -0400 | [diff] [blame] | 194 | (ret, stdout, stderr) = VPPUtil.exec_command(cmd) |
| 195 | if ret != 0: |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 196 | raise RuntimeError( |
| 197 | "{} failed on node {} {}".format(cmd, self._node["host"], stderr) |
| 198 | ) |
John DeNisco | 68b0ee3 | 2017-09-27 16:35:23 -0400 | [diff] [blame] | 199 | |
Paul Vinciguerra | 582eac5 | 2020-04-03 12:18:40 -0400 | [diff] [blame] | 200 | # Write the new contents |
| 201 | # Get the Default Linux command line, ignoring commented lines |
| 202 | content = "" |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 203 | lines = stdout.split("\n") |
Paul Vinciguerra | 582eac5 | 2020-04-03 12:18:40 -0400 | [diff] [blame] | 204 | for line in lines: |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 205 | if line == "": |
| 206 | content += line + "\n" |
Paul Vinciguerra | 582eac5 | 2020-04-03 12:18:40 -0400 | [diff] [blame] | 207 | continue |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 208 | if line[0] == "#": |
| 209 | content += line + "\n" |
Paul Vinciguerra | 582eac5 | 2020-04-03 12:18:40 -0400 | [diff] [blame] | 210 | continue |
John DeNisco | 68b0ee3 | 2017-09-27 16:35:23 -0400 | [diff] [blame] | 211 | |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 212 | ldefault = re.findall(r"{}=.+".format(grubcmdline), line) |
Paul Vinciguerra | 582eac5 | 2020-04-03 12:18:40 -0400 | [diff] [blame] | 213 | if ldefault: |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 214 | content += vpp_cmdline + "\n" |
Paul Vinciguerra | 582eac5 | 2020-04-03 12:18:40 -0400 | [diff] [blame] | 215 | else: |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 216 | content += line + "\n" |
John DeNisco | 68b0ee3 | 2017-09-27 16:35:23 -0400 | [diff] [blame] | 217 | |
Paul Vinciguerra | 582eac5 | 2020-04-03 12:18:40 -0400 | [diff] [blame] | 218 | content = content.replace(r"`", r"\`") |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 219 | content = content.rstrip("\n") |
Paul Vinciguerra | 582eac5 | 2020-04-03 12:18:40 -0400 | [diff] [blame] | 220 | cmd = "sudo cat > {0} << EOF\n{1}\n".format(filename, content) |
| 221 | (ret, stdout, stderr) = VPPUtil.exec_command(cmd) |
| 222 | if ret != 0: |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 223 | raise RuntimeError( |
| 224 | "{} failed on node {} {}".format(cmd, self._node["host"], stderr) |
| 225 | ) |
John DeNisco | 68b0ee3 | 2017-09-27 16:35:23 -0400 | [diff] [blame] | 226 | |
| 227 | return vpp_cmdline |
| 228 | |
| 229 | def __init__(self, node): |
| 230 | distro = VPPUtil.get_linux_distro() |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 231 | if distro[0] == "Ubuntu": |
| 232 | node["cpu"]["grubcmdline"] = "GRUB_CMDLINE_LINUX_DEFAULT" |
John DeNisco | 68b0ee3 | 2017-09-27 16:35:23 -0400 | [diff] [blame] | 233 | else: |
Klement Sekera | d9b0c6f | 2022-04-26 19:02:15 +0200 | [diff] [blame] | 234 | node["cpu"]["grubcmdline"] = "GRUB_CMDLINE_LINUX" |
John DeNisco | 68b0ee3 | 2017-09-27 16:35:23 -0400 | [diff] [blame] | 235 | |
| 236 | self._node = node |
| 237 | self._current_cmdline = "" |
| 238 | self._default_cmdline = "" |
| 239 | self._get_current_cmdline() |
| 240 | self._get_default_cmdline() |