blob: 976b20019c4bc76b90b0823edb22d47e7e7ae636 [file] [log] [blame]
John DeNisco68b0ee32017-09-27 16:35:23 -04001# 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
16import re
17
18from vpplib.VPPUtil import VPPUtil
19
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020020__all__ = ["VppGrubUtil"]
John DeNisco68b0ee32017-09-27 16:35:23 -040021
22
23class VppGrubUtil(object):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020024 """VPP Grub Utilities."""
John DeNisco68b0ee32017-09-27 16:35:23 -040025
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 Sekerad9b0c6f2022-04-26 19:02:15 +020035 cmd = "sudo cat /proc/cmdline"
John DeNisco68b0ee32017-09-27 16:35:23 -040036 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
37 if ret != 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020038 raise RuntimeError(
39 "{} on node {} {} {}".format(cmd, self._node["host"], stdout, stderr)
40 )
John DeNisco68b0ee32017-09-27 16:35:23 -040041
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020042 self._current_cmdline = stdout.strip("\n")
John DeNisco68b0ee32017-09-27 16:35:23 -040043
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 Sekerad9b0c6f2022-04-26 19:02:15 +020053 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 DeNisco68b0ee32017-09-27 16:35:23 -040057 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
58 if ret != 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020059 raise RuntimeError(
60 "{} Executing failed on node {} {}".format(
61 cmd, self._node["host"], stderr
62 )
63 )
John DeNisco68b0ee32017-09-27 16:35:23 -040064
65 # Get the Default Linux command line, ignoring commented lines
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020066 lines = stdout.split("\n")
John DeNisco68b0ee32017-09-27 16:35:23 -040067 for line in lines:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020068 if line == "" or line[0] == "#":
John DeNisco68b0ee32017-09-27 16:35:23 -040069 continue
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020070 ldefault = re.findall(r"{}=.+".format(grubcmdline), line)
John DeNisco68b0ee32017-09-27 16:35:23 -040071 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 Sekerad9b0c6f2022-04-26 19:02:15 +0200102 grubcmdline = self._node["cpu"]["grubcmdline"]
John DeNisco68b0ee32017-09-27 16:35:23 -0400103 cmdline = self._default_cmdline
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200104 value = cmdline.split("{}=".format(grubcmdline))[1]
John DeNisco68b0ee32017-09-27 16:35:23 -0400105 value = value.rstrip('"').lstrip('"')
106
Paul Vinciguerra339bc6b2018-12-19 02:05:25 -0800107 # jadfix intel_pstate=disable sometimes cause networks to
108 # hang on reboot
John DeNiscoc6b2a202017-11-01 12:37:47 -0400109 # iommu = re.findall(r'iommu=\w+', value)
110 # pstate = re.findall(r'intel_pstate=\w+', value)
John DeNisco68b0ee32017-09-27 16:35:23 -0400111 # If there is already some iommu commands set, leave them,
112 # if not use ours
John DeNiscoc6b2a202017-11-01 12:37:47 -0400113 # if iommu == [] and pstate == []:
114 # value = '{} intel_pstate=disable'.format(value)
John DeNisco68b0ee32017-09-27 16:35:23 -0400115
116 # Replace isolcpus with ours
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200117 isolcpus = re.findall(r"isolcpus=[\w+\-,]+", value)
John DeNisco68b0ee32017-09-27 16:35:23 -0400118 if not isolcpus:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200119 if isolated_cpus != "":
John DeNisco68b0ee32017-09-27 16:35:23 -0400120 value = "{} isolcpus={}".format(value, isolated_cpus)
121 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200122 if isolated_cpus != "":
123 value = re.sub(
124 r"isolcpus=[\w+\-,]+", "isolcpus={}".format(isolated_cpus), value
125 )
John DeNisco68b0ee32017-09-27 16:35:23 -0400126 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200127 value = re.sub(r"isolcpus=[\w+\-,]+", "", value)
John DeNisco68b0ee32017-09-27 16:35:23 -0400128
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200129 nohz = re.findall(r"nohz_full=[\w+\-,]+", value)
John DeNisco68b0ee32017-09-27 16:35:23 -0400130 if not nohz:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200131 if isolated_cpus != "":
John DeNisco68b0ee32017-09-27 16:35:23 -0400132 value = "{} nohz_full={}".format(value, isolated_cpus)
133 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200134 if isolated_cpus != "":
135 value = re.sub(
136 r"nohz_full=[\w+\-,]+", "nohz_full={}".format(isolated_cpus), value
137 )
John DeNisco68b0ee32017-09-27 16:35:23 -0400138 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200139 value = re.sub(r"nohz_full=[\w+\-,]+", "", value)
John DeNisco68b0ee32017-09-27 16:35:23 -0400140
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200141 rcu = re.findall(r"rcu_nocbs=[\w+\-,]+", value)
John DeNisco68b0ee32017-09-27 16:35:23 -0400142 if not rcu:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200143 if isolated_cpus != "":
John DeNisco68b0ee32017-09-27 16:35:23 -0400144 value = "{} rcu_nocbs={}".format(value, isolated_cpus)
145 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200146 if isolated_cpus != "":
147 value = re.sub(
148 r"rcu_nocbs=[\w+\-,]+", "rcu_nocbs={}".format(isolated_cpus), value
149 )
John DeNisco68b0ee32017-09-27 16:35:23 -0400150 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200151 value = re.sub(r"rcu_nocbs=[\w+\-,]+", "", value)
John DeNisco68b0ee32017-09-27 16:35:23 -0400152
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200153 value = value.lstrip(" ").rstrip(" ")
John DeNisco68b0ee32017-09-27 16:35:23 -0400154 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 Vinciguerra582eac52020-04-03 12:18:40 -0400170 if len(vpp_cmdline):
171 # Update grub
172 # Save the original file
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200173 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 DeNisco68b0ee32017-09-27 16:35:23 -0400177
Paul Vinciguerra582eac52020-04-03 12:18:40 -0400178 # Write the output file
179 # Does a copy of the original file exist, if not create one
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200180 (ret, stdout, stderr) = VPPUtil.exec_command("ls {}".format(ofilename))
Paul Vinciguerra582eac52020-04-03 12:18:40 -0400181 if ret != 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200182 if stdout.strip("\n") != ofilename:
183 cmd = "sudo cp {} {}".format(filename, ofilename)
Paul Vinciguerra582eac52020-04-03 12:18:40 -0400184 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
185 if ret != 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200186 raise RuntimeError(
187 "{} failed on node {} {}".format(
188 cmd, self._node["host"], stderr
189 )
190 )
John DeNisco68b0ee32017-09-27 16:35:23 -0400191
Paul Vinciguerra582eac52020-04-03 12:18:40 -0400192 # Get the contents of the current grub config file
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200193 cmd = "cat {}".format(filename)
Paul Vinciguerra582eac52020-04-03 12:18:40 -0400194 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
195 if ret != 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200196 raise RuntimeError(
197 "{} failed on node {} {}".format(cmd, self._node["host"], stderr)
198 )
John DeNisco68b0ee32017-09-27 16:35:23 -0400199
Paul Vinciguerra582eac52020-04-03 12:18:40 -0400200 # Write the new contents
201 # Get the Default Linux command line, ignoring commented lines
202 content = ""
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200203 lines = stdout.split("\n")
Paul Vinciguerra582eac52020-04-03 12:18:40 -0400204 for line in lines:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200205 if line == "":
206 content += line + "\n"
Paul Vinciguerra582eac52020-04-03 12:18:40 -0400207 continue
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200208 if line[0] == "#":
209 content += line + "\n"
Paul Vinciguerra582eac52020-04-03 12:18:40 -0400210 continue
John DeNisco68b0ee32017-09-27 16:35:23 -0400211
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200212 ldefault = re.findall(r"{}=.+".format(grubcmdline), line)
Paul Vinciguerra582eac52020-04-03 12:18:40 -0400213 if ldefault:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200214 content += vpp_cmdline + "\n"
Paul Vinciguerra582eac52020-04-03 12:18:40 -0400215 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200216 content += line + "\n"
John DeNisco68b0ee32017-09-27 16:35:23 -0400217
Paul Vinciguerra582eac52020-04-03 12:18:40 -0400218 content = content.replace(r"`", r"\`")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200219 content = content.rstrip("\n")
Paul Vinciguerra582eac52020-04-03 12:18:40 -0400220 cmd = "sudo cat > {0} << EOF\n{1}\n".format(filename, content)
221 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
222 if ret != 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200223 raise RuntimeError(
224 "{} failed on node {} {}".format(cmd, self._node["host"], stderr)
225 )
John DeNisco68b0ee32017-09-27 16:35:23 -0400226
227 return vpp_cmdline
228
229 def __init__(self, node):
230 distro = VPPUtil.get_linux_distro()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200231 if distro[0] == "Ubuntu":
232 node["cpu"]["grubcmdline"] = "GRUB_CMDLINE_LINUX_DEFAULT"
John DeNisco68b0ee32017-09-27 16:35:23 -0400233 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200234 node["cpu"]["grubcmdline"] = "GRUB_CMDLINE_LINUX"
John DeNisco68b0ee32017-09-27 16:35:23 -0400235
236 self._node = node
237 self._current_cmdline = ""
238 self._default_cmdline = ""
239 self._get_current_cmdline()
240 self._get_default_cmdline()