]> git.proxmox.com Git - mirror_ifupdown2.git/blame - ifupdown2/addons/ethtool.py
Fixed new file addition breakage with 0b762139
[mirror_ifupdown2.git] / ifupdown2 / addons / ethtool.py
CommitLineData
f82758bf
RP
1#!/usr/bin/python
2#
3# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
4# Author: Roopa Prabhu, roopa@cumulusnetworks.com
5#
0b762139
ST
6import json
7import ifupdown.policymanager as policymanager
f82758bf
RP
8
9try:
10 from ipaddr import IPNetwork
11 from sets import Set
12 from ifupdown.iface import *
0b762139 13 from ifupdownaddons.utilsbase import *
f82758bf
RP
14 from ifupdownaddons.modulebase import moduleBase
15 from ifupdownaddons.iproute2 import iproute2
16except ImportError, e:
17 raise ImportError (str(e) + "- required module not found")
18
0b762139 19class ethtool(moduleBase,utilsBase):
f82758bf
RP
20 """ ifupdown2 addon module to configure ethtool attributes """
21
22 _modinfo = {'mhelp' : 'ethtool configuration module for interfaces',
23 'attrs': {
24 'link-speed' :
25 {'help' : 'set link speed',
0b762139
ST
26 'example' : ['link-speed 1000'],
27 'default' : 'varies by platform and port'},
f82758bf
RP
28 'link-duplex' :
29 {'help': 'set link duplex',
30 'example' : ['link-duplex full'],
31 'validvals' : ['half', 'full'],
0b762139 32 'default' : 'full'},
f82758bf
RP
33 'link-autoneg' :
34 {'help': 'set autonegotiation',
35 'example' : ['link-autoneg on'],
36 'validvals' : ['on', 'off'],
0b762139 37 'default' : 'varies by platform and port'}}}
f82758bf
RP
38
39 def __init__(self, *args, **kargs):
40 moduleBase.__init__(self, *args, **kargs)
41 self.ipcmd = None
42
0b762139
ST
43 def _post_up(self, ifaceobj, operation='post_up'):
44 """
45 _post_up and _pre_down will reset the layer 2 attributes to default policy
46 settings.
47 """
f82758bf
RP
48 if not self.ipcmd.link_exists(ifaceobj.name):
49 return
50 cmd = ''
0b762139
ST
51 for attr in ['speed', 'duplex', 'autoneg']:
52 # attribute existed before but we must reset to default
53 config_val = ifaceobj.get_attr_value_first('link-%s'%attr)
54 default_val = policymanager.policymanager_api.get_iface_default(
55 module_name='ethtool',
56 ifname=ifaceobj.name,
57 attr='link-%s'%attr)
58
59 # check running values
60 running_val = None
61 if attr == 'autoneg':
62 # we can only get autoneg from ethtool
63 output = self.exec_commandl(['ethtool', ifaceobj.name])
64 running_val = self.get_autoneg(ethtool_output=output)
65 else:
66 running_val = self.read_file_oneline('/sys/class/net/%s/%s' % \
67 (ifaceobj.name, attr))
68 if config_val and config_val == running_val:
69 # running value is what is configured, do nothing
70 continue
71 if not config_val and default_val and default_val == running_val:
72 # nothing configured but the default is running
73 continue
74 # if we got this far, we need to change it
75 if config_val and (config_val != running_val):
76 # if the configured value is not set, set it
77 cmd += ' %s %s' % (attr, config_val)
78 elif default_val and (default_val != running_val):
79 # or if it has a default not equal to running value, set it
80 cmd += ' %s %s' % (attr, default_val)
81 else:
82 # no value set nor default, leave it alone
83 pass
f82758bf 84 if cmd:
0b762139
ST
85 self.logger.debug('ethtool %s: iface %s cmd is %s' % \
86 (operation, ifaceobj.name, cmd))
f82758bf 87 try:
0b762139
ST
88 # we should only be calling ethtool if there
89 # is a speed set or we can find a default speed
90 # because we should only be calling ethtool on swp ports
f82758bf
RP
91 cmd = 'ethtool -s %s %s' %(ifaceobj.name, cmd)
92 self.exec_command(cmd)
93 except Exception, e:
94 ifaceobj.status = ifaceStatus.ERROR
95 self.log_warn('%s: %s' %(ifaceobj.name, str(e)))
0b762139
ST
96 else:
97 pass
98
99 def _pre_down(self, ifaceobj):
100 pass #self._post_up(ifaceobj,operation="_pre_down")
f82758bf
RP
101
102 def _query_check(self, ifaceobj, ifaceobjcurr):
103 """
0b762139
ST
104 _query_check() needs to compare the configured (or running)
105 attribute with the running attribute.
106
107 If there is nothing configured, we compare the default attribute with
108 the running attribute and FAIL if they are different.
109 This is because a reboot will lose their running attribute
110 (the default will get set).
111 """
112 for attr in ['speed', 'duplex', 'autoneg']:
113 # autoneg comes from ethtool whereas speed and duplex from /sys/class
114 if attr == 'autoneg':
115 output = self.exec_commandl(['ethtool', ifaceobj.name])
116 running_attr = self.get_autoneg(ethtool_output=output)
117 else:
118 running_attr = self.read_file_oneline('/sys/class/net/%s/%s' % \
119 (ifaceobj.name, attr))
120
121 configured = ifaceobj.get_attr_value_first('link-%s'%attr)
122 default = policymanager.policymanager_api.get_iface_default(
123 module_name='ethtool',
124 ifname=ifaceobj.name,
125 attr='link-%s'%attr)
126
127 # there is a case where there is no running config or
128 # (there is no default and it is not configured).
129 # In this case, we do nothing (e.g. eth0 has only a
130 # default duplex, lo has nothing)
131 if (not running_attr or (not configured and not default)):
132 continue
133
134 # we make sure we can get a running value first
135 if (running_attr and configured and running_attr == configured):
136 # PASS since running is what is configured
137 ifaceobjcurr.update_config_with_status('link-%s'%attr,
138 running_attr, 0)
139 elif (running_attr and configured and running_attr != configured):
140 # We show a FAIL since it is not the configured or default
141 ifaceobjcurr.update_config_with_status('link-%s'%attr,
142 running_attr, 1)
143 elif (running_attr and default and running_attr == default):
144 # PASS since running is default
145 ifaceobjcurr.update_config_with_status('link-%s'%attr,
146 running_attr, 0)
147 elif (default or configured):
148 # We show a FAIL since it is not the configured or default
149 ifaceobjcurr.update_config_with_status('link-%s'%attr,
150 running_attr, 1)
151 return
152
153 def get_autoneg(self,ethtool_output=None):
154 """
155 get_autoneg simply calls the ethtool command and parses out
156 the autoneg value.
157 """
158 ethtool_attrs = ethtool_output.split()
159 if ('Auto-negotiation:' in ethtool_attrs):
160 return(ethtool_attrs[ethtool_attrs.index('Auto-negotiation:')+1])
161 else:
162 return(None)
163
164 def _query_running(self, ifaceobj, ifaceobj_getfunc=None):
165 """
166 _query_running looks at the speed and duplex from /sys/class
167 and retreives autoneg from ethtool. We do not report autoneg
168 if speed is not available because this usually means the link is
169 down and the autoneg value is not reliable when the link is down.
170 """
171 # do not bother showing swp ifaces that are not up for the speed
172 # duplex and autoneg are not reliable.
173 if not self.ipcmd.is_link_up(ifaceobj.name):
f82758bf 174 return
0b762139
ST
175 for attr in ['speed', 'duplex', 'autoneg']:
176 # autoneg comes from ethtool whereas speed and duplex from /sys/class
177 running_attr = None
178 try:
179 if attr == 'autoneg':
180 output=self.exec_commandl(['ethtool', ifaceobj.name])
181 running_attr = self.get_autoneg(ethtool_output=output)
f82758bf 182 else:
0b762139
ST
183 running_attr = self.read_file_oneline('/sys/class/net/%s/%s' % \
184 (ifaceobj.name, attr))
185 except:
186 # for nonexistent interfaces, we get an error (rc = 256 or 19200)
187 pass
188
189 # show it
190 if (running_attr):
191 ifaceobj.update_config('link-%s'%attr, running_attr)
f82758bf 192
f82758bf
RP
193 return
194
0b762139
ST
195 _run_ops = {'pre-down' : _pre_down,
196 'post-up' : _post_up,
197 'query-checkcurr' : _query_check,
198 'query-running' : _query_running }
f82758bf
RP
199
200 def get_ops(self):
201 """ returns list of ops supported by this module """
202 return self._run_ops.keys()
203
204 def _init_command_handlers(self):
205 if not self.ipcmd:
206 self.ipcmd = iproute2(**self.get_flags())
207
208 def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
209 """ run ethtool configuration on the interface object passed as
210 argument
211
212 Args:
213 **ifaceobj** (object): iface object
214
215 **operation** (str): any of 'post-up', 'query-checkcurr',
216 'query-running'
217 Kwargs:
218 **query_ifaceobj** (object): query check ifaceobject. This is only
219 valid when op is 'query-checkcurr'. It is an object same as
220 ifaceobj, but contains running attribute values and its config
221 status. The modules can use it to return queried running state
222 of interfaces. status is success if the running state is same
223 as user required state in ifaceobj. error otherwise.
224 """
225 op_handler = self._run_ops.get(operation)
226 if not op_handler:
227 return
228 self._init_command_handlers()
0b762139
ST
229
230 # check to make sure we are only checking/setting interfaces with
231 # no lower interfaces. No bridges, no vlans, loopbacks.
232 if ifaceobj.lowerifaces != None or \
233 self.ipcmd.link_isloopback(ifaceobj.name) or \
234 self.ipcmd.is_vlan_device_by_name(ifaceobj.name):
235 return
236
f82758bf
RP
237 if operation == 'query-checkcurr':
238 op_handler(self, ifaceobj, query_ifaceobj)
239 else:
240 op_handler(self, ifaceobj)