2017-09-27 16:35:23 -04:00
|
|
|
# Copyright (c) 2016 Cisco and/or its affiliates.
|
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
# you may not use this file except in compliance with the License.
|
|
|
|
# You may obtain a copy of the License at:
|
|
|
|
#
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
#
|
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
# See the License for the specific language governing permissions and
|
|
|
|
# limitations under the License.
|
|
|
|
|
|
|
|
"""VPP Grub Utility Library."""
|
|
|
|
|
|
|
|
import re
|
|
|
|
|
|
|
|
from vpplib.VPPUtil import VPPUtil
|
|
|
|
|
2022-04-26 19:02:15 +02:00
|
|
|
__all__ = ["VppGrubUtil"]
|
2017-09-27 16:35:23 -04:00
|
|
|
|
|
|
|
|
|
|
|
class VppGrubUtil(object):
|
2022-04-26 19:02:15 +02:00
|
|
|
"""VPP Grub Utilities."""
|
2017-09-27 16:35:23 -04:00
|
|
|
|
|
|
|
def _get_current_cmdline(self):
|
|
|
|
"""
|
|
|
|
Using /proc/cmdline return the current grub cmdline
|
|
|
|
|
|
|
|
:returns: The current grub cmdline
|
|
|
|
:rtype: string
|
|
|
|
"""
|
|
|
|
|
|
|
|
# Get the memory information using /proc/meminfo
|
2022-04-26 19:02:15 +02:00
|
|
|
cmd = "sudo cat /proc/cmdline"
|
2017-09-27 16:35:23 -04:00
|
|
|
(ret, stdout, stderr) = VPPUtil.exec_command(cmd)
|
|
|
|
if ret != 0:
|
2022-04-26 19:02:15 +02:00
|
|
|
raise RuntimeError(
|
|
|
|
"{} on node {} {} {}".format(cmd, self._node["host"], stdout, stderr)
|
|
|
|
)
|
2017-09-27 16:35:23 -04:00
|
|
|
|
2022-04-26 19:02:15 +02:00
|
|
|
self._current_cmdline = stdout.strip("\n")
|
2017-09-27 16:35:23 -04:00
|
|
|
|
|
|
|
def _get_default_cmdline(self):
|
|
|
|
"""
|
|
|
|
Using /etc/default/grub return the default grub cmdline
|
|
|
|
|
|
|
|
:returns: The default grub cmdline
|
|
|
|
:rtype: string
|
|
|
|
"""
|
|
|
|
|
|
|
|
# Get the default grub cmdline
|
2022-04-26 19:02:15 +02:00
|
|
|
rootdir = self._node["rootdir"]
|
|
|
|
gfile = self._node["cpu"]["grub_config_file"]
|
|
|
|
grubcmdline = self._node["cpu"]["grubcmdline"]
|
|
|
|
cmd = "cat {}".format(rootdir + gfile)
|
2017-09-27 16:35:23 -04:00
|
|
|
(ret, stdout, stderr) = VPPUtil.exec_command(cmd)
|
|
|
|
if ret != 0:
|
2022-04-26 19:02:15 +02:00
|
|
|
raise RuntimeError(
|
|
|
|
"{} Executing failed on node {} {}".format(
|
|
|
|
cmd, self._node["host"], stderr
|
|
|
|
)
|
|
|
|
)
|
2017-09-27 16:35:23 -04:00
|
|
|
|
|
|
|
# Get the Default Linux command line, ignoring commented lines
|
2022-04-26 19:02:15 +02:00
|
|
|
lines = stdout.split("\n")
|
2017-09-27 16:35:23 -04:00
|
|
|
for line in lines:
|
2022-04-26 19:02:15 +02:00
|
|
|
if line == "" or line[0] == "#":
|
2017-09-27 16:35:23 -04:00
|
|
|
continue
|
2022-04-26 19:02:15 +02:00
|
|
|
ldefault = re.findall(r"{}=.+".format(grubcmdline), line)
|
2017-09-27 16:35:23 -04:00
|
|
|
if ldefault:
|
|
|
|
self._default_cmdline = ldefault[0]
|
|
|
|
break
|
|
|
|
|
|
|
|
def get_current_cmdline(self):
|
|
|
|
"""
|
|
|
|
Returns the saved grub cmdline
|
|
|
|
|
|
|
|
:returns: The saved grub cmdline
|
|
|
|
:rtype: string
|
|
|
|
"""
|
|
|
|
return self._current_cmdline
|
|
|
|
|
|
|
|
def get_default_cmdline(self):
|
|
|
|
"""
|
|
|
|
Returns the default grub cmdline
|
|
|
|
|
|
|
|
:returns: The default grub cmdline
|
|
|
|
:rtype: string
|
|
|
|
"""
|
|
|
|
return self._default_cmdline
|
|
|
|
|
|
|
|
def create_cmdline(self, isolated_cpus):
|
|
|
|
"""
|
|
|
|
Create the new grub cmdline
|
|
|
|
|
|
|
|
:param isolated_cpus: The isolated cpu string
|
|
|
|
:type isolated_cpus: string
|
|
|
|
:returns: The command line
|
|
|
|
:rtype: string
|
|
|
|
"""
|
2022-04-26 19:02:15 +02:00
|
|
|
grubcmdline = self._node["cpu"]["grubcmdline"]
|
2017-09-27 16:35:23 -04:00
|
|
|
cmdline = self._default_cmdline
|
2022-04-26 19:02:15 +02:00
|
|
|
value = cmdline.split("{}=".format(grubcmdline))[1]
|
2017-09-27 16:35:23 -04:00
|
|
|
value = value.rstrip('"').lstrip('"')
|
|
|
|
|
2018-12-19 02:05:25 -08:00
|
|
|
# jadfix intel_pstate=disable sometimes cause networks to
|
|
|
|
# hang on reboot
|
2017-11-01 12:37:47 -04:00
|
|
|
# iommu = re.findall(r'iommu=\w+', value)
|
|
|
|
# pstate = re.findall(r'intel_pstate=\w+', value)
|
2017-09-27 16:35:23 -04:00
|
|
|
# If there is already some iommu commands set, leave them,
|
|
|
|
# if not use ours
|
2017-11-01 12:37:47 -04:00
|
|
|
# if iommu == [] and pstate == []:
|
|
|
|
# value = '{} intel_pstate=disable'.format(value)
|
2017-09-27 16:35:23 -04:00
|
|
|
|
|
|
|
# Replace isolcpus with ours
|
2022-04-26 19:02:15 +02:00
|
|
|
isolcpus = re.findall(r"isolcpus=[\w+\-,]+", value)
|
2017-09-27 16:35:23 -04:00
|
|
|
if not isolcpus:
|
2022-04-26 19:02:15 +02:00
|
|
|
if isolated_cpus != "":
|
2017-09-27 16:35:23 -04:00
|
|
|
value = "{} isolcpus={}".format(value, isolated_cpus)
|
|
|
|
else:
|
2022-04-26 19:02:15 +02:00
|
|
|
if isolated_cpus != "":
|
|
|
|
value = re.sub(
|
|
|
|
r"isolcpus=[\w+\-,]+", "isolcpus={}".format(isolated_cpus), value
|
|
|
|
)
|
2017-09-27 16:35:23 -04:00
|
|
|
else:
|
2022-04-26 19:02:15 +02:00
|
|
|
value = re.sub(r"isolcpus=[\w+\-,]+", "", value)
|
2017-09-27 16:35:23 -04:00
|
|
|
|
2022-04-26 19:02:15 +02:00
|
|
|
nohz = re.findall(r"nohz_full=[\w+\-,]+", value)
|
2017-09-27 16:35:23 -04:00
|
|
|
if not nohz:
|
2022-04-26 19:02:15 +02:00
|
|
|
if isolated_cpus != "":
|
2017-09-27 16:35:23 -04:00
|
|
|
value = "{} nohz_full={}".format(value, isolated_cpus)
|
|
|
|
else:
|
2022-04-26 19:02:15 +02:00
|
|
|
if isolated_cpus != "":
|
|
|
|
value = re.sub(
|
|
|
|
r"nohz_full=[\w+\-,]+", "nohz_full={}".format(isolated_cpus), value
|
|
|
|
)
|
2017-09-27 16:35:23 -04:00
|
|
|
else:
|
2022-04-26 19:02:15 +02:00
|
|
|
value = re.sub(r"nohz_full=[\w+\-,]+", "", value)
|
2017-09-27 16:35:23 -04:00
|
|
|
|
2022-04-26 19:02:15 +02:00
|
|
|
rcu = re.findall(r"rcu_nocbs=[\w+\-,]+", value)
|
2017-09-27 16:35:23 -04:00
|
|
|
if not rcu:
|
2022-04-26 19:02:15 +02:00
|
|
|
if isolated_cpus != "":
|
2017-09-27 16:35:23 -04:00
|
|
|
value = "{} rcu_nocbs={}".format(value, isolated_cpus)
|
|
|
|
else:
|
2022-04-26 19:02:15 +02:00
|
|
|
if isolated_cpus != "":
|
|
|
|
value = re.sub(
|
|
|
|
r"rcu_nocbs=[\w+\-,]+", "rcu_nocbs={}".format(isolated_cpus), value
|
|
|
|
)
|
2017-09-27 16:35:23 -04:00
|
|
|
else:
|
2022-04-26 19:02:15 +02:00
|
|
|
value = re.sub(r"rcu_nocbs=[\w+\-,]+", "", value)
|
2017-09-27 16:35:23 -04:00
|
|
|
|
2022-04-26 19:02:15 +02:00
|
|
|
value = value.lstrip(" ").rstrip(" ")
|
2017-09-27 16:35:23 -04:00
|
|
|
cmdline = '{}="{}"'.format(grubcmdline, value)
|
|
|
|
return cmdline
|
|
|
|
|
|
|
|
def apply_cmdline(self, node, isolated_cpus):
|
|
|
|
"""
|
|
|
|
Apply cmdline to the default grub file
|
|
|
|
|
|
|
|
:param node: Node dictionary with cpuinfo.
|
|
|
|
:param isolated_cpus: The isolated cpu string
|
|
|
|
:type node: dict
|
|
|
|
:type isolated_cpus: string
|
|
|
|
:return The vpp cmdline
|
|
|
|
:rtype string
|
|
|
|
"""
|
|
|
|
|
|
|
|
vpp_cmdline = self.create_cmdline(isolated_cpus)
|
2020-04-03 12:18:40 -04:00
|
|
|
if len(vpp_cmdline):
|
|
|
|
# Update grub
|
|
|
|
# Save the original file
|
2022-04-26 19:02:15 +02:00
|
|
|
rootdir = node["rootdir"]
|
|
|
|
grubcmdline = node["cpu"]["grubcmdline"]
|
|
|
|
ofilename = rootdir + node["cpu"]["grub_config_file"] + ".orig"
|
|
|
|
filename = rootdir + node["cpu"]["grub_config_file"]
|
2020-04-03 12:18:40 -04:00
|
|
|
|
|
|
|
# Write the output file
|
|
|
|
# Does a copy of the original file exist, if not create one
|
2022-04-26 19:02:15 +02:00
|
|
|
(ret, stdout, stderr) = VPPUtil.exec_command("ls {}".format(ofilename))
|
2020-04-03 12:18:40 -04:00
|
|
|
if ret != 0:
|
2022-04-26 19:02:15 +02:00
|
|
|
if stdout.strip("\n") != ofilename:
|
|
|
|
cmd = "sudo cp {} {}".format(filename, ofilename)
|
2020-04-03 12:18:40 -04:00
|
|
|
(ret, stdout, stderr) = VPPUtil.exec_command(cmd)
|
|
|
|
if ret != 0:
|
2022-04-26 19:02:15 +02:00
|
|
|
raise RuntimeError(
|
|
|
|
"{} failed on node {} {}".format(
|
|
|
|
cmd, self._node["host"], stderr
|
|
|
|
)
|
|
|
|
)
|
2020-04-03 12:18:40 -04:00
|
|
|
|
|
|
|
# Get the contents of the current grub config file
|
2022-04-26 19:02:15 +02:00
|
|
|
cmd = "cat {}".format(filename)
|
2020-04-03 12:18:40 -04:00
|
|
|
(ret, stdout, stderr) = VPPUtil.exec_command(cmd)
|
|
|
|
if ret != 0:
|
2022-04-26 19:02:15 +02:00
|
|
|
raise RuntimeError(
|
|
|
|
"{} failed on node {} {}".format(cmd, self._node["host"], stderr)
|
|
|
|
)
|
2020-04-03 12:18:40 -04:00
|
|
|
|
|
|
|
# Write the new contents
|
|
|
|
# Get the Default Linux command line, ignoring commented lines
|
|
|
|
content = ""
|
2022-04-26 19:02:15 +02:00
|
|
|
lines = stdout.split("\n")
|
2020-04-03 12:18:40 -04:00
|
|
|
for line in lines:
|
2022-04-26 19:02:15 +02:00
|
|
|
if line == "":
|
|
|
|
content += line + "\n"
|
2020-04-03 12:18:40 -04:00
|
|
|
continue
|
2022-04-26 19:02:15 +02:00
|
|
|
if line[0] == "#":
|
|
|
|
content += line + "\n"
|
2020-04-03 12:18:40 -04:00
|
|
|
continue
|
|
|
|
|
2022-04-26 19:02:15 +02:00
|
|
|
ldefault = re.findall(r"{}=.+".format(grubcmdline), line)
|
2020-04-03 12:18:40 -04:00
|
|
|
if ldefault:
|
2022-04-26 19:02:15 +02:00
|
|
|
content += vpp_cmdline + "\n"
|
2020-04-03 12:18:40 -04:00
|
|
|
else:
|
2022-04-26 19:02:15 +02:00
|
|
|
content += line + "\n"
|
2020-04-03 12:18:40 -04:00
|
|
|
|
|
|
|
content = content.replace(r"`", r"\`")
|
2022-04-26 19:02:15 +02:00
|
|
|
content = content.rstrip("\n")
|
2020-04-03 12:18:40 -04:00
|
|
|
cmd = "sudo cat > {0} << EOF\n{1}\n".format(filename, content)
|
|
|
|
(ret, stdout, stderr) = VPPUtil.exec_command(cmd)
|
|
|
|
if ret != 0:
|
2022-04-26 19:02:15 +02:00
|
|
|
raise RuntimeError(
|
|
|
|
"{} failed on node {} {}".format(cmd, self._node["host"], stderr)
|
|
|
|
)
|
2017-09-27 16:35:23 -04:00
|
|
|
|
|
|
|
return vpp_cmdline
|
|
|
|
|
|
|
|
def __init__(self, node):
|
|
|
|
distro = VPPUtil.get_linux_distro()
|
2022-04-26 19:02:15 +02:00
|
|
|
if distro[0] == "Ubuntu":
|
|
|
|
node["cpu"]["grubcmdline"] = "GRUB_CMDLINE_LINUX_DEFAULT"
|
2017-09-27 16:35:23 -04:00
|
|
|
else:
|
2022-04-26 19:02:15 +02:00
|
|
|
node["cpu"]["grubcmdline"] = "GRUB_CMDLINE_LINUX"
|
2017-09-27 16:35:23 -04:00
|
|
|
|
|
|
|
self._node = node
|
|
|
|
self._current_cmdline = ""
|
|
|
|
self._default_cmdline = ""
|
|
|
|
self._get_current_cmdline()
|
|
|
|
self._get_default_cmdline()
|