]> git.proxmox.com Git - mirror_ifupdown2.git/blob - ifupdown2/addons/ethtool.py
addon: ethtool: link-speed: add 10 to valid values array
[mirror_ifupdown2.git] / ifupdown2 / addons / ethtool.py
1 #!/usr/bin/python
2 #
3 # Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
4 # Author: Roopa Prabhu, roopa@cumulusnetworks.com
5 #
6
7 import os
8
9 try:
10 import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
11 import ifupdown2.ifupdown.policymanager as policymanager
12
13 from ifupdown2.ifupdown.iface import *
14 from ifupdown2.ifupdown.utils import utils
15 from ifupdown2.ifupdown.exceptions import moduleNotSupported
16
17 from ifupdown2.ifupdownaddons.utilsbase import *
18 from ifupdown2.ifupdownaddons.LinkUtils import LinkUtils
19 from ifupdown2.ifupdownaddons.modulebase import moduleBase
20 except ImportError:
21 import ifupdown.ifupdownflags as ifupdownflags
22 import ifupdown.policymanager as policymanager
23
24 from ifupdown.iface import *
25 from ifupdown.utils import utils
26 from ifupdown.exceptions import moduleNotSupported
27
28 from ifupdownaddons.utilsbase import *
29 from ifupdownaddons.LinkUtils import LinkUtils
30 from ifupdownaddons.modulebase import moduleBase
31
32
33 class ethtool(moduleBase,utilsBase):
34 """ ifupdown2 addon module to configure ethtool attributes """
35
36 _modinfo = {'mhelp' : 'ethtool configuration module for interfaces',
37 'attrs': {
38 'link-speed' :
39 {'help' : 'set link speed',
40 'validvals' : ['10',
41 '100',
42 '1000',
43 '10000',
44 '25000',
45 '40000',
46 '50000',
47 '100000'],
48 'example' : ['link-speed 1000'],
49 'default' : 'varies by platform and port'},
50 'link-duplex' :
51 {'help': 'set link duplex',
52 'example' : ['link-duplex full'],
53 'validvals' : ['half', 'full'],
54 'default' : 'full'},
55 'link-autoneg' :
56 {'help': 'set autonegotiation',
57 'example' : ['link-autoneg on'],
58 'validvals' : ['yes', 'no', 'on', 'off'],
59 'default' : 'varies by platform and port'},
60 'link-fec' :
61 {'help': 'set forward error correction mode',
62 'example' : ['link-fec rs'],
63 'validvals' : ['rs', 'baser', 'auto', 'off'],
64 'default' : 'varies by platform and port'}}}
65
66 def __init__(self, *args, **kargs):
67 moduleBase.__init__(self, *args, **kargs)
68 if not os.path.exists(utils.ethtool_cmd):
69 raise moduleNotSupported('module init failed: %s: not found' % utils.ethtool_cmd)
70 self.ipcmd = None
71 # keep a list of iface objects who have modified link attributes
72 self.ifaceobjs_modified_configs = []
73
74 def do_fec_settings(self, ifaceobj):
75 feccmd = ''
76
77 # attribute existed before but we must reset to default
78 config_val = ifaceobj.get_attr_value_first('link-fec')
79 default_val = policymanager.policymanager_api.get_iface_default(
80 module_name='ethtool',
81 ifname=ifaceobj.name,
82 attr='link-fec')
83
84 if not default_val and not config_val:
85 # there is no point in checking the running config
86 # if we have no default and the user did not have settings
87 return
88
89 # check running values
90 running_val = self.get_running_attr('fec', ifaceobj)
91 if config_val and config_val == running_val:
92 return
93
94 if not config_val and default_val and default_val == running_val:
95 # nothing configured but the default is running
96 return
97
98 # if we got this far, we need to change it
99 if config_val and (config_val != running_val):
100 # if the configured value is not set, set it
101 feccmd = ' %s %s' % ("encoding", config_val)
102 elif default_val and (default_val != running_val):
103 # or if it has a default not equal to running value, set it
104 feccmd = ' %s %s' % ("encoding", default_val)
105
106 if feccmd:
107 try:
108 feccmd = ('%s --set-fec %s %s' %
109 (utils.ethtool_cmd, ifaceobj.name, feccmd))
110 utils.exec_command(feccmd)
111 except Exception, e:
112 self.log_error('%s: %s' %(ifaceobj.name, str(e)), ifaceobj)
113 else:
114 pass
115
116 def do_speed_settings(self, ifaceobj, operation='post_up'):
117 cmd = ''
118
119 autoneg_to_configure = None
120 speed_to_configure = None
121 duplex_to_configure = None
122
123 config_speed = ifaceobj.get_attr_value_first('link-speed')
124 config_duplex = ifaceobj.get_attr_value_first('link-duplex')
125 config_autoneg = ifaceobj.get_attr_value_first('link-autoneg')
126
127 default_speed = policymanager.policymanager_api.get_iface_default(
128 module_name='ethtool',
129 ifname=ifaceobj.name,
130 attr='link-speed'
131 )
132
133 default_duplex = policymanager.policymanager_api.get_iface_default(
134 module_name='ethtool',
135 ifname=ifaceobj.name,
136 attr='link-duplex'
137 )
138
139 default_autoneg = policymanager.policymanager_api.get_iface_default(
140 module_name='ethtool',
141 ifname=ifaceobj.name,
142 attr='link-autoneg'
143 )
144
145 # autoneg wins if provided by user and is on
146 if config_autoneg and utils.get_boolean_from_string(config_autoneg):
147 autoneg_to_configure = config_autoneg
148 speed_to_configure = None
149 duplex_to_configure = None
150 elif config_speed:
151 # Any speed settings configured by the user wins
152 autoneg_to_configure = None
153 speed_to_configure = config_speed
154 duplex_to_configure = config_duplex
155 if not config_duplex:
156 duplex_to_configure = default_duplex
157 else:
158 # if user given autoneg config is off, we must respect that and
159 # override any default autoneg config
160 if config_autoneg and not utils.get_boolean_from_string(config_autoneg):
161 default_autoneg = 'off'
162
163 if default_autoneg and utils.get_boolean_from_string(default_autoneg):
164 autoneg_to_configure = utils.get_onoff_bool(default_autoneg)
165 speed_to_configure = None
166 duplex_to_configure = None
167 else:
168 autoneg_to_configure = None
169 speed_to_configure = default_speed
170 duplex_to_configure = default_duplex
171
172 if autoneg_to_configure:
173 autoneg_to_configure = utils.get_onoff_bool(autoneg_to_configure)
174 # check running values
175 running_val = self.get_running_attr('autoneg', ifaceobj)
176 if autoneg_to_configure != running_val:
177 # if the configured value is not set, set it
178 cmd += ' autoneg %s' % autoneg_to_configure
179 else:
180 force_set = False
181 if speed_to_configure:
182 # check running values
183 if utils.get_boolean_from_string(self.get_running_attr('autoneg', ifaceobj) or 'off'):
184 cmd = 'autoneg off'
185 # if we are transitioning from autoneg 'on' to 'off'
186 # don't check running speed
187 force_set = True
188
189 running_val = self.get_running_attr('speed', ifaceobj)
190 if force_set or (speed_to_configure != running_val):
191 # if the configured value is not set, set it
192 cmd += ' speed %s' % speed_to_configure
193
194 if duplex_to_configure:
195 # check running values
196 running_val = self.get_running_attr('duplex', ifaceobj)
197 if force_set or (duplex_to_configure != running_val):
198 # if the configured value is not set, set it
199 cmd += ' duplex %s' % duplex_to_configure
200
201 if cmd:
202 try:
203 cmd = ('%s -s %s %s' % (utils.ethtool_cmd, ifaceobj.name, cmd))
204 utils.exec_command(cmd)
205 except Exception, e:
206 self.log_error('%s: %s' %(ifaceobj.name, str(e)), ifaceobj, raise_error=False)
207
208 def _pre_up(self, ifaceobj, operation='post_up'):
209 """
210 _pre_up and _pre_down will reset the layer 2 attributes to default policy
211 settings.
212 """
213 if not self.ipcmd.link_exists(ifaceobj.name):
214 return
215
216 self.do_speed_settings(ifaceobj)
217 self.do_fec_settings(ifaceobj)
218
219 def _pre_down(self, ifaceobj):
220 pass #self._post_up(ifaceobj,operation="_pre_down")
221
222 def _query_check(self, ifaceobj, ifaceobjcurr):
223 """
224 _query_check() needs to compare the configured (or running)
225 attribute with the running attribute.
226
227 If there is nothing configured, we compare the default attribute with
228 the running attribute and FAIL if they are different.
229 This is because a reboot will lose their running attribute
230 (the default will get set).
231 """
232 for attr in ['speed', 'duplex', 'autoneg', 'fec']:
233 configured = ifaceobj.get_attr_value_first('link-%s'%attr)
234 # if there is nothing configured, do not check
235 if not configured:
236 if not ifupdownflags.flags.WITHDEFAULTS:
237 continue
238 default = policymanager.policymanager_api.get_iface_default(
239 module_name='ethtool',
240 ifname=ifaceobj.name,
241 attr='link-%s'%attr)
242 # if we have no default, do not bother checking
243 # this avoids ethtool calls on virtual interfaces
244 if not default:
245 continue
246 # autoneg comes from ethtool whereas speed and duplex from /sys/class
247 running_attr = self.get_running_attr(attr, ifaceobj)
248 if not running_attr:
249 if not configured:
250 continue
251 ifaceobjcurr.update_config_with_status('link-%s' % attr,
252 'unknown', 1)
253 continue
254
255 if attr == 'autoneg':
256 if configured == 'yes' and running_attr == 'on':
257 running_attr = 'yes'
258 elif configured == 'no' and running_attr == 'off':
259 running_attr = 'no'
260
261 # we make sure we can get a running value first
262 if (running_attr and configured and running_attr == configured):
263 # PASS since running is what is configured
264 ifaceobjcurr.update_config_with_status('link-%s'%attr,
265 running_attr, 0)
266 elif (running_attr and configured and running_attr != configured):
267 # We show a FAIL since it is not the configured or default
268 ifaceobjcurr.update_config_with_status('link-%s'%attr,
269 running_attr, 1)
270 elif (running_attr and default and running_attr == default):
271 # PASS since running is default
272 ifaceobjcurr.update_config_with_status('link-%s'%attr,
273 running_attr, 0)
274 elif (default or configured):
275 # We show a FAIL since it is not the configured or default
276 ifaceobjcurr.update_config_with_status('link-%s'%attr,
277 running_attr, 1)
278 return
279
280 def get_autoneg(self,ethtool_output=None):
281 """
282 get_autoneg simply calls the ethtool command and parses out
283 the autoneg value.
284 """
285 ethtool_attrs = ethtool_output.split()
286 if ('Auto-negotiation:' in ethtool_attrs):
287 return(ethtool_attrs[ethtool_attrs.index('Auto-negotiation:')+1])
288 else:
289 return(None)
290
291 def get_fec_encoding(self,ethtool_output=None):
292 """
293 get_fec_encoding simply calls the ethtool show-fec command and parses out
294 the fec encoding value.
295 """
296 try:
297 for attr in ethtool_output.splitlines():
298 if attr.startswith('FEC encodings'):
299 fec_attrs = attr.split()
300 return(fec_attrs[fec_attrs.index(':')+1])
301 except Exception as e:
302 self.logger.debug('ethtool: problems in ethtool set-fec output'
303 ' %s: %s' %(ethtool_output.splitlines(), str(e)))
304
305 return(None)
306
307 def get_running_attr(self,attr='',ifaceobj=None):
308 if not ifaceobj or not attr:
309 return
310 running_attr = None
311 try:
312 if attr == 'autoneg':
313 output = utils.exec_commandl([utils.ethtool_cmd, ifaceobj.name])
314 running_attr = self.get_autoneg(ethtool_output=output)
315 elif attr == 'fec':
316 output = utils.exec_command('%s --show-fec %s'%
317 (utils.ethtool_cmd, ifaceobj.name))
318 running_attr = self.get_fec_encoding(ethtool_output=output)
319 else:
320 running_attr = self.read_file_oneline('/sys/class/net/%s/%s' % \
321 (ifaceobj.name, attr))
322 except Exception as e:
323 # for nonexistent interfaces, we get an error (rc = 256 or 19200)
324 self.logger.debug('ethtool: problems calling ethtool or reading'
325 ' /sys/class on iface %s for attr %s: %s' %
326 (ifaceobj.name, attr, str(e)))
327 return running_attr
328
329
330 def _query_running(self, ifaceobj, ifaceobj_getfunc=None):
331 """
332 _query_running looks at the speed and duplex from /sys/class
333 and retreives autoneg from ethtool. We do not report autoneg
334 if speed is not available because this usually means the link is
335 down and the autoneg value is not reliable when the link is down.
336 """
337 # do not bother showing swp ifaces that are not up for the speed
338 # duplex and autoneg are not reliable.
339 if not self.ipcmd.is_link_up(ifaceobj.name):
340 return
341 for attr in ['speed', 'duplex', 'autoneg']:
342 default_val = policymanager.policymanager_api.get_iface_default(
343 module_name='ethtool',
344 ifname=ifaceobj.name,
345 attr='link-%s'%attr)
346 # do not continue if we have no defaults
347 # this avoids ethtool calls on virtual interfaces
348 if not default_val:
349 continue
350 running_attr = self.get_running_attr(attr, ifaceobj)
351
352 # Only show the link attributes if they differ from defaults
353 # to see the defaults, we should implement another flag (--with-defaults)
354 if default_val == running_attr:
355 continue
356
357 # do not proceed if speed = 0
358 if attr == 'speed' and running_attr and running_attr == '0':
359 return
360 if running_attr:
361 ifaceobj.update_config('link-%s'%attr, running_attr)
362
363 return
364
365 def _query(self, ifaceobj, **kwargs):
366 """ add default policy attributes supported by the module """
367 for attr in ['speed', 'duplex', 'autoneg', 'fec']:
368 if ifaceobj.get_attr_value_first('link-%s'%attr):
369 continue
370 default = policymanager.policymanager_api.get_iface_default(
371 module_name='ethtool',
372 ifname=ifaceobj.name,
373 attr='link-%s' %attr)
374 if not default:
375 continue
376 ifaceobj.update_config('link-%s' %attr, default)
377
378 _run_ops = {'pre-down' : _pre_down,
379 'pre-up' : _pre_up,
380 'query-checkcurr' : _query_check,
381 'query-running' : _query_running,
382 'query' : _query}
383
384 def get_ops(self):
385 """ returns list of ops supported by this module """
386 return self._run_ops.keys()
387
388 def _init_command_handlers(self):
389 if not self.ipcmd:
390 self.ipcmd = LinkUtils()
391
392 def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
393 """ run ethtool configuration on the interface object passed as
394 argument
395
396 Args:
397 **ifaceobj** (object): iface object
398
399 **operation** (str): any of 'post-up', 'query-checkcurr',
400 'query-running'
401 Kwargs:
402 **query_ifaceobj** (object): query check ifaceobject. This is only
403 valid when op is 'query-checkcurr'. It is an object same as
404 ifaceobj, but contains running attribute values and its config
405 status. The modules can use it to return queried running state
406 of interfaces. status is success if the running state is same
407 as user required state in ifaceobj. error otherwise.
408 """
409 if (ifaceobj.link_kind or
410 ifaceobj.link_privflags & ifaceLinkPrivFlags.LOOPBACK):
411 return
412 op_handler = self._run_ops.get(operation)
413 if not op_handler:
414 return
415 self._init_command_handlers()
416 if operation == 'query-checkcurr':
417 op_handler(self, ifaceobj, query_ifaceobj)
418 else:
419 op_handler(self, ifaceobj)