]>
git.proxmox.com Git - mirror_ifupdown2.git/blob - addons/ifenslave.py
3 # Copyright 2014 Cumulus Networks, Inc. All rights reserved.
4 # Author: Roopa Prabhu, roopa@cumulusnetworks.com
8 from ifupdown
.iface
import *
10 from ifupdownaddons
.modulebase
import moduleBase
11 from ifupdownaddons
.ifenslaveutil
import ifenslaveutil
12 from ifupdownaddons
.iproute2
import iproute2
14 class ifenslave(moduleBase
):
15 """ ifupdown2 addon module to configure bond interfaces """
16 _modinfo
= { 'mhelp' : 'bond configuration module',
19 {'help' : 'bond use carrier',
20 'validvals' : ['0', '1'],
22 'example': ['bond-use-carrier 1']},
24 {'help' : 'bond use carrier',
25 'validrange' : ['0', '255'],
27 'example' : ['bond-num-grat-arp 1']},
29 {'help' : 'bond slave devices',
30 'validrange' : ['0', '255'],
32 'example' : ['bond-num-unsol-na 1']},
33 'bond-xmit-hash-policy' :
34 {'help' : 'bond slave devices',
35 'validvals' : ['layer2', 'layer3+4', 'layer2+3'],
37 'example' : ['bond-xmit-hash-policy layer2']},
39 {'help' : 'bond miimon',
40 'validrange' : ['0', '255'],
42 'example' : ['bond-miimon 0']},
44 {'help' : 'bond mode',
45 'validvals' : ['balance-rr', 'active-backup',
46 'balance-xor', 'broadcast', '802.3ad',
47 'balance-tlb', 'balance-alb'],
48 'default' : 'balance-rr',
49 'example' : ['bond-mode 802.3ad']},
51 {'help' : 'bond use carrier',
52 'validvals' : ['0', '1'],
54 'example' : ['bond-lacp-rate 0']},
56 {'help' : 'bond min links',
58 'example' : ['bond-min-links 0']},
59 'bond-ad-sys-priority':
60 {'help' : '802.3ad system priority',
62 'example' : ['bond-ad-sys-priority 65535']},
63 'bond-ad-sys-mac-addr':
64 {'help' : '802.3ad system mac address',
65 'default' : '00:00:00:00:00:00',
66 'example' : ['bond-ad-sys-mac-addr 00:00:00:00:00:00']},
67 'bond-lacp-fallback-allow':
68 {'help' : 'allow lacp fall back',
69 'validvals' : ['0', '1'],
71 'example' : ['bond-lacp-fallback-allow 0']},
72 'bond-lacp-fallback-period':
73 {'help' : 'grace period (seconds) for lacp fall back',
74 'validrange' : ['0', '100'],
76 'example' : ['bond-lacp-fallback-period 100']},
77 'bond-lacp-fallback-priority':
78 {'help' : 'slave priority for lacp fall back',
79 'example' : ['bond-lacp-fallback-priority swp1=1 swp2=1 swp3=2']},
81 {'help' : 'bond slaves',
83 'example' : ['bond-slaves swp1 swp2',
84 'bond-slaves glob swp1-2',
85 'bond-slaves regex (swp[1|2)']}}}
87 def __init__(self
, *args
, **kargs
):
88 ifupdownaddons
.modulebase
.moduleBase
.__init
__(self
, *args
, **kargs
)
90 self
.ifenslavecmd
= None
92 def _is_bond(self
, ifaceobj
):
93 if ifaceobj
.get_attr_value_first('bond-slaves'):
97 def get_dependent_ifacenames(self
, ifaceobj
, ifacenames_all
=None):
98 """ Returns list of interfaces dependent on ifaceobj """
100 if not self
._is
_bond
(ifaceobj
):
102 slave_list
= self
.parse_port_list(ifaceobj
.get_attr_value_first(
103 'bond-slaves'), ifacenames_all
)
105 # Also save a copy for future use
106 ifaceobj
.priv_data
= list(slave_list
)
109 def get_dependent_ifacenames_running(self
, ifaceobj
):
110 self
._init
_command
_handlers
()
111 return self
.ifenslavecmd
.get_slaves(ifaceobj
.name
)
113 def _get_slave_list(self
, ifaceobj
):
114 """ Returns slave list present in ifaceobj config """
116 # If priv data already has slave list use that first.
117 if ifaceobj
.priv_data
:
118 return ifaceobj
.priv_data
119 slaves
= ifaceobj
.get_attr_value_first('bond-slaves')
121 return self
.parse_port_list(slaves
)
125 def fetch_attr(self
, ifaceobj
, attrname
):
126 attrval
= ifaceobj
.get_attr_value_first(attrname
)
128 msg
= ('%s: invalid value %s for attr %s.'
129 %(ifaceobj
.name
, attrval
, attrname
))
130 optiondict
= self
.get_mod_attr(attrname
)
133 validvals
= optiondict
.get('validvals')
134 if validvals
and attrval
not in validvals
:
135 raise Exception(msg
+ ' Valid values are %s' %str
(validvals
))
136 validrange
= optiondict
.get('validrange')
138 if (int(attrval
) < int(validrange
[0]) or
139 int(attrval
) > int(validrange
[1])):
140 raise Exception(msg
+ ' Valid range is [%s,%s]'
141 %(validrange
[0], validrange
[1]))
144 def _apply_master_settings(self
, ifaceobj
):
145 have_attrs_to_set
= 0
146 ifenslavecmd_attrmap
= OrderedDict([('bond-mode' , 'mode'),
147 ('bond-miimon' , 'miimon'),
148 ('bond-use-carrier', 'use_carrier'),
149 ('bond-lacp-rate' , 'lacp_rate'),
150 ('bond-xmit-hash-policy' , 'xmit_hash_policy'),
151 ('bond-min-links' , 'min_links'),
152 ('bond-num-grat-arp' , 'num_grat_arp'),
153 ('bond-num-unsol-na' , 'num_unsol_na'),
154 ('bond-ad-sys-mac-addr' , 'ad_sys_mac_addr'),
155 ('bond-ad-sys-priority' , 'ad_sys_priority'),
156 ('bond-lacp-fallback-allow', 'lacp_fallback_allow'),
157 ('bond-lacp-fallback-period', 'lacp_fallback_period')])
158 linkstatus
= self
.ipcmd
.link_get_status(ifaceobj
.name
)
160 # assume link status is 'UP'
163 # order of attributes set matters for bond, so
164 # construct the list sequentially
165 attrstoset
= OrderedDict()
166 for k
, dstk
in ifenslavecmd_attrmap
.items():
167 v
= self
.fetch_attr(ifaceobj
, k
)
172 have_attrs_to_set
= 1
173 self
.ifenslavecmd
.set_attrs(ifaceobj
.name
, attrstoset
,
174 self
.ipcmd
.link_down
if linkstatus
== 'UP' else None)
178 if have_attrs_to_set
and linkstatus
== 'UP':
179 self
.ipcmd
.link_up(ifaceobj
.name
)
181 def _add_slaves(self
, ifaceobj
):
184 slaves
= self
._get
_slave
_list
(ifaceobj
)
186 self
.logger
.debug('%s: no slaves found' %ifaceobj
.name
)
189 if not self
.PERFMODE
:
190 runningslaves
= self
.ifenslavecmd
.get_slaves(ifaceobj
.name
);
192 # Delete active slaves not in the new slave list
193 [ self
.ifenslavecmd
.remove_slave(ifaceobj
.name
, s
)
194 for s
in runningslaves
if s
not in slaves
]
196 for slave
in Set(slaves
).difference(Set(runningslaves
)):
197 if (not self
.PERFMODE
and
198 not self
.ipcmd
.link_exists(slave
)):
199 self
.log_warn('%s: skipping slave %s, does not exist'
200 %(ifaceobj
.name
, slave
))
202 self
.ifenslavecmd
.enslave_slave(ifaceobj
.name
, slave
,
203 prehook
=self
.ipcmd
.link_down
,
204 posthook
=self
.ipcmd
.link_up
)
206 def _apply_slaves_lacp_fallback_prio(self
, ifaceobj
):
207 slaves
= self
.ifenslavecmd
.get_slaves(ifaceobj
.name
)
208 attrval
= ifaceobj
.get_attr_value_first('bond-lacp-fallback-priority')
210 portlist
= self
.parse_port_list(attrval
)
212 self
.log_warn('%s: could not parse \'%s %s\''
213 %(ifaceobj
.name
, attrname
, attrval
))
218 (port
, val
) = p
.split('=')
219 if port
not in slaves
:
220 self
.log_warn('%s: skipping slave %s, does not exist'
221 %(ifaceobj
.name
, port
))
224 self
.ifenslavecmd
.set_lacp_fallback_priority(ifaceobj
.name
, port
, val
)
226 self
.log_warn('%s: failed to set lacp_fallback_priority %s (%s)'
227 %(ifaceobj
.name
, port
, str(e
)))
231 self
.ifenslavecmd
.set_lacp_fallback_priority(ifaceobj
.name
, p
, '0')
233 self
.log_warn('%s: failed to clear lacp_fallback_priority %s (%s)'
234 %(ifaceobj
.name
, p
, str(e
)))
237 def _up(self
, ifaceobj
):
239 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
240 self
.ifenslavecmd
.create_bond(ifaceobj
.name
)
241 self
._apply
_master
_settings
(ifaceobj
)
242 self
._add
_slaves
(ifaceobj
)
243 self
._apply
_slaves
_lacp
_fallback
_prio
(ifaceobj
)
245 self
.log_error(str(e
))
247 def _down(self
, ifaceobj
):
249 self
.ifenslavecmd
.delete_bond(ifaceobj
.name
)
251 self
.log_warn(str(e
))
253 def _query_check(self
, ifaceobj
, ifaceobjcurr
):
256 if not self
.ifenslavecmd
.bond_exists(ifaceobj
.name
):
257 self
.logger
.debug('bond iface %s' %ifaceobj
.name
+
259 ifaceobjcurr
.status
= ifaceStatus
.NOTFOUND
262 ifaceattrs
= self
.dict_key_subset(ifaceobj
.config
,
263 self
.get_mod_attrs())
264 if not ifaceattrs
: return
265 runningattrs
= self
._query
_running
_attrs
(ifaceobj
.name
)
267 v
= ifaceobj
.get_attr_value_first(k
)
270 if k
== 'bond-slaves':
273 rv
= runningattrs
.get(k
)
275 ifaceobjcurr
.update_config_with_status(k
, 'None', 1)
277 if k
== 'bond-lacp-fallback-priority':
280 prio_str
= ' '.join(prios
)
281 ifaceobjcurr
.update_config_with_status(k
, rv
,
282 1 if prio_str
!= rv
else 0)
285 ifaceobjcurr
.update_config_with_status(k
, rv
,
287 runningslaves
= runningattrs
.get('bond-slaves')
288 if not slaves
and not runningslaves
:
291 if slaves
and runningslaves
:
292 if slaves
and runningslaves
:
293 difference
= set(slaves
).symmetric_difference(runningslaves
)
296 ifaceobjcurr
.update_config_with_status('bond-slaves',
297 ' '.join(runningslaves
)
298 if runningslaves
else 'None', retslave
)
300 def _query_running_attrs(self
, bondname
):
301 bondattrs
= {'bond-mode' :
302 self
.ifenslavecmd
.get_mode(bondname
),
304 self
.ifenslavecmd
.get_miimon(bondname
),
306 self
.ifenslavecmd
.get_use_carrier(bondname
),
308 self
.ifenslavecmd
.get_lacp_rate(bondname
),
310 self
.ifenslavecmd
.get_min_links(bondname
),
311 'bond-ad-sys-mac-addr' :
312 self
.ifenslavecmd
.get_ad_sys_mac_addr(bondname
),
313 'bond-ad-sys-priority' :
314 self
.ifenslavecmd
.get_ad_sys_priority(bondname
),
315 'bond-xmit-hash-policy' :
316 self
.ifenslavecmd
.get_xmit_hash_policy(bondname
),
317 'bond-lacp-fallback-allow' :
318 self
.ifenslavecmd
.get_lacp_fallback_allow(bondname
),
319 'bond-lacp-fallback-period' :
320 self
.ifenslavecmd
.get_lacp_fallback_period(bondname
),
321 'bond-lacp-fallback-priority' :
322 self
.ifenslavecmd
.get_lacp_fallback_priority(bondname
)}
323 slaves
= self
.ifenslavecmd
.get_slaves(bondname
)
325 bondattrs
['bond-slaves'] = slaves
328 def _query_running(self
, ifaceobjrunning
):
329 if not self
.ifenslavecmd
.bond_exists(ifaceobjrunning
.name
):
331 bondattrs
= self
._query
_running
_attrs
(ifaceobjrunning
.name
)
332 if bondattrs
.get('bond-slaves'):
333 bondattrs
['bond-slaves'] = ' '.join(bondattrs
.get('bond-slaves'))
334 [ifaceobjrunning
.update_config(k
, v
)
335 for k
, v
in bondattrs
.items()
336 if v
and v
!= self
.get_mod_subattr(k
, 'default')]
338 _run_ops
= {'pre-up' : _up
,
340 'query-running' : _query_running
,
341 'query-checkcurr' : _query_check
}
344 """ returns list of ops supported by this module """
345 return self
._run
_ops
.keys()
347 def _init_command_handlers(self
):
348 flags
= self
.get_flags()
350 self
.ipcmd
= iproute2(**flags
)
351 if not self
.ifenslavecmd
:
352 self
.ifenslavecmd
= ifenslaveutil(**flags
)
354 def run(self
, ifaceobj
, operation
, query_ifaceobj
=None):
355 """ run bond configuration on the interface object passed as argument
358 **ifaceobj** (object): iface object
360 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
364 **query_ifaceobj** (object): query check ifaceobject. This is only
365 valid when op is 'query-checkcurr'. It is an object same as
366 ifaceobj, but contains running attribute values and its config
367 status. The modules can use it to return queried running state
368 of interfaces. status is success if the running state is same
369 as user required state in ifaceobj. error otherwise.
371 op_handler
= self
._run
_ops
.get(operation
)
374 if operation
!= 'query-running' and not self
._is
_bond
(ifaceobj
):
376 self
._init
_command
_handlers
()
377 if operation
== 'query-checkcurr':
378 op_handler(self
, ifaceobj
, query_ifaceobj
)
380 op_handler(self
, ifaceobj
)