]> git.proxmox.com Git - mirror_ifupdown2.git/blame - ifupdown2/addons/ethtool.py
addon: ethtool: link-speed: add 10 to valid values array
[mirror_ifupdown2.git] / ifupdown2 / addons / ethtool.py
CommitLineData
15ef32ea
RP
1#!/usr/bin/python
2#
d486dd0d 3# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
15ef32ea
RP
4# Author: Roopa Prabhu, roopa@cumulusnetworks.com
5#
d486dd0d
JF
6
7import os
15ef32ea
RP
8
9try:
d486dd0d
JF
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
20except ImportError:
21 import ifupdown.ifupdownflags as ifupdownflags
22 import ifupdown.policymanager as policymanager
23
15ef32ea 24 from ifupdown.iface import *
a193d8d1 25 from ifupdown.utils import utils
d486dd0d
JF
26 from ifupdown.exceptions import moduleNotSupported
27
3d44fbd0 28 from ifupdownaddons.utilsbase import *
d486dd0d
JF
29 from ifupdownaddons.LinkUtils import LinkUtils
30 from ifupdownaddons.modulebase import moduleBase
31
15ef32ea 32
3d44fbd0 33class ethtool(moduleBase,utilsBase):
15ef32ea
RP
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',
a220d2d1
JF
40 'validvals' : ['10',
41 '100',
a4cf8448
JF
42 '1000',
43 '10000',
44 '25000',
45 '40000',
46 '50000',
47 '100000'],
3d44fbd0
ST
48 'example' : ['link-speed 1000'],
49 'default' : 'varies by platform and port'},
15ef32ea
RP
50 'link-duplex' :
51 {'help': 'set link duplex',
52 'example' : ['link-duplex full'],
53 'validvals' : ['half', 'full'],
3d44fbd0 54 'default' : 'full'},
15ef32ea
RP
55 'link-autoneg' :
56 {'help': 'set autonegotiation',
57 'example' : ['link-autoneg on'],
594fb088 58 'validvals' : ['yes', 'no', 'on', 'off'],
d8b6aad0
VSR
59 'default' : 'varies by platform and port'},
60 'link-fec' :
61 {'help': 'set forward error correction mode',
62 'example' : ['link-fec rs'],
d486dd0d 63 'validvals' : ['rs', 'baser', 'auto', 'off'],
3d44fbd0 64 'default' : 'varies by platform and port'}}}
15ef32ea
RP
65
66 def __init__(self, *args, **kargs):
67 moduleBase.__init__(self, *args, **kargs)
d486dd0d
JF
68 if not os.path.exists(utils.ethtool_cmd):
69 raise moduleNotSupported('module init failed: %s: not found' % utils.ethtool_cmd)
15ef32ea 70 self.ipcmd = None
7444feea
ST
71 # keep a list of iface objects who have modified link attributes
72 self.ifaceobjs_modified_configs = []
15ef32ea 73
d486dd0d 74 def do_fec_settings(self, ifaceobj):
d8b6aad0 75 feccmd = ''
3d44fbd0 76
d486dd0d
JF
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')
594fb088 83
d486dd0d
JF
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
7444feea 88
d486dd0d
JF
89 # check running values
90 running_val = self.get_running_attr('fec', ifaceobj)
91 if config_val and config_val == running_val:
92 return
7444feea 93
d486dd0d
JF
94 if not config_val and default_val and default_val == running_val:
95 # nothing configured but the default is running
96 return
7444feea 97
d486dd0d
JF
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)
d8b6aad0 105
d486dd0d 106 if feccmd:
15ef32ea 107 try:
d486dd0d
JF
108 feccmd = ('%s --set-fec %s %s' %
109 (utils.ethtool_cmd, ifaceobj.name, feccmd))
110 utils.exec_command(feccmd)
15ef32ea 111 except Exception, e:
bf3eda91 112 self.log_error('%s: %s' %(ifaceobj.name, str(e)), ifaceobj)
3d44fbd0
ST
113 else:
114 pass
115
d486dd0d
JF
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:
d8b6aad0 202 try:
d486dd0d
JF
203 cmd = ('%s -s %s %s' % (utils.ethtool_cmd, ifaceobj.name, cmd))
204 utils.exec_command(cmd)
d8b6aad0 205 except Exception, e:
d486dd0d
JF
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)
d8b6aad0 218
3d44fbd0
ST
219 def _pre_down(self, ifaceobj):
220 pass #self._post_up(ifaceobj,operation="_pre_down")
15ef32ea 221
6e16e5ae 222 def _query_check(self, ifaceobj, ifaceobjcurr):
e74d01e1 223 """
3d44fbd0
ST
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 """
d8b6aad0 232 for attr in ['speed', 'duplex', 'autoneg', 'fec']:
97202602
ST
233 configured = ifaceobj.get_attr_value_first('link-%s'%attr)
234 # if there is nothing configured, do not check
235 if not configured:
6e16e5ae 236 if not ifupdownflags.flags.WITHDEFAULTS:
669b422a 237 continue
3d44fbd0
ST
238 default = policymanager.policymanager_api.get_iface_default(
239 module_name='ethtool',
240 ifname=ifaceobj.name,
241 attr='link-%s'%attr)
8d60ab41
ST
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)
b2a87e4e
JF
248 if not running_attr:
249 if not configured:
250 continue
251 ifaceobjcurr.update_config_with_status('link-%s' % attr,
252 'unknown', 1)
3d44fbd0
ST
253 continue
254
594fb088
JF
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
3d44fbd0
ST
261 # we make sure we can get a running value first
262 if (running_attr and configured and running_attr == configured):
d8b6aad0 263 # PASS since running is what is configured
3d44fbd0
ST
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
d8b6aad0
VSR
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()
6092d545 300 return(fec_attrs[fec_attrs.index(':')+1])
d8b6aad0
VSR
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
d2431a3d
ST
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':
d486dd0d 313 output = utils.exec_commandl([utils.ethtool_cmd, ifaceobj.name])
d2431a3d 314 running_attr = self.get_autoneg(ethtool_output=output)
d8b6aad0 315 elif attr == 'fec':
d486dd0d
JF
316 output = utils.exec_command('%s --show-fec %s'%
317 (utils.ethtool_cmd, ifaceobj.name))
d8b6aad0 318 running_attr = self.get_fec_encoding(ethtool_output=output)
d2431a3d
ST
319 else:
320 running_attr = self.read_file_oneline('/sys/class/net/%s/%s' % \
321 (ifaceobj.name, attr))
a193d8d1 322 except Exception as e:
d2431a3d
ST
323 # for nonexistent interfaces, we get an error (rc = 256 or 19200)
324 self.logger.debug('ethtool: problems calling ethtool or reading'
a193d8d1
JF
325 ' /sys/class on iface %s for attr %s: %s' %
326 (ifaceobj.name, attr, str(e)))
d2431a3d
ST
327 return running_attr
328
329
3d44fbd0
ST
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):
e74d01e1 340 return
3d44fbd0 341 for attr in ['speed', 'duplex', 'autoneg']:
8d60ab41
ST
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
d2431a3d 350 running_attr = self.get_running_attr(attr, ifaceobj)
d8b6aad0 351
16e30aab
ST
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
151d8024
RP
356
357 # do not proceed if speed = 0
358 if attr == 'speed' and running_attr and running_attr == '0':
359 return
8d60ab41 360 if running_attr:
3d44fbd0 361 ifaceobj.update_config('link-%s'%attr, running_attr)
15ef32ea 362
15ef32ea
RP
363 return
364
baa909c6
N
365 def _query(self, ifaceobj, **kwargs):
366 """ add default policy attributes supported by the module """
d8b6aad0 367 for attr in ['speed', 'duplex', 'autoneg', 'fec']:
baa909c6
N
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
3d44fbd0 378 _run_ops = {'pre-down' : _pre_down,
d486dd0d 379 'pre-up' : _pre_up,
3d44fbd0 380 'query-checkcurr' : _query_check,
baa909c6
N
381 'query-running' : _query_running,
382 'query' : _query}
15ef32ea
RP
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:
d486dd0d 390 self.ipcmd = LinkUtils()
15ef32ea 391
84ca006f 392 def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
15ef32ea
RP
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 """
6ceda69e
JF
409 if (ifaceobj.link_kind or
410 ifaceobj.link_privflags & ifaceLinkPrivFlags.LOOPBACK):
d07b5a9f 411 return
15ef32ea
RP
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':
6e16e5ae 417 op_handler(self, ifaceobj, query_ifaceobj)
15ef32ea
RP
418 else:
419 op_handler(self, ifaceobj)