]>
Commit | Line | Data |
---|---|---|
35681c06 | 1 | #!/usr/bin/env python3 |
d486dd0d JF |
2 | # |
3 | # Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved. | |
4 | # Authors: | |
5 | # Roopa Prabhu, roopa@cumulusnetworks.com | |
6 | # Julien Fortin, julien@cumulusnetworks.com | |
7 | # | |
8 | ||
9 | import os | |
10 | ||
d486dd0d | 11 | try: |
223ba5af | 12 | from ifupdown2.lib.addon import Addon |
d486dd0d JF |
13 | from ifupdown2.nlmanager.nlmanager import Link |
14 | ||
15 | from ifupdown2.ifupdown.iface import * | |
16 | from ifupdown2.ifupdown.utils import utils | |
d486dd0d JF |
17 | from ifupdown2.ifupdown.statemanager import statemanager_api as statemanager |
18 | ||
19 | import ifupdown2.ifupdown.policymanager as policymanager | |
20 | import ifupdown2.ifupdown.ifupdownflags as ifupdownflags | |
21 | ||
d486dd0d | 22 | from ifupdown2.ifupdownaddons.modulebase import moduleBase |
bd441a51 | 23 | except (ImportError, ModuleNotFoundError): |
223ba5af | 24 | from lib.addon import Addon |
d486dd0d JF |
25 | from nlmanager.nlmanager import Link |
26 | ||
27 | from ifupdown.iface import * | |
28 | from ifupdown.utils import utils | |
d486dd0d JF |
29 | from ifupdown.statemanager import statemanager_api as statemanager |
30 | ||
d486dd0d JF |
31 | from ifupdownaddons.modulebase import moduleBase |
32 | ||
33 | import ifupdown.policymanager as policymanager | |
34 | import ifupdown.ifupdownflags as ifupdownflags | |
35 | ||
223ba5af | 36 | class bond(Addon, moduleBase): |
d486dd0d JF |
37 | """ ifupdown2 addon module to configure bond interfaces """ |
38 | ||
39 | overrides_ifupdown_scripts = ['ifenslave', ] | |
40 | ||
223ba5af JF |
41 | _modinfo = { |
42 | "mhelp": "bond configuration module", | |
43 | "attrs": { | |
44 | "bond-use-carrier": { | |
45 | "help": "bond use carrier", | |
46 | "validvals": ["yes", "no", "0", "1"], | |
47 | "default": "yes", | |
48 | "example": ["bond-use-carrier yes"]}, | |
49 | "bond-num-grat-arp": { | |
50 | "help": "bond use carrier", | |
51 | "validrange": ["0", "255"], | |
52 | "default": "1", | |
53 | "example": ["bond-num-grat-arp 1"] | |
54 | }, | |
55 | "bond-num-unsol-na": { | |
56 | "help": "bond slave devices", | |
57 | "validrange": ["0", "255"], | |
58 | "default": "1", | |
59 | "example": ["bond-num-unsol-na 1"] | |
60 | }, | |
61 | "bond-xmit-hash-policy": { | |
62 | "help": "bond slave devices", | |
63 | "validvals": [ | |
64 | "0", "layer2", | |
65 | "1", "layer3+4", | |
66 | "2", "layer2+3", | |
67 | "3", "encap2+3", | |
9a26f48f | 68 | "4", "encap3+4", |
69 | "5", "vlan+srcmac" | |
223ba5af JF |
70 | ], |
71 | "default": "layer2", | |
72 | "example": ["bond-xmit-hash-policy layer2"] | |
73 | }, | |
74 | "bond-miimon": { | |
75 | "help": "bond miimon", | |
76 | "validrange": ["0", "255"], | |
77 | "default": "0", | |
78 | "example": ["bond-miimon 0"] | |
79 | }, | |
80 | "bond-mode": { | |
81 | "help": "bond mode", | |
82 | "validvals": [ | |
83 | "0", "balance-rr", | |
84 | "1", "active-backup", | |
85 | "2", "balance-xor", | |
86 | "3", "broadcast", | |
87 | "4", "802.3ad", | |
88 | "5", "balance-tlb", | |
89 | "6", "balance-alb" | |
90 | ], | |
91 | "default": "balance-rr", | |
92 | "example": ["bond-mode 802.3ad"] | |
93 | }, | |
94 | "bond-lacp-rate": { | |
95 | "help": "bond lacp rate", | |
96 | "validvals": ["0", "slow", "1", "fast"], | |
97 | "default": "0", | |
98 | "example": ["bond-lacp-rate 0"] | |
99 | }, | |
100 | "bond-min-links": { | |
101 | "help": "bond min links", | |
102 | "default": "0", | |
103 | "validrange": ["0", "255"], | |
104 | "example": ["bond-min-links 0"] | |
105 | }, | |
106 | "bond-ad-sys-priority": { | |
107 | "help": "802.3ad system priority", | |
108 | "default": "65535", | |
109 | "validrange": ["0", "65535"], | |
110 | "example": ["bond-ad-sys-priority 65535"], | |
111 | "deprecated": True, | |
112 | "new-attribute": "bond-ad-actor-sys-prio" | |
113 | }, | |
114 | "bond-ad-actor-sys-prio": { | |
115 | "help": "802.3ad system priority", | |
116 | "default": "65535", | |
117 | "validrange": ["0", "65535"], | |
118 | "example": ["bond-ad-actor-sys-prio 65535"] | |
119 | }, | |
120 | "bond-ad-sys-mac-addr": { | |
121 | "help": "802.3ad system mac address", | |
122 | "validvals": ["<mac>", ], | |
123 | "example": ["bond-ad-sys-mac-addr 00:00:00:00:00:00"], | |
124 | "deprecated": True, | |
125 | "new-attribute": "bond-ad-actor-system" | |
126 | }, | |
127 | "bond-ad-actor-system": { | |
128 | "help": "802.3ad system mac address", | |
129 | "validvals": ["<mac>", ], | |
130 | "example": ["bond-ad-actor-system 00:00:00:00:00:00"], | |
131 | }, | |
132 | "bond-lacp-bypass-allow": { | |
133 | "help": "allow lacp bypass", | |
134 | "validvals": ["yes", "no", "0", "1"], | |
135 | "default": "no", | |
136 | "example": ["bond-lacp-bypass-allow no"] | |
137 | }, | |
138 | "bond-slaves": { | |
139 | "help": "bond slaves", | |
140 | "required": True, | |
141 | "multivalue": True, | |
142 | "validvals": ["<interface-list>"], | |
143 | "example": [ | |
144 | "bond-slaves swp1 swp2", | |
145 | "bond-slaves glob swp1-2", | |
d34d1513 | 146 | "bond-slaves regex (swp[1|2])" |
223ba5af JF |
147 | ], |
148 | "aliases": ["bond-ports"] | |
149 | }, | |
150 | "bond-updelay": { | |
151 | "help": "bond updelay", | |
152 | "default": "0", | |
153 | "validrange": ["0", "65535"], | |
154 | "example": ["bond-updelay 100"] | |
155 | }, | |
156 | "bond-downdelay": { | |
157 | "help": "bond downdelay", | |
158 | "default": "0", | |
159 | "validrange": ["0", "65535"], | |
160 | "example": ["bond-downdelay 100"] | |
161 | }, | |
162 | "bond-primary": { | |
163 | "help": "Control which slave interface is " | |
164 | "preferred active member", | |
165 | "example": ["bond-primary swp1"] | |
716316cf AD |
166 | }, |
167 | "bond-primary-reselect": { | |
168 | "help": "bond primary reselect", | |
169 | "validvals": [ | |
170 | "0", "always", | |
171 | "1", "better", | |
172 | "2", "failure", | |
173 | ], | |
174 | "example": ["bond-primary-reselect failure"] | |
9808982e JF |
175 | }, |
176 | "es-sys-mac": { | |
177 | "help": "evpn-mh: system mac address", | |
178 | "validvals": ["<mac>", ], | |
4b706d71 | 179 | "example": ["es-sys-mac 00:00:00:00:00:42"], |
223ba5af JF |
180 | } |
181 | } | |
182 | } | |
d486dd0d JF |
183 | |
184 | _bond_attr_netlink_map = { | |
185 | 'bond-mode': Link.IFLA_BOND_MODE, | |
186 | 'bond-miimon': Link.IFLA_BOND_MIIMON, | |
187 | 'bond-use-carrier': Link.IFLA_BOND_USE_CARRIER, | |
188 | 'bond-lacp-rate': Link.IFLA_BOND_AD_LACP_RATE, | |
189 | 'bond-xmit-hash-policy': Link.IFLA_BOND_XMIT_HASH_POLICY, | |
190 | 'bond-min-links': Link.IFLA_BOND_MIN_LINKS, | |
191 | 'bond-num-grat-arp': Link.IFLA_BOND_NUM_PEER_NOTIF, | |
192 | 'bond-num-unsol-na': Link.IFLA_BOND_NUM_PEER_NOTIF, | |
9808982e | 193 | 'es-sys-mac': Link.IFLA_BOND_AD_ACTOR_SYSTEM, |
d486dd0d JF |
194 | 'bond-ad-sys-mac-addr': Link.IFLA_BOND_AD_ACTOR_SYSTEM, |
195 | 'bond-ad-actor-system': Link.IFLA_BOND_AD_ACTOR_SYSTEM, | |
196 | 'bond-ad-sys-priority': Link.IFLA_BOND_AD_ACTOR_SYS_PRIO, | |
197 | 'bond-ad-actor-sys-prio': Link.IFLA_BOND_AD_ACTOR_SYS_PRIO, | |
198 | 'bond-lacp-bypass-allow': Link.IFLA_BOND_AD_LACP_BYPASS, | |
199 | 'bond-updelay': Link.IFLA_BOND_UPDELAY, | |
223ba5af | 200 | 'bond-downdelay': Link.IFLA_BOND_DOWNDELAY, |
716316cf AD |
201 | 'bond-primary': Link.IFLA_BOND_PRIMARY, |
202 | 'bond-primary-reselect': Link.IFLA_BOND_PRIMARY_RESELECT | |
203 | ||
d486dd0d JF |
204 | } |
205 | ||
206 | # ifquery-check attr dictionary with callable object to translate user data to netlink format | |
207 | _bond_attr_ifquery_check_translate_func = { | |
208 | Link.IFLA_BOND_MODE: lambda x: Link.ifla_bond_mode_tbl[x], | |
209 | Link.IFLA_BOND_MIIMON: int, | |
210 | Link.IFLA_BOND_USE_CARRIER: utils.get_boolean_from_string, | |
211 | Link.IFLA_BOND_AD_LACP_RATE: lambda x: int(utils.get_boolean_from_string(x)), | |
212 | Link.IFLA_BOND_XMIT_HASH_POLICY: lambda x: Link.ifla_bond_xmit_hash_policy_tbl[x], | |
213 | Link.IFLA_BOND_MIN_LINKS: int, | |
214 | Link.IFLA_BOND_NUM_PEER_NOTIF: int, | |
215 | Link.IFLA_BOND_AD_ACTOR_SYSTEM: str, | |
216 | Link.IFLA_BOND_AD_ACTOR_SYS_PRIO: int, | |
217 | Link.IFLA_BOND_AD_LACP_BYPASS: lambda x: int(utils.get_boolean_from_string(x)), | |
218 | Link.IFLA_BOND_UPDELAY: int, | |
223ba5af | 219 | Link.IFLA_BOND_DOWNDELAY: int, |
716316cf | 220 | Link.IFLA_BOND_PRIMARY_RESELECT: lambda x: Link.ifla_bond_primary_reselect_tbl[x], |
223ba5af | 221 | # Link.IFLA_BOND_PRIMARY: self.netlink.get_ifname is added in __init__() |
d486dd0d JF |
222 | } |
223 | ||
224 | # ifup attr list with callable object to translate user data to netlink format | |
225 | # in the future this can be moved to a dictionary, whenever we detect that some | |
226 | # netlink capabilities are missing we can dynamically remove them from the dict. | |
227 | _bond_attr_set_list = ( | |
228 | ('bond-mode', Link.IFLA_BOND_MODE, lambda x: Link.ifla_bond_mode_tbl[x]), | |
229 | ('bond-xmit-hash-policy', Link.IFLA_BOND_XMIT_HASH_POLICY, lambda x: Link.ifla_bond_xmit_hash_policy_tbl[x]), | |
230 | ('bond-miimon', Link.IFLA_BOND_MIIMON, int), | |
231 | ('bond-min-links', Link.IFLA_BOND_MIN_LINKS, int), | |
232 | ('bond-num-grat-arp', Link.IFLA_BOND_NUM_PEER_NOTIF, int), | |
233 | ('bond-num-unsol-na', Link.IFLA_BOND_NUM_PEER_NOTIF, int), | |
234 | ('bond-ad-sys-priority', Link.IFLA_BOND_AD_ACTOR_SYS_PRIO, int), | |
235 | ('bond-ad-actor-sys-prio', Link.IFLA_BOND_AD_ACTOR_SYS_PRIO, int), | |
236 | ('bond-updelay', Link.IFLA_BOND_UPDELAY, int), | |
237 | ('bond-downdelay', Link.IFLA_BOND_DOWNDELAY, int), | |
238 | ('bond-use-carrier', Link.IFLA_BOND_USE_CARRIER, lambda x: int(utils.get_boolean_from_string(x))), | |
239 | ('bond-lacp-rate', Link.IFLA_BOND_AD_LACP_RATE, lambda x: int(utils.get_boolean_from_string(x))), | |
240 | ('bond-lacp-bypass-allow', Link.IFLA_BOND_AD_LACP_BYPASS, lambda x: int(utils.get_boolean_from_string(x))), | |
9808982e | 241 | ('es-sys-mac', Link.IFLA_BOND_AD_ACTOR_SYSTEM, str), |
d486dd0d | 242 | ('bond-ad-sys-mac-addr', Link.IFLA_BOND_AD_ACTOR_SYSTEM, str), |
716316cf AD |
243 | ('bond-ad-actor-system', Link.IFLA_BOND_AD_ACTOR_SYSTEM, str), |
244 | ('bond-primary-reselect', Link.IFLA_BOND_PRIMARY_RESELECT, lambda x: Link.ifla_bond_primary_reselect_tbl[x]) | |
223ba5af | 245 | # ('bond-primary', Link.IFLA_BOND_PRIMARY, self.cache.get_ifindex) added in __init__() |
d486dd0d JF |
246 | ) |
247 | ||
248 | def __init__(self, *args, **kargs): | |
223ba5af | 249 | Addon.__init__(self) |
d486dd0d | 250 | moduleBase.__init__(self, *args, **kargs) |
d486dd0d JF |
251 | |
252 | if not os.path.exists('/sys/class/net/bonding_masters'): | |
0c4237d5 JF |
253 | try: |
254 | utils.exec_command('modprobe -q bonding') | |
255 | except Exception as e: | |
256 | self.logger.info("bond: error while loading bonding module: %s" % str(e)) | |
d486dd0d | 257 | |
223ba5af JF |
258 | self._bond_attr_ifquery_check_translate_func[Link.IFLA_BOND_PRIMARY] = self.cache.get_ifindex |
259 | self._bond_attr_set_list = self._bond_attr_set_list + (('bond-primary', Link.IFLA_BOND_PRIMARY, self.cache.get_ifindex),) | |
260 | ||
03813675 JF |
261 | self.bond_mac_mgmt = utils.get_boolean_from_string( |
262 | policymanager.policymanager_api.get_module_globals( | |
263 | module_name=self.__class__.__name__, | |
264 | attr="bond_mac_mgmt"), | |
265 | True | |
266 | ) | |
6bc9fadc JF |
267 | |
268 | def get_bond_slaves(self, ifaceobj): | |
269 | # bond-ports aliases should be translated to bond-slaves | |
270 | return ifaceobj.get_attr_value_first('bond-slaves') | |
d486dd0d JF |
271 | |
272 | def _is_bond(self, ifaceobj): | |
273 | # at first link_kind is not set but once ifupdownmain | |
274 | # calls get_dependent_ifacenames link_kind is set to BOND | |
223ba5af | 275 | return ifaceobj.link_kind & ifaceLinkKind.BOND or self.get_bond_slaves(ifaceobj) |
d486dd0d | 276 | |
59ab29fb | 277 | def get_dependent_ifacenames(self, ifaceobj, ifacenames_all=None, old_ifaceobjs=False): |
d486dd0d JF |
278 | """ Returns list of interfaces dependent on ifaceobj """ |
279 | ||
280 | if not self._is_bond(ifaceobj): | |
281 | return None | |
282 | slave_list = self.parse_port_list(ifaceobj.name, | |
283 | self.get_bond_slaves(ifaceobj), | |
284 | ifacenames_all) | |
285 | ifaceobj.dependency_type = ifaceDependencyType.MASTER_SLAVE | |
286 | # Also save a copy for future use | |
287 | ifaceobj.priv_data = list(slave_list) | |
288 | if ifaceobj.link_type != ifaceLinkType.LINK_NA: | |
289 | ifaceobj.link_type = ifaceLinkType.LINK_MASTER | |
290 | ifaceobj.link_kind |= ifaceLinkKind.BOND | |
291 | ifaceobj.role |= ifaceRole.MASTER | |
292 | ||
9808982e JF |
293 | if ifaceobj.get_attr_value("es-sys-mac"): |
294 | ifaceobj.link_privflags |= ifaceLinkPrivFlags.ES_BOND | |
295 | ||
d486dd0d JF |
296 | return slave_list |
297 | ||
298 | def syntax_check(self, ifaceobj, ifaceobj_getfunc): | |
299 | return self.syntax_check_updown_delay(ifaceobj) | |
300 | ||
301 | def get_dependent_ifacenames_running(self, ifaceobj): | |
223ba5af | 302 | return self.cache.get_slaves(ifaceobj.name) |
d486dd0d JF |
303 | |
304 | def _get_slave_list(self, ifaceobj): | |
305 | """ Returns slave list present in ifaceobj config """ | |
306 | ||
307 | # If priv data already has slave list use that first. | |
308 | if ifaceobj.priv_data: | |
309 | return ifaceobj.priv_data | |
310 | slaves = self.get_bond_slaves(ifaceobj) | |
311 | if slaves: | |
312 | return self.parse_port_list(ifaceobj.name, slaves) | |
313 | else: | |
314 | return None | |
315 | ||
ff775ef1 JF |
316 | def enable_ipv6_if_prev_brport(self, ifname): |
317 | """ | |
318 | If the intf was previously enslaved to a bridge it is possible ipv6 is still disabled. | |
319 | """ | |
320 | try: | |
223ba5af JF |
321 | for ifaceobj in statemanager.get_ifaceobjs(ifname) or []: |
322 | if ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT: | |
323 | self.write_file("/proc/sys/net/ipv6/conf/%s/disable_ipv6" % ifname, "0") | |
324 | return | |
3b01ed76 | 325 | except Exception as e: |
ff775ef1 JF |
326 | self.logger.info(str(e)) |
327 | ||
d486dd0d JF |
328 | def _is_clag_bond(self, ifaceobj): |
329 | if self.get_bond_slaves(ifaceobj): | |
330 | attrval = ifaceobj.get_attr_value_first('clag-id') | |
331 | if attrval and attrval != '0': | |
332 | return True | |
333 | return False | |
334 | ||
223ba5af | 335 | def _add_slaves(self, ifaceobj, runningslaves, ifaceobj_getfunc=None): |
d486dd0d JF |
336 | slaves = self._get_slave_list(ifaceobj) |
337 | if not slaves: | |
338 | self.logger.debug('%s: no slaves found' %ifaceobj.name) | |
339 | return | |
340 | ||
d486dd0d JF |
341 | clag_bond = self._is_clag_bond(ifaceobj) |
342 | ||
1f928890 JF |
343 | # remove duplicates and devices that are already enslaved |
344 | devices_to_enslave = [] | |
345 | for s in slaves: | |
346 | if s not in runningslaves and s not in devices_to_enslave: | |
347 | devices_to_enslave.append(s) | |
348 | ||
349 | for slave in devices_to_enslave: | |
d486dd0d | 350 | if (not ifupdownflags.flags.PERFMODE and |
223ba5af | 351 | not self.cache.link_exists(slave)): |
d486dd0d JF |
352 | self.log_error('%s: skipping slave %s, does not exist' |
353 | %(ifaceobj.name, slave), ifaceobj, | |
354 | raise_error=False) | |
355 | continue | |
356 | link_up = False | |
223ba5af JF |
357 | if self.cache.link_is_up(slave): |
358 | self.netlink.link_down_force(slave) | |
d486dd0d | 359 | link_up = True |
9808982e JF |
360 | |
361 | # if clag or ES bond: place the slave in a protodown state; | |
362 | # (clagd will proto-up it when it is ready) | |
363 | if clag_bond or ifaceobj.link_privflags & ifaceLinkPrivFlags.ES_BOND: | |
d486dd0d | 364 | try: |
223ba5af | 365 | self.netlink.link_set_protodown_on(slave) |
3b01ed76 | 366 | except Exception as e: |
d486dd0d | 367 | self.logger.error('%s: %s' % (ifaceobj.name, str(e))) |
223ba5af | 368 | |
ff775ef1 | 369 | self.enable_ipv6_if_prev_brport(slave) |
223ba5af | 370 | self.netlink.link_set_master(slave, ifaceobj.name) |
03813675 | 371 | runningslaves.append(slave) |
223ba5af JF |
372 | # TODO: if this fail we should switch to iproute2 |
373 | # start a batch: down - set master - up | |
d486dd0d JF |
374 | if link_up or ifaceobj.link_type != ifaceLinkType.LINK_NA: |
375 | try: | |
376 | if (ifaceobj_getfunc(slave)[0].link_privflags & | |
377 | ifaceLinkPrivFlags.KEEP_LINK_DOWN): | |
223ba5af | 378 | self.netlink.link_down_force(slave) |
d486dd0d | 379 | else: |
03813675 | 380 | self.netlink.link_up_force(slave) |
3b01ed76 | 381 | except Exception as e: |
d486dd0d JF |
382 | self.logger.debug('%s: %s' % (ifaceobj.name, str(e))) |
383 | pass | |
384 | ||
385 | if runningslaves: | |
03813675 JF |
386 | removed_slave = [] |
387 | ||
d486dd0d | 388 | for s in runningslaves: |
d079ad3f JF |
389 | # make sure that slaves are not in protodown since we are not in the clag-bond or es-bond case |
390 | if not clag_bond and not ifaceobj.link_privflags & ifaceLinkPrivFlags.ES_BOND and self.cache.get_link_protodown(s): | |
391 | self.netlink.link_set_protodown_off(s) | |
392 | ||
d486dd0d | 393 | if s not in slaves: |
223ba5af | 394 | self.sysfs.bond_remove_slave(ifaceobj.name, s) |
03813675 | 395 | removed_slave.append(s) |
d486dd0d JF |
396 | if clag_bond: |
397 | try: | |
223ba5af | 398 | self.netlink.link_set_protodown_off(s) |
3b01ed76 | 399 | except Exception as e: |
d486dd0d | 400 | self.logger.error('%s: %s' % (ifaceobj.name, str(e))) |
315f4f03 JF |
401 | |
402 | # ip link set $slave nomaster will set the slave admin down | |
403 | # if the slave has an auto stanza, we should keep it admin up | |
404 | # unless link-down yes is set | |
405 | slave_class_auto = False | |
406 | slave_link_down = False | |
407 | for obj in ifaceobj_getfunc(s) or []: | |
408 | if obj.auto: | |
409 | slave_class_auto = True | |
410 | if obj.link_privflags & ifaceLinkPrivFlags.KEEP_LINK_DOWN: | |
411 | slave_link_down = True | |
412 | if slave_class_auto and not slave_link_down: | |
413 | self.netlink.link_up_force(s) | |
d486dd0d JF |
414 | else: |
415 | # apply link-down config changes on running slaves | |
416 | try: | |
223ba5af | 417 | link_up = self.cache.link_is_up(s) |
d486dd0d JF |
418 | config_link_down = (ifaceobj_getfunc(s)[0].link_privflags & |
419 | ifaceLinkPrivFlags.KEEP_LINK_DOWN) | |
420 | if (config_link_down and link_up): | |
223ba5af | 421 | self.netlink.link_down_force(s) |
d486dd0d | 422 | elif (not config_link_down and not link_up): |
223ba5af | 423 | self.netlink.link_up_force(s) |
3b01ed76 | 424 | except Exception as e: |
c46af1c9 | 425 | self.logger.warning('%s: %s' % (ifaceobj.name, str(e))) |
d486dd0d | 426 | |
03813675 JF |
427 | for s in removed_slave: |
428 | try: | |
429 | runningslaves.remove(s) | |
430 | except: | |
431 | pass | |
432 | ||
433 | return runningslaves | |
434 | ||
d486dd0d JF |
435 | def _check_updown_delay_log(self, ifaceobj, attr_name, value): |
436 | ifaceobj.status = ifaceStatus.ERROR | |
437 | self.logger.error('%s: unable to set %s %s as MII link monitoring is ' | |
438 | 'disabled' % (ifaceobj.name, attr_name, value)) | |
439 | # return False to notify syntax_check that an error has been logged | |
440 | return False | |
441 | ||
442 | def syntax_check_updown_delay(self, ifaceobj): | |
443 | result = True | |
444 | updelay = ifaceobj.get_attr_value_first('bond-updelay') | |
445 | downdelay = ifaceobj.get_attr_value_first('bond-downdelay') | |
446 | ||
447 | if not updelay and not downdelay: | |
448 | return True | |
449 | ||
450 | try: | |
451 | miimon = int(ifaceobj.get_attr_value_first('bond-miimon')) | |
3218f49d | 452 | except Exception: |
d486dd0d JF |
453 | try: |
454 | miimon = int(policymanager.policymanager_api.get_iface_default( | |
455 | module_name=self.__class__.__name__, | |
456 | ifname=ifaceobj.name, | |
457 | attr='bond-miimon')) | |
3218f49d | 458 | except Exception: |
d486dd0d JF |
459 | miimon = 0 |
460 | ||
461 | if not miimon: | |
462 | # self._check_updown_delay_log returns False no matter what | |
463 | if updelay and int(updelay): | |
464 | result = self._check_updown_delay_log(ifaceobj, 'bond-updelay', updelay) | |
465 | if downdelay and int(downdelay): | |
466 | result = self._check_updown_delay_log(ifaceobj, 'bond-downdelay', downdelay) | |
467 | ||
468 | return result | |
469 | ||
470 | _bond_updown_delay_nl_list = ( | |
471 | (Link.IFLA_BOND_UPDELAY, 'bond-updelay'), | |
472 | (Link.IFLA_BOND_DOWNDELAY, 'bond-downdelay') | |
473 | ) | |
474 | ||
475 | def check_updown_delay_nl(self, link_exists, ifaceobj, ifla_info_data): | |
476 | """ | |
477 | IFLA_BOND_MIIMON | |
478 | Specifies the time, in milliseconds, to wait before enabling a slave | |
479 | after a link recovery has been detected. This option is only valid | |
480 | for the miimon link monitor. The updelay value should be a multiple | |
481 | of the miimon value; if not, it will be rounded down to the nearest | |
482 | multiple. The default value is 0. | |
483 | ||
484 | This ifla_bond_miimon code should be move to get_ifla_bond_attr_from_user_config | |
485 | but we need to know if the operation was successful to update the cache accordingly | |
486 | """ | |
487 | ifla_bond_miimon = ifla_info_data.get(Link.IFLA_BOND_MIIMON) | |
488 | if link_exists and ifla_bond_miimon is None: | |
223ba5af | 489 | ifla_bond_miimon = self.cache.get_link_info_data_attribute(ifaceobj.name, Link.IFLA_BOND_MIIMON) |
d486dd0d JF |
490 | |
491 | if ifla_bond_miimon == 0: | |
492 | for nl_attr, attr_name in self._bond_updown_delay_nl_list: | |
493 | delay = ifla_info_data.get(nl_attr) | |
494 | # if up-down-delay exists we need to remove it, if non zero log error | |
495 | if delay is not None: | |
496 | if delay > 0: | |
497 | self._check_updown_delay_log(ifaceobj, attr_name, delay) | |
498 | del ifla_info_data[nl_attr] | |
499 | return True | |
500 | return False | |
501 | ||
502 | _bond_lacp_attrs = ( | |
503 | (Link.IFLA_BOND_AD_LACP_RATE, 'bond-lacp-rate'), | |
504 | (Link.IFLA_BOND_AD_LACP_BYPASS, 'bond-lacp-bypass') | |
505 | ) | |
506 | ||
507 | def _check_bond_mode_user_config(self, ifname, link_exists, ifla_info_data): | |
508 | ifla_bond_mode = ifla_info_data.get(Link.IFLA_BOND_MODE) | |
509 | if ifla_bond_mode is None and link_exists: | |
223ba5af | 510 | ifla_bond_mode = self.cache.get_link_info_data_attribute(ifname, Link.IFLA_BOND_MODE) |
d486dd0d JF |
511 | # in this case the link already exists (we have a cached value): |
512 | # if IFLA_BOND_MODE is not present in ifla_info_data it means: | |
513 | # - that bond-mode was present in the user config and didn't change | |
514 | # - never was in the user config so bond mode should be the system default value | |
515 | # - was removed from the stanza so we might have to reset it to default value | |
516 | # nevertheless we need to add it back to the ifla_info_data dict to check | |
517 | # if we need to reset the mode to system default | |
518 | ifla_info_data[Link.IFLA_BOND_MODE] = ifla_bond_mode | |
519 | ||
520 | if ifla_bond_mode == 4: # 802.3ad | |
521 | min_links = ifla_info_data.get(Link.IFLA_BOND_MIN_LINKS) | |
522 | if min_links is None: | |
223ba5af | 523 | min_links = self.cache.get_link_info_data_attribute(ifname, Link.IFLA_BOND_MIN_LINKS) |
d486dd0d JF |
524 | # get_min_links_nl may return None so we need to strictly check 0 |
525 | if min_links == 0: | |
c46af1c9 | 526 | self.logger.warning('%s: attribute bond-min-links is set to \'0\'' % ifname) |
d486dd0d JF |
527 | else: |
528 | # IFLA_BOND_AD_LACP_RATE and IFLA_BOND_AD_LACP_BYPASS only for 802.3ad mode (4) | |
529 | for nl_attr, attr_name in self._bond_lacp_attrs: | |
530 | if nl_attr in ifla_info_data: | |
531 | self.logger.info('%s: ignoring %s: only available for 802.3ad mode (4)' % (ifname, attr_name)) | |
532 | del ifla_info_data[nl_attr] | |
533 | ||
534 | @staticmethod | |
535 | def get_saved_ifaceobj(link_exists, ifname): | |
536 | if link_exists: | |
537 | old_config = statemanager.get_ifaceobjs(ifname) | |
538 | if old_config: | |
539 | return old_config[0] | |
540 | return None | |
541 | ||
542 | def get_ifla_bond_attr_from_user_config(self, ifaceobj, link_exists): | |
543 | """ | |
544 | Potential issue: if a user load the bond driver with custom | |
545 | default values (say bond-mode 3), ifupdown2 has no knowledge | |
546 | of these default values. | |
547 | At bond creation everything should work, bonds will be created | |
548 | with mode 3 (even if not specified under the stanza). | |
549 | But, for example: if the user specifies a value under bond-mode | |
550 | and later on the user removes the bond-mode line from the stanza | |
551 | we will detect it and reset to MODINFO: BOND-MODE: DEFAULT aka 0 | |
552 | which is not the real default value that the user may expect. | |
553 | """ | |
554 | ifname = ifaceobj.name | |
555 | ifla_info_data = OrderedDict() | |
556 | old_config = self.get_saved_ifaceobj(link_exists, ifname) | |
557 | ||
558 | # for each bond attribute we fetch the user configuration | |
559 | # if no configuration is provided we look for a config in policy files | |
560 | for attr_name, netlink_attr, func_ptr in self._bond_attr_set_list: | |
561 | cached_value = None | |
562 | user_config = ifaceobj.get_attr_value_first(attr_name) | |
563 | ||
564 | if not user_config: | |
565 | user_config = policymanager.policymanager_api.get_iface_default( | |
566 | module_name=self.__class__.__name__, | |
567 | ifname=ifname, | |
568 | attr=attr_name) | |
569 | if user_config: | |
570 | self.logger.debug('%s: %s %s: extracted from policy files' | |
571 | % (ifname, attr_name, user_config)) | |
572 | ||
573 | # no policy override, do we need to reset an attr to default value? | |
574 | if not user_config and old_config and old_config.get_attr_value_first(attr_name): | |
575 | # if the link already exists but the value is set | |
576 | # (potentially removed from the stanza, we need to reset it to default) | |
577 | # might not work for specific cases, see explanation at the top of this function :) | |
578 | user_config = self.get_attr_default_value(attr_name) | |
579 | if user_config: | |
580 | self.logger.debug('%s: %s: removed from stanza, resetting to default value: %s' | |
581 | % (ifname, attr_name, user_config)) | |
582 | ||
583 | if user_config: | |
584 | try: | |
585 | nl_value = func_ptr(user_config.lower()) | |
586 | ||
587 | if link_exists: | |
223ba5af | 588 | cached_value = self.cache.get_link_info_data_attribute(ifname, netlink_attr) |
d486dd0d JF |
589 | |
590 | if link_exists and cached_value is None: | |
591 | # the link already exists but we don't have any value | |
592 | # cached for this attr, it probably means that the | |
593 | # capability is not available on this system (i.e old kernel) | |
594 | self.logger.debug('%s: ignoring %s %s: capability ' | |
595 | 'probably not supported on this system' | |
596 | % (ifname, attr_name, user_config)) | |
597 | continue | |
598 | elif link_exists: | |
599 | # there should be a cached value if the link already exists | |
600 | if cached_value == nl_value: | |
601 | # if the user value is already cached: continue | |
602 | continue | |
603 | ||
604 | # else: the link doesn't exist so we create the bond with | |
605 | # all the user/policy defined values without extra checks | |
606 | ifla_info_data[netlink_attr] = nl_value | |
607 | ||
608 | if cached_value is not None: | |
609 | self.logger.info('%s: set %s %s (cache %s)' % (ifname, attr_name, user_config, cached_value)) | |
610 | else: | |
611 | self.logger.info('%s: set %s %s' % (ifname, attr_name, user_config)) | |
612 | ||
613 | except KeyError: | |
614 | self.logger.warning('%s: invalid %s value %s' % (ifname, attr_name, user_config)) | |
615 | ||
616 | self._check_bond_mode_user_config(ifname, link_exists, ifla_info_data) | |
617 | return ifla_info_data | |
618 | ||
619 | _bond_down_nl_attributes_list = ( | |
620 | Link.IFLA_BOND_MODE, | |
621 | Link.IFLA_BOND_XMIT_HASH_POLICY, | |
622 | Link.IFLA_BOND_AD_LACP_RATE, | |
623 | Link.IFLA_BOND_MIN_LINKS | |
624 | ) | |
625 | ||
626 | def _should_down_bond(self, ifla_info_data): | |
627 | for nl_attr in self._bond_down_nl_attributes_list: | |
628 | if nl_attr in ifla_info_data: | |
629 | return True | |
630 | return False | |
631 | ||
223ba5af | 632 | def should_update_bond_mode(self, ifaceobj, ifname, is_link_up, ifla_info_data, bond_slaves): |
d486dd0d JF |
633 | # if bond-mode was changed the bond needs to be brought |
634 | # down and slaves un-slaved before bond mode is changed. | |
223ba5af | 635 | cached_bond_mode = self.cache.get_link_info_data_attribute(ifname, Link.IFLA_BOND_MODE) |
d486dd0d JF |
636 | ifla_bond_mode = ifla_info_data.get(Link.IFLA_BOND_MODE) |
637 | ||
638 | # bond-mode was changed or is not specified | |
639 | if ifla_bond_mode is not None: | |
640 | if ifla_bond_mode != cached_bond_mode: | |
641 | self.logger.info('%s: bond mode changed to %s: running ops on bond and slaves' | |
642 | % (ifname, ifla_bond_mode)) | |
643 | if is_link_up: | |
223ba5af | 644 | self.netlink.link_down(ifname) |
d486dd0d JF |
645 | is_link_up = False |
646 | ||
647 | for lower_dev in ifaceobj.lowerifaces: | |
223ba5af | 648 | self.netlink.link_set_nomaster(lower_dev) |
9808982e JF |
649 | |
650 | # when unslaving a device from an ES bond we need to set | |
651 | # protodown off | |
652 | if ifaceobj.link_privflags & ifaceLinkPrivFlags.ES_BOND: | |
653 | self.netlink.link_set_protodown_off(lower_dev) | |
654 | ||
223ba5af JF |
655 | try: |
656 | bond_slaves.remove(lower_dev) | |
3218f49d | 657 | except Exception: |
223ba5af | 658 | pass |
d486dd0d | 659 | |
d486dd0d JF |
660 | else: |
661 | # bond-mode user config value is the current running(cached) value | |
662 | # no need to reset it again we can ignore this attribute | |
663 | del ifla_info_data[Link.IFLA_BOND_MODE] | |
664 | ||
223ba5af | 665 | return is_link_up, bond_slaves |
d486dd0d JF |
666 | |
667 | def create_or_set_bond_config(self, ifaceobj): | |
668 | ifname = ifaceobj.name | |
223ba5af | 669 | link_exists, is_link_up = self.cache.link_exists_and_up(ifname) |
d486dd0d JF |
670 | ifla_info_data = self.get_ifla_bond_attr_from_user_config(ifaceobj, link_exists) |
671 | ||
672 | remove_delay_from_cache = self.check_updown_delay_nl(link_exists, ifaceobj, ifla_info_data) | |
673 | ||
674 | # if link exists: down link if specific attributes are specified | |
675 | if link_exists: | |
676 | # did bond-mode changed? | |
223ba5af JF |
677 | is_link_up, bond_slaves = self.should_update_bond_mode( |
678 | ifaceobj, | |
679 | ifname, | |
680 | is_link_up, | |
681 | ifla_info_data, | |
682 | self.cache.get_slaves(ifname) | |
683 | ) | |
d486dd0d JF |
684 | |
685 | # if specific attributes need to be set we need to down the bond first | |
686 | if ifla_info_data and is_link_up: | |
687 | if self._should_down_bond(ifla_info_data): | |
223ba5af | 688 | self.netlink.link_down_force(ifname) |
d486dd0d | 689 | is_link_up = False |
223ba5af JF |
690 | else: |
691 | bond_slaves = [] | |
d486dd0d JF |
692 | |
693 | if link_exists and not ifla_info_data: | |
694 | # if the bond already exists and no attrs need to be set | |
695 | # ignore the netlink call | |
696 | self.logger.info('%s: already exists, no change detected' % ifname) | |
697 | else: | |
698 | try: | |
223ba5af | 699 | self.netlink.link_add_bond_with_info_data(ifname, ifla_info_data) |
d486dd0d JF |
700 | except Exception as e: |
701 | # defensive code | |
702 | # if anything happens, we try to set up the bond with the sysfs api | |
703 | self.logger.debug('%s: bond setup: %s' % (ifname, str(e))) | |
704 | self.create_or_set_bond_config_sysfs(ifaceobj, ifla_info_data) | |
705 | ||
706 | if remove_delay_from_cache: | |
707 | # making sure up/down delay attributes are set to 0 before caching | |
708 | # this can be removed when moving to a nllistener/live cache | |
709 | ifla_info_data[Link.IFLA_BOND_UPDELAY] = 0 | |
710 | ifla_info_data[Link.IFLA_BOND_DOWNDELAY] = 0 | |
711 | ||
d486dd0d | 712 | if link_exists and ifla_info_data and not is_link_up: |
223ba5af JF |
713 | self.netlink.link_up_force(ifname) |
714 | ||
03813675 | 715 | return link_exists, bond_slaves |
d486dd0d JF |
716 | |
717 | def create_or_set_bond_config_sysfs(self, ifaceobj, ifla_info_data): | |
d0d657ed JF |
718 | if len(ifaceobj.name) > 15: |
719 | self.log_error("%s: cannot create bond: interface name exceeds max length of 15" % ifaceobj.name, ifaceobj) | |
720 | return | |
721 | ||
223ba5af JF |
722 | if not self.cache.link_exists(ifaceobj.name): |
723 | self.sysfs.bond_create(ifaceobj.name) | |
724 | self.sysfs.bond_set_attrs_nl(ifaceobj.name, ifla_info_data) | |
d486dd0d JF |
725 | |
726 | def _up(self, ifaceobj, ifaceobj_getfunc=None): | |
727 | try: | |
03813675 JF |
728 | link_exists, bond_slaves = self.create_or_set_bond_config(ifaceobj) |
729 | bond_slaves = self._add_slaves( | |
223ba5af JF |
730 | ifaceobj, |
731 | bond_slaves, | |
732 | ifaceobj_getfunc, | |
733 | ) | |
03813675 JF |
734 | |
735 | if not self.bond_mac_mgmt or not link_exists or ifaceobj.get_attr_value_first("hwaddress"): | |
736 | return | |
737 | ||
738 | # check if the bond mac address is correctly inherited from it's | |
739 | # first slave. There's a case where that might not be happening: | |
740 | # $ ip link show swp1 | grep ether | |
741 | # link/ether 08:00:27:04:d8:01 brd ff:ff:ff:ff:ff:ff | |
742 | # $ ip link show swp2 | grep ether | |
743 | # link/ether 08:00:27:04:d8:02 brd ff:ff:ff:ff:ff:ff | |
744 | # $ ip link add dev bond0 type bond | |
745 | # $ ip link set dev swp1 master bond0 | |
746 | # $ ip link set dev swp2 master bond0 | |
747 | # $ ip link show bond0 | grep ether | |
748 | # link/ether 08:00:27:04:d8:01 brd ff:ff:ff:ff:ff:ff | |
749 | # $ ip link add dev bond1 type bond | |
750 | # $ ip link set dev swp1 master bond1 | |
751 | # $ ip link show swp1 | grep ether | |
752 | # link/ether 08:00:27:04:d8:01 brd ff:ff:ff:ff:ff:ff | |
753 | # $ ip link show swp2 | grep ether | |
754 | # link/ether 08:00:27:04:d8:01 brd ff:ff:ff:ff:ff:ff | |
755 | # $ ip link show bond0 | grep ether | |
756 | # link/ether 08:00:27:04:d8:01 brd ff:ff:ff:ff:ff:ff | |
757 | # $ ip link show bond1 | grep ether | |
758 | # link/ether 08:00:27:04:d8:01 brd ff:ff:ff:ff:ff:ff | |
759 | # $ | |
760 | # ifupdown2 will automatically correct and fix this unexpected behavior | |
761 | bond_mac = self.cache.get_link_address(ifaceobj.name) | |
762 | ||
763 | if bond_slaves: | |
764 | first_slave_ifname = bond_slaves[0] | |
765 | first_slave_mac = self.cache.get_link_info_slave_data_attribute( | |
766 | first_slave_ifname, | |
767 | Link.IFLA_BOND_SLAVE_PERM_HWADDR | |
768 | ) | |
769 | ||
770 | if first_slave_mac and bond_mac != first_slave_mac: | |
771 | self.logger.info( | |
772 | "%s: invalid bond mac detected - resetting to %s's mac (%s)" | |
773 | % (ifaceobj.name, first_slave_ifname, first_slave_mac) | |
774 | ) | |
859b8643 | 775 | self.netlink.link_set_address(ifaceobj.name, first_slave_mac, utils.mac_str_to_int(first_slave_mac)) |
3b01ed76 | 776 | except Exception as e: |
d486dd0d JF |
777 | self.log_error(str(e), ifaceobj) |
778 | ||
779 | def _down(self, ifaceobj, ifaceobj_getfunc=None): | |
780 | try: | |
223ba5af | 781 | self.netlink.link_del(ifaceobj.name) |
d486dd0d JF |
782 | except Exception as e: |
783 | self.log_warn('%s: %s' % (ifaceobj.name, str(e))) | |
784 | ||
785 | def _query_check_bond_slaves(self, ifaceobjcurr, attr, user_bond_slaves, running_bond_slaves): | |
786 | query = 1 | |
787 | ||
788 | if user_bond_slaves and running_bond_slaves: | |
789 | if not set(user_bond_slaves).symmetric_difference(running_bond_slaves): | |
790 | query = 0 | |
791 | ||
792 | # we want to display the same bond-slaves list as provided | |
793 | # in the interfaces file but if this list contains regexes or | |
794 | # globs, for now, we won't try to change it. | |
795 | if 'regex' in user_bond_slaves or 'glob' in user_bond_slaves: | |
796 | user_bond_slaves = running_bond_slaves | |
797 | else: | |
798 | ordered = [] | |
799 | for slave in user_bond_slaves: | |
800 | if slave in running_bond_slaves: | |
801 | ordered.append(slave) | |
802 | user_bond_slaves = ordered | |
803 | ifaceobjcurr.update_config_with_status(attr, ' '.join(user_bond_slaves) if user_bond_slaves else 'None', query) | |
804 | ||
805 | def _query_check(self, ifaceobj, ifaceobjcurr, ifaceobj_getfunc=None): | |
223ba5af | 806 | if not self.cache.bond_exists(ifaceobj.name): |
d486dd0d JF |
807 | self.logger.debug('bond iface %s does not exist' % ifaceobj.name) |
808 | return | |
809 | ||
810 | iface_attrs = self.dict_key_subset(ifaceobj.config, self.get_mod_attrs()) | |
811 | if not iface_attrs: | |
812 | return | |
813 | ||
814 | # remove bond-slaves and bond-ports from the list, | |
815 | # because there aren't any ifla_info_data netlink attr for slaves | |
816 | # an exception is raised when index is not found, so query_slaves will stay False | |
817 | query_slaves = False | |
818 | ||
819 | user_bond_slaves = None | |
820 | running_bond_slaves = None | |
821 | try: | |
822 | del iface_attrs[iface_attrs.index('bond-slaves')] | |
823 | ||
824 | # if user specified bond-slaves we need to display it | |
825 | query_slaves = True | |
826 | if not user_bond_slaves: | |
827 | user_bond_slaves = self._get_slave_list(ifaceobj) | |
223ba5af | 828 | running_bond_slaves = self.cache.get_slaves(ifaceobj.name) |
d486dd0d JF |
829 | |
830 | self._query_check_bond_slaves(ifaceobjcurr, 'bond-slaves', user_bond_slaves, running_bond_slaves) | |
3218f49d | 831 | except Exception: |
d486dd0d JF |
832 | pass |
833 | try: | |
834 | del iface_attrs[iface_attrs.index('bond-ports')] | |
835 | ||
836 | # if user specified bond-ports we need to display it | |
837 | if not query_slaves and not user_bond_slaves: # if get_slave_list was already called for slaves | |
838 | user_bond_slaves = self._get_slave_list(ifaceobj) | |
223ba5af | 839 | running_bond_slaves = self.cache.get_slaves(ifaceobj.name) |
d486dd0d JF |
840 | |
841 | self._query_check_bond_slaves(ifaceobjcurr, 'bond-ports', user_bond_slaves, running_bond_slaves) | |
3218f49d | 842 | except Exception: |
d486dd0d JF |
843 | pass |
844 | ||
845 | for attr in iface_attrs: | |
846 | nl_attr = self._bond_attr_netlink_map[attr] | |
847 | translate_func = self._bond_attr_ifquery_check_translate_func[nl_attr] | |
223ba5af | 848 | current_config = self.cache.get_link_info_data_attribute(ifaceobj.name, nl_attr) |
d486dd0d JF |
849 | user_config = ifaceobj.get_attr_value_first(attr) |
850 | ||
851 | if current_config == translate_func(user_config): | |
852 | ifaceobjcurr.update_config_with_status(attr, user_config, 0) | |
853 | else: | |
854 | ifaceobjcurr.update_config_with_status(attr, str(current_config), 1) | |
855 | ||
856 | @staticmethod | |
857 | def translate_nl_value_yesno(value): | |
858 | return 'yes' if value else 'no' | |
859 | ||
860 | @staticmethod | |
861 | def translate_nl_value_slowfast(value): | |
862 | return 'fast' if value else 'slow' | |
863 | ||
864 | def _query_running_attrs(self, bondname): | |
223ba5af JF |
865 | cached_vxlan_ifla_info_data = self.cache.get_link_info_data(bondname) |
866 | ||
d486dd0d | 867 | bond_attrs = { |
223ba5af JF |
868 | 'bond-mode': Link.ifla_bond_mode_pretty_tbl.get(cached_vxlan_ifla_info_data.get(Link.IFLA_BOND_MODE)), |
869 | 'bond-miimon': cached_vxlan_ifla_info_data.get(Link.IFLA_BOND_MIIMON), | |
870 | 'bond-use-carrier': self.translate_nl_value_yesno(cached_vxlan_ifla_info_data.get(Link.IFLA_BOND_USE_CARRIER)), | |
871 | 'bond-lacp-rate': self.translate_nl_value_slowfast(cached_vxlan_ifla_info_data.get(Link.IFLA_BOND_AD_LACP_RATE)), | |
872 | 'bond-min-links': cached_vxlan_ifla_info_data.get(Link.IFLA_BOND_MIN_LINKS), | |
873 | 'bond-ad-actor-system': cached_vxlan_ifla_info_data.get(Link.IFLA_BOND_AD_ACTOR_SYSTEM), | |
9808982e | 874 | 'es-sys-mac': cached_vxlan_ifla_info_data.get(Link.IFLA_BOND_AD_ACTOR_SYSTEM), |
223ba5af JF |
875 | 'bond-ad-actor-sys-prio': cached_vxlan_ifla_info_data.get(Link.IFLA_BOND_AD_ACTOR_SYS_PRIO), |
876 | '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)), | |
877 | 'bond-lacp-bypass-allow': self.translate_nl_value_yesno(cached_vxlan_ifla_info_data.get(Link.IFLA_BOND_AD_LACP_BYPASS)), | |
878 | 'bond-num-unsol-na': cached_vxlan_ifla_info_data.get(Link.IFLA_BOND_NUM_PEER_NOTIF), | |
879 | 'bond-num-grat-arp': cached_vxlan_ifla_info_data.get(Link.IFLA_BOND_NUM_PEER_NOTIF), | |
880 | 'bond-updelay': cached_vxlan_ifla_info_data.get(Link.IFLA_BOND_UPDELAY), | |
881 | 'bond-downdelay': cached_vxlan_ifla_info_data.get(Link.IFLA_BOND_DOWNDELAY) | |
d486dd0d | 882 | } |
223ba5af JF |
883 | |
884 | cached_bond_primary = cached_vxlan_ifla_info_data.get(Link.IFLA_BOND_PRIMARY) | |
885 | if cached_bond_primary: | |
886 | bond_attrs['bond-primary'] = self.cache.get_ifname(cached_bond_primary) | |
887 | ||
888 | slaves = self.cache.get_slaves(bondname) | |
d486dd0d JF |
889 | if slaves: |
890 | bond_attrs['bond-slaves'] = slaves | |
891 | return bond_attrs | |
892 | ||
893 | def _query_running(self, ifaceobjrunning, ifaceobj_getfunc=None): | |
223ba5af | 894 | if not self.cache.bond_exists(ifaceobjrunning.name): |
d486dd0d JF |
895 | return |
896 | bond_attrs = self._query_running_attrs(ifaceobjrunning.name) | |
897 | if bond_attrs.get('bond-slaves'): | |
898 | bond_attrs['bond-slaves'] = ' '.join(bond_attrs.get('bond-slaves')) | |
899 | ||
900 | [ifaceobjrunning.update_config(k, str(v)) | |
3b01ed76 | 901 | for k, v in list(bond_attrs.items()) |
d486dd0d JF |
902 | if v is not None] |
903 | ||
904 | _run_ops = { | |
905 | 'pre-up': _up, | |
906 | 'post-down': _down, | |
907 | 'query-running': _query_running, | |
908 | 'query-checkcurr': _query_check | |
909 | } | |
910 | ||
911 | def get_ops(self): | |
912 | """ returns list of ops supported by this module """ | |
3b01ed76 | 913 | return list(self._run_ops.keys()) |
d486dd0d | 914 | |
d486dd0d JF |
915 | def run(self, ifaceobj, operation, query_ifaceobj=None, |
916 | ifaceobj_getfunc=None): | |
917 | """ run bond configuration on the interface object passed as argument | |
918 | ||
919 | Args: | |
920 | **ifaceobj** (object): iface object | |
921 | ||
922 | **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr', | |
923 | 'query-running' | |
924 | ||
925 | Kwargs: | |
926 | **query_ifaceobj** (object): query check ifaceobject. This is only | |
927 | valid when op is 'query-checkcurr'. It is an object same as | |
928 | ifaceobj, but contains running attribute values and its config | |
929 | status. The modules can use it to return queried running state | |
930 | of interfaces. status is success if the running state is same | |
931 | as user required state in ifaceobj. error otherwise. | |
932 | """ | |
933 | op_handler = self._run_ops.get(operation) | |
934 | if not op_handler: | |
935 | return | |
936 | if operation != 'query-running' and not self._is_bond(ifaceobj): | |
937 | return | |
d486dd0d JF |
938 | if operation == 'query-checkcurr': |
939 | op_handler(self, ifaceobj, query_ifaceobj, | |
940 | ifaceobj_getfunc=ifaceobj_getfunc) | |
941 | else: | |
942 | op_handler(self, ifaceobj, ifaceobj_getfunc=ifaceobj_getfunc) |