blob: 1723170649ec3b3757fe35337239101b06316ea4 [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
20__all__ = ['VppGrubUtil']
21
22
23class VppGrubUtil(object):
24 """ VPP Grub Utilities."""
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
35 cmd = 'sudo cat /proc/cmdline'
36 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
37 if ret != 0:
38 raise RuntimeError('{} on node {} {} {}'.
39 format(cmd, self._node['host'],
40 stdout, stderr))
41
42 self._current_cmdline = stdout.strip('\n')
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
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)
57 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
58 if ret != 0:
59 raise RuntimeError('{} Executing failed on node {} {}'.
60 format(cmd, self._node['host'], stderr))
61
62 # Get the Default Linux command line, ignoring commented lines
63 lines = stdout.split('\n')
64 for line in lines:
65 if line == '' or line[0] == '#':
66 continue
67 ldefault = re.findall(r'{}=.+'.format(grubcmdline), line)
68 if ldefault:
69 self._default_cmdline = ldefault[0]
70 break
71
72 def get_current_cmdline(self):
73 """
74 Returns the saved grub cmdline
75
76 :returns: The saved grub cmdline
77 :rtype: string
78 """
79 return self._current_cmdline
80
81 def get_default_cmdline(self):
82 """
83 Returns the default grub cmdline
84
85 :returns: The default grub cmdline
86 :rtype: string
87 """
88 return self._default_cmdline
89
90 def create_cmdline(self, isolated_cpus):
91 """
92 Create the new grub cmdline
93
94 :param isolated_cpus: The isolated cpu string
95 :type isolated_cpus: string
96 :returns: The command line
97 :rtype: string
98 """
99 grubcmdline = self._node['cpu']['grubcmdline']
100 cmdline = self._default_cmdline
101 value = cmdline.split('{}='.format(grubcmdline))[1]
102 value = value.rstrip('"').lstrip('"')
103
John DeNiscoc6b2a202017-11-01 12:37:47 -0400104 # jadfix intel_pstate=disable sometimes cause networks to hang on reboot
105 # iommu = re.findall(r'iommu=\w+', value)
106 # pstate = re.findall(r'intel_pstate=\w+', value)
John DeNisco68b0ee32017-09-27 16:35:23 -0400107 # If there is already some iommu commands set, leave them,
108 # if not use ours
John DeNiscoc6b2a202017-11-01 12:37:47 -0400109 # if iommu == [] and pstate == []:
110 # value = '{} intel_pstate=disable'.format(value)
John DeNisco68b0ee32017-09-27 16:35:23 -0400111
112 # Replace isolcpus with ours
113 isolcpus = re.findall(r'isolcpus=[\w+\-,]+', value)
114 if not isolcpus:
115 if isolated_cpus != '':
116 value = "{} isolcpus={}".format(value, isolated_cpus)
117 else:
118 if isolated_cpus != '':
119 value = re.sub(r'isolcpus=[\w+\-,]+',
120 'isolcpus={}'.format(isolated_cpus),
121 value)
122 else:
123 value = re.sub(r'isolcpus=[\w+\-,]+', '', value)
124
125 nohz = re.findall(r'nohz_full=[\w+\-,]+', value)
126 if not nohz:
127 if isolated_cpus != '':
128 value = "{} nohz_full={}".format(value, isolated_cpus)
129 else:
130 if isolated_cpus != '':
131 value = re.sub(r'nohz_full=[\w+\-,]+',
132 'nohz_full={}'.format(isolated_cpus),
133 value)
134 else:
135 value = re.sub(r'nohz_full=[\w+\-,]+', '', value)
136
137 rcu = re.findall(r'rcu_nocbs=[\w+\-,]+', value)
138 if not rcu:
139 if isolated_cpus != '':
140 value = "{} rcu_nocbs={}".format(value, isolated_cpus)
141 else:
142 if isolated_cpus != '':
143 value = re.sub(r'rcu_nocbs=[\w+\-,]+',
144 'rcu_nocbs={}'.format(isolated_cpus),
145 value)
146 else:
147 value = re.sub(r'rcu_nocbs=[\w+\-,]+', '', value)
148
149 value = value.lstrip(' ').rstrip(' ')
150 cmdline = '{}="{}"'.format(grubcmdline, value)
151 return cmdline
152
153 def apply_cmdline(self, node, isolated_cpus):
154 """
155 Apply cmdline to the default grub file
156
157 :param node: Node dictionary with cpuinfo.
158 :param isolated_cpus: The isolated cpu string
159 :type node: dict
160 :type isolated_cpus: string
161 :return The vpp cmdline
162 :rtype string
163 """
164
165 vpp_cmdline = self.create_cmdline(isolated_cpus)
166 if vpp_cmdline == '':
167 return vpp_cmdline
168
169 # Update grub
170 # Save the original file
171 rootdir = node['rootdir']
172 grubcmdline = node['cpu']['grubcmdline']
173 ofilename = rootdir + node['cpu']['grub_config_file'] + '.orig'
174 filename = rootdir + node['cpu']['grub_config_file']
175
176 # Write the output file
177 # Does a copy of the original file exist, if not create one
178 (ret, stdout, stderr) = VPPUtil.exec_command('ls {}'.format(ofilename))
179 if ret != 0:
180 if stdout.strip('\n') != ofilename:
181 cmd = 'sudo cp {} {}'.format(filename, ofilename)
182 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
183 if ret != 0:
184 raise RuntimeError('{} failed on node {} {}'.
185 format(cmd, self._node['host'], stderr))
186
187 # Get the contents of the current grub config file
188 cmd = 'cat {}'.format(filename)
189 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
190 if ret != 0:
191 raise RuntimeError('{} failed on node {} {}'.format(
192 cmd,
193 self._node['host'],
194 stderr))
195
196 # Write the new contents
197 # Get the Default Linux command line, ignoring commented lines
198 content = ""
199 lines = stdout.split('\n')
200 for line in lines:
201 if line == '':
202 content += line + '\n'
203 continue
204 if line[0] == '#':
205 content += line + '\n'
206 continue
207
208 ldefault = re.findall(r'{}=.+'.format(grubcmdline), line)
209 if ldefault:
210 content += vpp_cmdline + '\n'
211 else:
212 content += line + '\n'
213
214 content = content.replace(r"`", r"\`")
215 content = content.rstrip('\n')
216 cmd = "sudo cat > {0} << EOF\n{1}\n".format(filename, content)
217 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
218 if ret != 0:
219 raise RuntimeError('{} failed on node {} {}'.format(
220 cmd,
221 self._node['host'],
222 stderr))
223
224 return vpp_cmdline
225
226 def __init__(self, node):
227 distro = VPPUtil.get_linux_distro()
228 if distro[0] == 'Ubuntu':
229 node['cpu']['grubcmdline'] = 'GRUB_CMDLINE_LINUX_DEFAULT'
230 else:
231 node['cpu']['grubcmdline'] = 'GRUB_CMDLINE_LINUX'
232
233 self._node = node
234 self._current_cmdline = ""
235 self._default_cmdline = ""
236 self._get_current_cmdline()
237 self._get_default_cmdline()