3 # Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
5 # Roopa Prabhu, roopa@cumulusnetworks.com
6 # Julien Fortin, julien@cumulusnetworks.com
14 from ifupdown2
.lib
.addon
import Addon
15 from ifupdown2
.nlmanager
.nlmanager
import Link
17 from ifupdown2
.ifupdown
.iface
import *
18 from ifupdown2
.ifupdown
.utils
import utils
19 from ifupdown2
.ifupdown
.statemanager
import statemanager_api
as statemanager
21 import ifupdown2
.ifupdown
.policymanager
as policymanager
22 import ifupdown2
.ifupdown
.ifupdownflags
as ifupdownflags
24 from ifupdown2
.ifupdownaddons
.modulebase
import moduleBase
26 from lib
.addon
import Addon
27 from nlmanager
.nlmanager
import Link
29 from ifupdown
.iface
import *
30 from ifupdown
.utils
import utils
31 from ifupdown
.statemanager
import statemanager_api
as statemanager
33 from ifupdownaddons
.modulebase
import moduleBase
35 import ifupdown
.policymanager
as policymanager
36 import ifupdown
.ifupdownflags
as ifupdownflags
38 class bond(Addon
, moduleBase
):
39 """ ifupdown2 addon module to configure bond interfaces """
41 overrides_ifupdown_scripts
= ['ifenslave', ]
44 "mhelp": "bond configuration module",
47 "help": "bond use carrier",
48 "validvals": ["yes", "no", "0", "1"],
50 "example": ["bond-use-carrier yes"]},
51 "bond-num-grat-arp": {
52 "help": "bond use carrier",
53 "validrange": ["0", "255"],
55 "example": ["bond-num-grat-arp 1"]
57 "bond-num-unsol-na": {
58 "help": "bond slave devices",
59 "validrange": ["0", "255"],
61 "example": ["bond-num-unsol-na 1"]
63 "bond-xmit-hash-policy": {
64 "help": "bond slave devices",
73 "example": ["bond-xmit-hash-policy layer2"]
76 "help": "bond miimon",
77 "validrange": ["0", "255"],
79 "example": ["bond-miimon 0"]
92 "default": "balance-rr",
93 "example": ["bond-mode 802.3ad"]
96 "help": "bond lacp rate",
97 "validvals": ["0", "slow", "1", "fast"],
99 "example": ["bond-lacp-rate 0"]
102 "help": "bond min links",
104 "validrange": ["0", "255"],
105 "example": ["bond-min-links 0"]
107 "bond-ad-sys-priority": {
108 "help": "802.3ad system priority",
110 "validrange": ["0", "65535"],
111 "example": ["bond-ad-sys-priority 65535"],
113 "new-attribute": "bond-ad-actor-sys-prio"
115 "bond-ad-actor-sys-prio": {
116 "help": "802.3ad system priority",
118 "validrange": ["0", "65535"],
119 "example": ["bond-ad-actor-sys-prio 65535"]
121 "bond-ad-sys-mac-addr": {
122 "help": "802.3ad system mac address",
123 "validvals": ["<mac>", ],
124 "example": ["bond-ad-sys-mac-addr 00:00:00:00:00:00"],
126 "new-attribute": "bond-ad-actor-system"
128 "bond-ad-actor-system": {
129 "help": "802.3ad system mac address",
130 "validvals": ["<mac>", ],
131 "example": ["bond-ad-actor-system 00:00:00:00:00:00"],
133 "bond-lacp-bypass-allow": {
134 "help": "allow lacp bypass",
135 "validvals": ["yes", "no", "0", "1"],
137 "example": ["bond-lacp-bypass-allow no"]
140 "help": "bond slaves",
143 "validvals": ["<interface-list>"],
145 "bond-slaves swp1 swp2",
146 "bond-slaves glob swp1-2",
147 "bond-slaves regex (swp[1|2)"
149 "aliases": ["bond-ports"]
152 "help": "bond updelay",
154 "validrange": ["0", "65535"],
155 "example": ["bond-updelay 100"]
158 "help": "bond downdelay",
160 "validrange": ["0", "65535"],
161 "example": ["bond-downdelay 100"]
164 "help": "Control which slave interface is "
165 "preferred active member",
166 "example": ["bond-primary swp1"]
171 _bond_attr_netlink_map
= {
172 'bond-mode': Link
.IFLA_BOND_MODE
,
173 'bond-miimon': Link
.IFLA_BOND_MIIMON
,
174 'bond-use-carrier': Link
.IFLA_BOND_USE_CARRIER
,
175 'bond-lacp-rate': Link
.IFLA_BOND_AD_LACP_RATE
,
176 'bond-xmit-hash-policy': Link
.IFLA_BOND_XMIT_HASH_POLICY
,
177 'bond-min-links': Link
.IFLA_BOND_MIN_LINKS
,
178 'bond-num-grat-arp': Link
.IFLA_BOND_NUM_PEER_NOTIF
,
179 'bond-num-unsol-na': Link
.IFLA_BOND_NUM_PEER_NOTIF
,
180 'bond-ad-sys-mac-addr': Link
.IFLA_BOND_AD_ACTOR_SYSTEM
,
181 'bond-ad-actor-system': Link
.IFLA_BOND_AD_ACTOR_SYSTEM
,
182 'bond-ad-sys-priority': Link
.IFLA_BOND_AD_ACTOR_SYS_PRIO
,
183 'bond-ad-actor-sys-prio': Link
.IFLA_BOND_AD_ACTOR_SYS_PRIO
,
184 'bond-lacp-bypass-allow': Link
.IFLA_BOND_AD_LACP_BYPASS
,
185 'bond-updelay': Link
.IFLA_BOND_UPDELAY
,
186 'bond-downdelay': Link
.IFLA_BOND_DOWNDELAY
,
187 'bond-primary': Link
.IFLA_BOND_PRIMARY
190 # ifquery-check attr dictionary with callable object to translate user data to netlink format
191 _bond_attr_ifquery_check_translate_func
= {
192 Link
.IFLA_BOND_MODE
: lambda x
: Link
.ifla_bond_mode_tbl
[x
],
193 Link
.IFLA_BOND_MIIMON
: int,
194 Link
.IFLA_BOND_USE_CARRIER
: utils
.get_boolean_from_string
,
195 Link
.IFLA_BOND_AD_LACP_RATE
: lambda x
: int(utils
.get_boolean_from_string(x
)),
196 Link
.IFLA_BOND_XMIT_HASH_POLICY
: lambda x
: Link
.ifla_bond_xmit_hash_policy_tbl
[x
],
197 Link
.IFLA_BOND_MIN_LINKS
: int,
198 Link
.IFLA_BOND_NUM_PEER_NOTIF
: int,
199 Link
.IFLA_BOND_AD_ACTOR_SYSTEM
: str,
200 Link
.IFLA_BOND_AD_ACTOR_SYS_PRIO
: int,
201 Link
.IFLA_BOND_AD_LACP_BYPASS
: lambda x
: int(utils
.get_boolean_from_string(x
)),
202 Link
.IFLA_BOND_UPDELAY
: int,
203 Link
.IFLA_BOND_DOWNDELAY
: int,
204 # Link.IFLA_BOND_PRIMARY: self.netlink.get_ifname is added in __init__()
207 # ifup attr list with callable object to translate user data to netlink format
208 # in the future this can be moved to a dictionary, whenever we detect that some
209 # netlink capabilities are missing we can dynamically remove them from the dict.
210 _bond_attr_set_list
= (
211 ('bond-mode', Link
.IFLA_BOND_MODE
, lambda x
: Link
.ifla_bond_mode_tbl
[x
]),
212 ('bond-xmit-hash-policy', Link
.IFLA_BOND_XMIT_HASH_POLICY
, lambda x
: Link
.ifla_bond_xmit_hash_policy_tbl
[x
]),
213 ('bond-miimon', Link
.IFLA_BOND_MIIMON
, int),
214 ('bond-min-links', Link
.IFLA_BOND_MIN_LINKS
, int),
215 ('bond-num-grat-arp', Link
.IFLA_BOND_NUM_PEER_NOTIF
, int),
216 ('bond-num-unsol-na', Link
.IFLA_BOND_NUM_PEER_NOTIF
, int),
217 ('bond-ad-sys-priority', Link
.IFLA_BOND_AD_ACTOR_SYS_PRIO
, int),
218 ('bond-ad-actor-sys-prio', Link
.IFLA_BOND_AD_ACTOR_SYS_PRIO
, int),
219 ('bond-updelay', Link
.IFLA_BOND_UPDELAY
, int),
220 ('bond-downdelay', Link
.IFLA_BOND_DOWNDELAY
, int),
221 ('bond-use-carrier', Link
.IFLA_BOND_USE_CARRIER
, lambda x
: int(utils
.get_boolean_from_string(x
))),
222 ('bond-lacp-rate', Link
.IFLA_BOND_AD_LACP_RATE
, lambda x
: int(utils
.get_boolean_from_string(x
))),
223 ('bond-lacp-bypass-allow', Link
.IFLA_BOND_AD_LACP_BYPASS
, lambda x
: int(utils
.get_boolean_from_string(x
))),
224 ('bond-ad-sys-mac-addr', Link
.IFLA_BOND_AD_ACTOR_SYSTEM
, str),
225 ('bond-ad-actor-system', Link
.IFLA_BOND_AD_ACTOR_SYSTEM
, str)
226 # ('bond-primary', Link.IFLA_BOND_PRIMARY, self.cache.get_ifindex) added in __init__()
229 def __init__(self
, *args
, **kargs
):
231 moduleBase
.__init
__(self
, *args
, **kargs
)
233 if not os
.path
.exists('/sys/class/net/bonding_masters'):
235 utils
.exec_command('modprobe -q bonding')
236 except Exception as e
:
237 self
.logger
.info("bond: error while loading bonding module: %s" % str(e
))
239 self
._bond
_attr
_ifquery
_check
_translate
_func
[Link
.IFLA_BOND_PRIMARY
] = self
.cache
.get_ifindex
240 self
._bond
_attr
_set
_list
= self
._bond
_attr
_set
_list
+ (('bond-primary', Link
.IFLA_BOND_PRIMARY
, self
.cache
.get_ifindex
),)
243 def get_bond_slaves(ifaceobj
):
244 slaves
= ifaceobj
.get_attr_value_first('bond-slaves')
246 slaves
= ifaceobj
.get_attr_value_first('bond-ports')
249 def _is_bond(self
, ifaceobj
):
250 # at first link_kind is not set but once ifupdownmain
251 # calls get_dependent_ifacenames link_kind is set to BOND
252 return ifaceobj
.link_kind
& ifaceLinkKind
.BOND
or self
.get_bond_slaves(ifaceobj
)
254 def get_dependent_ifacenames(self
, ifaceobj
, ifacenames_all
=None):
255 """ Returns list of interfaces dependent on ifaceobj """
257 if not self
._is
_bond
(ifaceobj
):
259 slave_list
= self
.parse_port_list(ifaceobj
.name
,
260 self
.get_bond_slaves(ifaceobj
),
262 ifaceobj
.dependency_type
= ifaceDependencyType
.MASTER_SLAVE
263 # Also save a copy for future use
264 ifaceobj
.priv_data
= list(slave_list
)
265 if ifaceobj
.link_type
!= ifaceLinkType
.LINK_NA
:
266 ifaceobj
.link_type
= ifaceLinkType
.LINK_MASTER
267 ifaceobj
.link_kind |
= ifaceLinkKind
.BOND
268 ifaceobj
.role |
= ifaceRole
.MASTER
272 def syntax_check(self
, ifaceobj
, ifaceobj_getfunc
):
273 return self
.syntax_check_updown_delay(ifaceobj
)
275 def get_dependent_ifacenames_running(self
, ifaceobj
):
276 return self
.cache
.get_slaves(ifaceobj
.name
)
278 def _get_slave_list(self
, ifaceobj
):
279 """ Returns slave list present in ifaceobj config """
281 # If priv data already has slave list use that first.
282 if ifaceobj
.priv_data
:
283 return ifaceobj
.priv_data
284 slaves
= self
.get_bond_slaves(ifaceobj
)
286 return self
.parse_port_list(ifaceobj
.name
, slaves
)
290 def enable_ipv6_if_prev_brport(self
, ifname
):
292 If the intf was previously enslaved to a bridge it is possible ipv6 is still disabled.
295 for ifaceobj
in statemanager
.get_ifaceobjs(ifname
) or []:
296 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
:
297 self
.write_file("/proc/sys/net/ipv6/conf/%s/disable_ipv6" % ifname
, "0")
300 self
.logger
.info(str(e
))
302 def _is_clag_bond(self
, ifaceobj
):
303 if self
.get_bond_slaves(ifaceobj
):
304 attrval
= ifaceobj
.get_attr_value_first('clag-id')
305 if attrval
and attrval
!= '0':
309 def _add_slaves(self
, ifaceobj
, runningslaves
, ifaceobj_getfunc
=None):
310 slaves
= self
._get
_slave
_list
(ifaceobj
)
312 self
.logger
.debug('%s: no slaves found' %ifaceobj
.name
)
315 clag_bond
= self
._is
_clag
_bond
(ifaceobj
)
317 for slave
in Set(slaves
).difference(Set(runningslaves
)):
318 if (not ifupdownflags
.flags
.PERFMODE
and
319 not self
.cache
.link_exists(slave
)):
320 self
.log_error('%s: skipping slave %s, does not exist'
321 %(ifaceobj
.name
, slave
), ifaceobj
,
325 if self
.cache
.link_is_up(slave
):
326 self
.netlink
.link_down_force(slave
)
328 # If clag bond place the slave in a protodown state; clagd
329 # will protoup it when it is ready
332 self
.netlink
.link_set_protodown_on(slave
)
334 self
.logger
.error('%s: %s' % (ifaceobj
.name
, str(e
)))
336 self
.enable_ipv6_if_prev_brport(slave
)
337 self
.netlink
.link_set_master(slave
, ifaceobj
.name
)
338 # TODO: if this fail we should switch to iproute2
339 # start a batch: down - set master - up
340 if link_up
or ifaceobj
.link_type
!= ifaceLinkType
.LINK_NA
:
342 if (ifaceobj_getfunc(slave
)[0].link_privflags
&
343 ifaceLinkPrivFlags
.KEEP_LINK_DOWN
):
344 self
.netlink
.link_down_force(slave
)
346 self
.netlink
.link_up(slave
)
348 self
.logger
.debug('%s: %s' % (ifaceobj
.name
, str(e
)))
352 for s
in runningslaves
:
354 self
.sysfs
.bond_remove_slave(ifaceobj
.name
, s
)
357 self
.netlink
.link_set_protodown_off(s
)
359 self
.logger
.error('%s: %s' % (ifaceobj
.name
, str(e
)))
361 # apply link-down config changes on running slaves
363 link_up
= self
.cache
.link_is_up(s
)
364 config_link_down
= (ifaceobj_getfunc(s
)[0].link_privflags
&
365 ifaceLinkPrivFlags
.KEEP_LINK_DOWN
)
366 if (config_link_down
and link_up
):
367 self
.netlink
.link_down_force(s
)
368 elif (not config_link_down
and not link_up
):
369 self
.netlink
.link_up_force(s
)
371 self
.logger
.warn('%s: %s' % (ifaceobj
.name
, str(e
)))
373 def _check_updown_delay_log(self
, ifaceobj
, attr_name
, value
):
374 ifaceobj
.status
= ifaceStatus
.ERROR
375 self
.logger
.error('%s: unable to set %s %s as MII link monitoring is '
376 'disabled' % (ifaceobj
.name
, attr_name
, value
))
377 # return False to notify syntax_check that an error has been logged
380 def syntax_check_updown_delay(self
, ifaceobj
):
382 updelay
= ifaceobj
.get_attr_value_first('bond-updelay')
383 downdelay
= ifaceobj
.get_attr_value_first('bond-downdelay')
385 if not updelay
and not downdelay
:
389 miimon
= int(ifaceobj
.get_attr_value_first('bond-miimon'))
392 miimon
= int(policymanager
.policymanager_api
.get_iface_default(
393 module_name
=self
.__class
__.__name
__,
394 ifname
=ifaceobj
.name
,
400 # self._check_updown_delay_log returns False no matter what
401 if updelay
and int(updelay
):
402 result
= self
._check
_updown
_delay
_log
(ifaceobj
, 'bond-updelay', updelay
)
403 if downdelay
and int(downdelay
):
404 result
= self
._check
_updown
_delay
_log
(ifaceobj
, 'bond-downdelay', downdelay
)
408 _bond_updown_delay_nl_list
= (
409 (Link
.IFLA_BOND_UPDELAY
, 'bond-updelay'),
410 (Link
.IFLA_BOND_DOWNDELAY
, 'bond-downdelay')
413 def check_updown_delay_nl(self
, link_exists
, ifaceobj
, ifla_info_data
):
416 Specifies the time, in milliseconds, to wait before enabling a slave
417 after a link recovery has been detected. This option is only valid
418 for the miimon link monitor. The updelay value should be a multiple
419 of the miimon value; if not, it will be rounded down to the nearest
420 multiple. The default value is 0.
422 This ifla_bond_miimon code should be move to get_ifla_bond_attr_from_user_config
423 but we need to know if the operation was successful to update the cache accordingly
425 ifla_bond_miimon
= ifla_info_data
.get(Link
.IFLA_BOND_MIIMON
)
426 if link_exists
and ifla_bond_miimon
is None:
427 ifla_bond_miimon
= self
.cache
.get_link_info_data_attribute(ifaceobj
.name
, Link
.IFLA_BOND_MIIMON
)
429 if ifla_bond_miimon
== 0:
430 for nl_attr
, attr_name
in self
._bond
_updown
_delay
_nl
_list
:
431 delay
= ifla_info_data
.get(nl_attr
)
432 # if up-down-delay exists we need to remove it, if non zero log error
433 if delay
is not None:
435 self
._check
_updown
_delay
_log
(ifaceobj
, attr_name
, delay
)
436 del ifla_info_data
[nl_attr
]
441 (Link
.IFLA_BOND_AD_LACP_RATE
, 'bond-lacp-rate'),
442 (Link
.IFLA_BOND_AD_LACP_BYPASS
, 'bond-lacp-bypass')
445 def _check_bond_mode_user_config(self
, ifname
, link_exists
, ifla_info_data
):
446 ifla_bond_mode
= ifla_info_data
.get(Link
.IFLA_BOND_MODE
)
447 if ifla_bond_mode
is None and link_exists
:
448 ifla_bond_mode
= self
.cache
.get_link_info_data_attribute(ifname
, Link
.IFLA_BOND_MODE
)
449 # in this case the link already exists (we have a cached value):
450 # if IFLA_BOND_MODE is not present in ifla_info_data it means:
451 # - that bond-mode was present in the user config and didn't change
452 # - never was in the user config so bond mode should be the system default value
453 # - was removed from the stanza so we might have to reset it to default value
454 # nevertheless we need to add it back to the ifla_info_data dict to check
455 # if we need to reset the mode to system default
456 ifla_info_data
[Link
.IFLA_BOND_MODE
] = ifla_bond_mode
458 if ifla_bond_mode
== 4: # 802.3ad
459 min_links
= ifla_info_data
.get(Link
.IFLA_BOND_MIN_LINKS
)
460 if min_links
is None:
461 min_links
= self
.cache
.get_link_info_data_attribute(ifname
, Link
.IFLA_BOND_MIN_LINKS
)
462 # get_min_links_nl may return None so we need to strictly check 0
464 self
.logger
.warn('%s: attribute bond-min-links is set to \'0\'' % ifname
)
466 # IFLA_BOND_AD_LACP_RATE and IFLA_BOND_AD_LACP_BYPASS only for 802.3ad mode (4)
467 for nl_attr
, attr_name
in self
._bond
_lacp
_attrs
:
468 if nl_attr
in ifla_info_data
:
469 self
.logger
.info('%s: ignoring %s: only available for 802.3ad mode (4)' % (ifname
, attr_name
))
470 del ifla_info_data
[nl_attr
]
473 def get_saved_ifaceobj(link_exists
, ifname
):
475 old_config
= statemanager
.get_ifaceobjs(ifname
)
480 def get_ifla_bond_attr_from_user_config(self
, ifaceobj
, link_exists
):
482 Potential issue: if a user load the bond driver with custom
483 default values (say bond-mode 3), ifupdown2 has no knowledge
484 of these default values.
485 At bond creation everything should work, bonds will be created
486 with mode 3 (even if not specified under the stanza).
487 But, for example: if the user specifies a value under bond-mode
488 and later on the user removes the bond-mode line from the stanza
489 we will detect it and reset to MODINFO: BOND-MODE: DEFAULT aka 0
490 which is not the real default value that the user may expect.
492 ifname
= ifaceobj
.name
493 ifla_info_data
= OrderedDict()
494 old_config
= self
.get_saved_ifaceobj(link_exists
, ifname
)
496 # for each bond attribute we fetch the user configuration
497 # if no configuration is provided we look for a config in policy files
498 for attr_name
, netlink_attr
, func_ptr
in self
._bond
_attr
_set
_list
:
500 user_config
= ifaceobj
.get_attr_value_first(attr_name
)
503 user_config
= policymanager
.policymanager_api
.get_iface_default(
504 module_name
=self
.__class
__.__name
__,
508 self
.logger
.debug('%s: %s %s: extracted from policy files'
509 % (ifname
, attr_name
, user_config
))
511 # no policy override, do we need to reset an attr to default value?
512 if not user_config
and old_config
and old_config
.get_attr_value_first(attr_name
):
513 # if the link already exists but the value is set
514 # (potentially removed from the stanza, we need to reset it to default)
515 # might not work for specific cases, see explanation at the top of this function :)
516 user_config
= self
.get_attr_default_value(attr_name
)
518 self
.logger
.debug('%s: %s: removed from stanza, resetting to default value: %s'
519 % (ifname
, attr_name
, user_config
))
523 nl_value
= func_ptr(user_config
.lower())
526 cached_value
= self
.cache
.get_link_info_data_attribute(ifname
, netlink_attr
)
528 if link_exists
and cached_value
is None:
529 # the link already exists but we don't have any value
530 # cached for this attr, it probably means that the
531 # capability is not available on this system (i.e old kernel)
532 self
.logger
.debug('%s: ignoring %s %s: capability '
533 'probably not supported on this system'
534 % (ifname
, attr_name
, user_config
))
537 # there should be a cached value if the link already exists
538 if cached_value
== nl_value
:
539 # if the user value is already cached: continue
542 # else: the link doesn't exist so we create the bond with
543 # all the user/policy defined values without extra checks
544 ifla_info_data
[netlink_attr
] = nl_value
546 if cached_value
is not None:
547 self
.logger
.info('%s: set %s %s (cache %s)' % (ifname
, attr_name
, user_config
, cached_value
))
549 self
.logger
.info('%s: set %s %s' % (ifname
, attr_name
, user_config
))
552 self
.logger
.warning('%s: invalid %s value %s' % (ifname
, attr_name
, user_config
))
554 self
._check
_bond
_mode
_user
_config
(ifname
, link_exists
, ifla_info_data
)
555 return ifla_info_data
557 _bond_down_nl_attributes_list
= (
559 Link
.IFLA_BOND_XMIT_HASH_POLICY
,
560 Link
.IFLA_BOND_AD_LACP_RATE
,
561 Link
.IFLA_BOND_MIN_LINKS
564 def _should_down_bond(self
, ifla_info_data
):
565 for nl_attr
in self
._bond
_down
_nl
_attributes
_list
:
566 if nl_attr
in ifla_info_data
:
570 def should_update_bond_mode(self
, ifaceobj
, ifname
, is_link_up
, ifla_info_data
, bond_slaves
):
571 # if bond-mode was changed the bond needs to be brought
572 # down and slaves un-slaved before bond mode is changed.
573 cached_bond_mode
= self
.cache
.get_link_info_data_attribute(ifname
, Link
.IFLA_BOND_MODE
)
574 ifla_bond_mode
= ifla_info_data
.get(Link
.IFLA_BOND_MODE
)
576 # bond-mode was changed or is not specified
577 if ifla_bond_mode
is not None:
578 if ifla_bond_mode
!= cached_bond_mode
:
579 self
.logger
.info('%s: bond mode changed to %s: running ops on bond and slaves'
580 % (ifname
, ifla_bond_mode
))
582 self
.netlink
.link_down(ifname
)
585 for lower_dev
in ifaceobj
.lowerifaces
:
586 self
.netlink
.link_set_nomaster(lower_dev
)
588 bond_slaves
.remove(lower_dev
)
593 # bond-mode user config value is the current running(cached) value
594 # no need to reset it again we can ignore this attribute
595 del ifla_info_data
[Link
.IFLA_BOND_MODE
]
597 return is_link_up
, bond_slaves
599 def create_or_set_bond_config(self
, ifaceobj
):
600 ifname
= ifaceobj
.name
601 link_exists
, is_link_up
= self
.cache
.link_exists_and_up(ifname
)
602 ifla_info_data
= self
.get_ifla_bond_attr_from_user_config(ifaceobj
, link_exists
)
604 remove_delay_from_cache
= self
.check_updown_delay_nl(link_exists
, ifaceobj
, ifla_info_data
)
606 # if link exists: down link if specific attributes are specified
608 # did bond-mode changed?
609 is_link_up
, bond_slaves
= self
.should_update_bond_mode(
614 self
.cache
.get_slaves(ifname
)
617 # if specific attributes need to be set we need to down the bond first
618 if ifla_info_data
and is_link_up
:
619 if self
._should
_down
_bond
(ifla_info_data
):
620 self
.netlink
.link_down_force(ifname
)
625 if link_exists
and not ifla_info_data
:
626 # if the bond already exists and no attrs need to be set
627 # ignore the netlink call
628 self
.logger
.info('%s: already exists, no change detected' % ifname
)
631 self
.netlink
.link_add_bond_with_info_data(ifname
, ifla_info_data
)
632 except Exception as e
:
634 # if anything happens, we try to set up the bond with the sysfs api
635 self
.logger
.debug('%s: bond setup: %s' % (ifname
, str(e
)))
636 self
.create_or_set_bond_config_sysfs(ifaceobj
, ifla_info_data
)
638 if remove_delay_from_cache
:
639 # making sure up/down delay attributes are set to 0 before caching
640 # this can be removed when moving to a nllistener/live cache
641 ifla_info_data
[Link
.IFLA_BOND_UPDELAY
] = 0
642 ifla_info_data
[Link
.IFLA_BOND_DOWNDELAY
] = 0
644 if link_exists
and ifla_info_data
and not is_link_up
:
645 self
.netlink
.link_up_force(ifname
)
649 def create_or_set_bond_config_sysfs(self
, ifaceobj
, ifla_info_data
):
650 if not self
.cache
.link_exists(ifaceobj
.name
):
651 self
.sysfs
.bond_create(ifaceobj
.name
)
652 self
.sysfs
.bond_set_attrs_nl(ifaceobj
.name
, ifla_info_data
)
654 def _up(self
, ifaceobj
, ifaceobj_getfunc
=None):
656 bond_slaves
= self
.create_or_set_bond_config(ifaceobj
)
663 self
.log_error(str(e
), ifaceobj
)
665 def _down(self
, ifaceobj
, ifaceobj_getfunc
=None):
667 self
.netlink
.link_del(ifaceobj
.name
)
668 except Exception as e
:
669 self
.log_warn('%s: %s' % (ifaceobj
.name
, str(e
)))
671 def _query_check_bond_slaves(self
, ifaceobjcurr
, attr
, user_bond_slaves
, running_bond_slaves
):
674 if user_bond_slaves
and running_bond_slaves
:
675 if not set(user_bond_slaves
).symmetric_difference(running_bond_slaves
):
678 # we want to display the same bond-slaves list as provided
679 # in the interfaces file but if this list contains regexes or
680 # globs, for now, we won't try to change it.
681 if 'regex' in user_bond_slaves
or 'glob' in user_bond_slaves
:
682 user_bond_slaves
= running_bond_slaves
685 for slave
in user_bond_slaves
:
686 if slave
in running_bond_slaves
:
687 ordered
.append(slave
)
688 user_bond_slaves
= ordered
689 ifaceobjcurr
.update_config_with_status(attr
, ' '.join(user_bond_slaves
) if user_bond_slaves
else 'None', query
)
691 def _query_check(self
, ifaceobj
, ifaceobjcurr
, ifaceobj_getfunc
=None):
692 if not self
.cache
.bond_exists(ifaceobj
.name
):
693 self
.logger
.debug('bond iface %s does not exist' % ifaceobj
.name
)
696 iface_attrs
= self
.dict_key_subset(ifaceobj
.config
, self
.get_mod_attrs())
700 # remove bond-slaves and bond-ports from the list,
701 # because there aren't any ifla_info_data netlink attr for slaves
702 # an exception is raised when index is not found, so query_slaves will stay False
705 user_bond_slaves
= None
706 running_bond_slaves
= None
708 del iface_attrs
[iface_attrs
.index('bond-slaves')]
710 # if user specified bond-slaves we need to display it
712 if not user_bond_slaves
:
713 user_bond_slaves
= self
._get
_slave
_list
(ifaceobj
)
714 running_bond_slaves
= self
.cache
.get_slaves(ifaceobj
.name
)
716 self
._query
_check
_bond
_slaves
(ifaceobjcurr
, 'bond-slaves', user_bond_slaves
, running_bond_slaves
)
720 del iface_attrs
[iface_attrs
.index('bond-ports')]
722 # if user specified bond-ports we need to display it
723 if not query_slaves
and not user_bond_slaves
: # if get_slave_list was already called for slaves
724 user_bond_slaves
= self
._get
_slave
_list
(ifaceobj
)
725 running_bond_slaves
= self
.cache
.get_slaves(ifaceobj
.name
)
727 self
._query
_check
_bond
_slaves
(ifaceobjcurr
, 'bond-ports', user_bond_slaves
, running_bond_slaves
)
731 for attr
in iface_attrs
:
732 nl_attr
= self
._bond
_attr
_netlink
_map
[attr
]
733 translate_func
= self
._bond
_attr
_ifquery
_check
_translate
_func
[nl_attr
]
734 current_config
= self
.cache
.get_link_info_data_attribute(ifaceobj
.name
, nl_attr
)
735 user_config
= ifaceobj
.get_attr_value_first(attr
)
737 if current_config
== translate_func(user_config
):
738 ifaceobjcurr
.update_config_with_status(attr
, user_config
, 0)
740 ifaceobjcurr
.update_config_with_status(attr
, str(current_config
), 1)
743 def translate_nl_value_yesno(value
):
744 return 'yes' if value
else 'no'
747 def translate_nl_value_slowfast(value
):
748 return 'fast' if value
else 'slow'
750 def _query_running_attrs(self
, bondname
):
751 cached_vxlan_ifla_info_data
= self
.cache
.get_link_info_data(bondname
)
754 'bond-mode': Link
.ifla_bond_mode_pretty_tbl
.get(cached_vxlan_ifla_info_data
.get(Link
.IFLA_BOND_MODE
)),
755 'bond-miimon': cached_vxlan_ifla_info_data
.get(Link
.IFLA_BOND_MIIMON
),
756 'bond-use-carrier': self
.translate_nl_value_yesno(cached_vxlan_ifla_info_data
.get(Link
.IFLA_BOND_USE_CARRIER
)),
757 'bond-lacp-rate': self
.translate_nl_value_slowfast(cached_vxlan_ifla_info_data
.get(Link
.IFLA_BOND_AD_LACP_RATE
)),
758 'bond-min-links': cached_vxlan_ifla_info_data
.get(Link
.IFLA_BOND_MIN_LINKS
),
759 'bond-ad-actor-system': cached_vxlan_ifla_info_data
.get(Link
.IFLA_BOND_AD_ACTOR_SYSTEM
),
760 'bond-ad-actor-sys-prio': cached_vxlan_ifla_info_data
.get(Link
.IFLA_BOND_AD_ACTOR_SYS_PRIO
),
761 'bond-xmit-hash-policy': Link
.ifla_bond_xmit_hash_policy_pretty_tbl
.get(cached_vxlan_ifla_info_data
.get(Link
.IFLA_BOND_XMIT_HASH_POLICY
)),
762 'bond-lacp-bypass-allow': self
.translate_nl_value_yesno(cached_vxlan_ifla_info_data
.get(Link
.IFLA_BOND_AD_LACP_BYPASS
)),
763 'bond-num-unsol-na': cached_vxlan_ifla_info_data
.get(Link
.IFLA_BOND_NUM_PEER_NOTIF
),
764 'bond-num-grat-arp': cached_vxlan_ifla_info_data
.get(Link
.IFLA_BOND_NUM_PEER_NOTIF
),
765 'bond-updelay': cached_vxlan_ifla_info_data
.get(Link
.IFLA_BOND_UPDELAY
),
766 'bond-downdelay': cached_vxlan_ifla_info_data
.get(Link
.IFLA_BOND_DOWNDELAY
)
769 cached_bond_primary
= cached_vxlan_ifla_info_data
.get(Link
.IFLA_BOND_PRIMARY
)
770 if cached_bond_primary
:
771 bond_attrs
['bond-primary'] = self
.cache
.get_ifname(cached_bond_primary
)
773 slaves
= self
.cache
.get_slaves(bondname
)
775 bond_attrs
['bond-slaves'] = slaves
778 def _query_running(self
, ifaceobjrunning
, ifaceobj_getfunc
=None):
779 if not self
.cache
.bond_exists(ifaceobjrunning
.name
):
781 bond_attrs
= self
._query
_running
_attrs
(ifaceobjrunning
.name
)
782 if bond_attrs
.get('bond-slaves'):
783 bond_attrs
['bond-slaves'] = ' '.join(bond_attrs
.get('bond-slaves'))
785 [ifaceobjrunning
.update_config(k
, str(v
))
786 for k
, v
in bond_attrs
.items()
792 'query-running': _query_running
,
793 'query-checkcurr': _query_check
797 """ returns list of ops supported by this module """
798 return self
._run
_ops
.keys()
800 def run(self
, ifaceobj
, operation
, query_ifaceobj
=None,
801 ifaceobj_getfunc
=None):
802 """ run bond configuration on the interface object passed as argument
805 **ifaceobj** (object): iface object
807 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
811 **query_ifaceobj** (object): query check ifaceobject. This is only
812 valid when op is 'query-checkcurr'. It is an object same as
813 ifaceobj, but contains running attribute values and its config
814 status. The modules can use it to return queried running state
815 of interfaces. status is success if the running state is same
816 as user required state in ifaceobj. error otherwise.
818 op_handler
= self
._run
_ops
.get(operation
)
821 if operation
!= 'query-running' and not self
._is
_bond
(ifaceobj
):
823 if operation
== 'query-checkcurr':
824 op_handler(self
, ifaceobj
, query_ifaceobj
,
825 ifaceobj_getfunc
=ifaceobj_getfunc
)
827 op_handler(self
, ifaceobj
, ifaceobj_getfunc
=ifaceobj_getfunc
)