3 # Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
4 # Author: Roopa Prabhu, roopa@cumulusnetworks.com
5 # Julien Fortin, julien@cumulusnetworks.com
15 from ipaddr
import IPNetwork
, IPv6Network
18 import ifupdown2
.ifupdown
.statemanager
as statemanager
19 import ifupdown2
.ifupdown
.ifupdownflags
as ifupdownflags
21 from ifupdown2
.nlmanager
.nlmanager
import Link
, Route
23 from ifupdown2
.ifupdown
.iface
import *
24 from ifupdown2
.ifupdown
.utils
import utils
25 from ifupdown2
.ifupdown
.netlink
import netlink
27 from ifupdown2
.ifupdownaddons
.utilsbase
import utilsBase
28 from ifupdown2
.ifupdownaddons
.cache
import linkCache
, MSTPAttrsCache
30 import ifupdown
.ifupdownflags
as ifupdownflags
31 import ifupdown
.statemanager
as statemanager
33 from nlmanager
.nlmanager
import Link
, Route
35 from ifupdown
.iface
import *
36 from ifupdown
.utils
import utils
37 from ifupdown
.netlink
import netlink
39 from ifupdownaddons
.utilsbase
import utilsBase
40 from ifupdownaddons
.cache
import linkCache
, MSTPAttrsCache
43 class LinkUtils(utilsBase
):
45 This class contains helper methods to cache and manipulate interfaces through
46 non-netlink APIs (sysfs, iproute2, brctl...)
48 _CACHE_FILL_DONE
= False
55 bridge_utils_is_installed
= os
.path
.exists(utils
.brctl_cmd
)
56 bridge_utils_missing_warning
= True
58 def __init__(self
, *args
, **kargs
):
59 utilsBase
.__init
__(self
, *args
, **kargs
)
61 self
.supported_command
= {
62 '%s -c -json vlan show' % utils
.bridge_cmd
: True,
65 self
.bridge_vlan_cache
= {}
66 self
.bridge_vlan_cache_fill_done
= False
68 if not ifupdownflags
.flags
.PERFMODE
and not LinkUtils
._CACHE
_FILL
_DONE
:
73 LinkUtils
._CACHE
_FILL
_DONE
= False
74 LinkUtils
.ipbatchbuf
= ''
75 LinkUtils
.ipbatch
= False
76 LinkUtils
.ipbatch_pause
= False
78 def _fill_cache(self
):
79 if not LinkUtils
._CACHE
_FILL
_DONE
:
82 LinkUtils
._CACHE
_FILL
_DONE
= True
87 def _get_vland_id(citems
, i
, warn
):
90 index
= sub
.index('id')
95 raise Exception('invalid use of \'vlan\' keyword')
98 def _link_fill(self
, ifacename
=None, refresh
=False):
99 """ fills cache with link information
101 if ifacename argument given, fill cache for ifacename, else
102 fill cache for all interfaces in the system
105 if LinkUtils
._CACHE
_FILL
_DONE
and not refresh
:
108 # if ifacename already present, return
109 if (ifacename
and not refresh
and
110 linkCache
.get_attr([ifacename
, 'ifflag'])):
117 [linkCache
.update_attrdict([ifname
], linkattrs
)
118 for ifname
, linkattrs
in netlink
.link_dump(ifacename
).items()]
119 except Exception as e
:
120 self
.logger
.info('%s' % str(e
))
121 # this netlink call replaces the call to _link_fill_iproute2_cmd()
122 # We shouldn't have netlink calls in the iproute2 module, this will
123 # be removed in the future. We plan to release, a flexible backend
124 # (netlink+iproute2) by default we will use netlink backend but with
125 # a CLI arg we can switch to iproute2 backend.
126 # Until we decide to create this "backend" switch capability,
127 # we have to put the netlink call inside the iproute2 module.
129 self
._link
_fill
_iproute
2_cmd
(ifacename
, refresh
)
131 self
._fill
_bond
_info
(ifacename
)
132 self
._fill
_bridge
_info
(ifacename
)
134 def _fill_bridge_info(self
, ifacename
):
140 cache_dict
= {ifacename
: linkCache
.links
.get(ifacename
, {})}
142 cache_dict
= linkCache
.links
144 for ifname
, obj
in cache_dict
.items():
145 slave_kind
= obj
.get('slave_kind')
146 if not slave_kind
and slave_kind
!= 'bridge':
149 info_slave_data
= obj
.get('info_slave_data')
150 if not info_slave_data
:
153 ifla_master
= obj
.get('master')
155 raise Exception('No master associated with bridge port %s' % ifname
)
158 Link
.IFLA_BRPORT_STATE
,
159 Link
.IFLA_BRPORT_COST
,
160 Link
.IFLA_BRPORT_PRIORITY
,
162 if nl_attr
not in info_slave_data
and LinkUtils
.bridge_utils_is_installed
:
163 self
._fill
_bridge
_info
_brctl
()
167 'pathcost': str(info_slave_data
.get(Link
.IFLA_BRPORT_COST
, 0)),
168 'fdelay': format(float(info_slave_data
.get(Link
.IFLA_BRPORT_FORWARD_DELAY_TIMER
, 0) / 100), '.2f'),
169 'portmcrouter': str(info_slave_data
.get(Link
.IFLA_BRPORT_MULTICAST_ROUTER
, 0)),
170 'portmcfl': str(info_slave_data
.get(Link
.IFLA_BRPORT_FAST_LEAVE
, 0)),
171 'portprio': str(info_slave_data
.get(Link
.IFLA_BRPORT_PRIORITY
, 0)),
172 'unicast-flood': str(info_slave_data
.get(Link
.IFLA_BRPORT_UNICAST_FLOOD
, 0)),
173 'multicast-flood': str(info_slave_data
.get(Link
.IFLA_BRPORT_MCAST_FLOOD
, 0)),
174 'learning': str(info_slave_data
.get(Link
.IFLA_BRPORT_LEARNING
, 0)),
175 'arp-nd-suppress': str(info_slave_data
.get(Link
.IFLA_BRPORT_ARP_SUPPRESS
, 0))
178 if ifla_master
in brports
:
179 brports
[ifla_master
][ifname
] = brport_attrs
181 brports
[ifla_master
] = {ifname
: brport_attrs
}
183 linkCache
.update_attrdict([ifla_master
, 'linkinfo', 'ports'], brports
[ifla_master
])
185 if LinkUtils
.bridge_utils_is_installed
:
186 self
._fill
_bridge
_info
_brctl
()
188 def _fill_bridge_info_brctl(self
):
189 brctlout
= utils
.exec_command('%s show' % utils
.brctl_cmd
)
193 for bline
in brctlout
.splitlines()[1:]:
194 bitems
= bline
.split()
198 linkCache
.update_attrdict([bitems
[0], 'linkinfo'],
201 linkCache
.update_attrdict([bitems
[0]],
202 {'linkinfo': {'stp': bitems
[2]}})
203 self
._bridge
_attrs
_fill
(bitems
[0])
205 def _bridge_attrs_fill(self
, bridgename
):
209 brout
= utils
.exec_command('%s showstp %s' % (utils
.brctl_cmd
, bridgename
))
210 chunks
= re
.split(r
'\n\n', brout
, maxsplit
=0, flags
=re
.MULTILINE
)
213 # Get all bridge attributes
214 broutlines
= chunks
[0].splitlines()
215 # battrs['pathcost'] = broutlines[3].split('path cost')[1].strip()
218 battrs
['maxage'] = broutlines
[4].split('bridge max age')[
219 1].strip().replace('.00', '')
224 battrs
['hello'] = broutlines
[5].split('bridge hello time')[
225 1].strip().replace('.00', '')
230 battrs
['fd'] = broutlines
[6].split('bridge forward delay')[
231 1].strip().replace('.00', '')
236 battrs
['ageing'] = broutlines
[7].split('ageing time')[
237 1].strip().replace('.00', '')
242 battrs
['mcrouter'] = broutlines
[12].split('mc router')[
243 1].strip().split('\t\t\t')[0]
248 battrs
['bridgeprio'] = self
.read_file_oneline(
249 '/sys/class/net/%s/bridge/priority' % bridgename
)
254 battrs
['vlan-protocol'] = VlanProtocols
.ID_TO_ETHERTYPES
[
255 self
.read_file_oneline(
256 '/sys/class/net/%s/bridge/vlan_protocol' % bridgename
)]
261 battrs
.update(self
._bridge
_get
_mcattrs
_from
_sysfs
(bridgename
))
265 # XXX: comment this out until mc attributes become available
267 # battrs['hashel'] = broutlines[10].split('hash elasticity')[1].split()[0].strip()
268 # battrs['hashmax'] = broutlines[10].split('hash max')[1].strip()
269 # battrs['mclmc'] = broutlines[11].split('mc last member count')[1].split()[0].strip()
270 # battrs['mciqc'] = broutlines[11].split('mc init query count')[1].strip()
271 # battrs['mcrouter'] = broutlines[12].split('mc router')[1].split()[0].strip()
272 ##battrs['mcsnoop'] = broutlines[12].split('mc snooping')[1].strip()
273 # battrs['mclmt'] = broutlines[13].split('mc last member timer')[1].split()[0].strip()
275 self
.logger
.warn('%s: error while processing bridge attributes: %s' % (bridgename
, str(e
)))
278 linkCache
.update_attrdict([bridgename
, 'linkinfo'], battrs
)
279 for cidx
in range(1, len(chunks
)):
280 bpout
= chunks
[cidx
].lstrip('\n')
281 if not bpout
or bpout
[0] == ' ':
283 bplines
= bpout
.splitlines()
284 pname
= bplines
[0].split()[0]
287 bportattrs
['pathcost'] = bplines
[2].split(
288 'path cost')[1].strip()
289 bportattrs
['fdelay'] = bplines
[4].split(
290 'forward delay timer')[1].strip()
291 bportattrs
['portmcrouter'] = self
.read_file_oneline(
292 '/sys/class/net/%s/brport/multicast_router' % pname
)
293 bportattrs
['portmcfl'] = self
.read_file_oneline(
294 '/sys/class/net/%s/brport/multicast_fast_leave' % pname
)
295 bportattrs
['portprio'] = self
.read_file_oneline(
296 '/sys/class/net/%s/brport/priority' % pname
)
297 bportattrs
['unicast-flood'] = self
.read_file_oneline(
298 '/sys/class/net/%s/brport/unicast_flood' % pname
)
299 bportattrs
['multicast-flood'] = self
.read_file_oneline(
300 '/sys/class/net/%s/brport/multicast_flood' % pname
)
301 bportattrs
['learning'] = self
.read_file_oneline(
302 '/sys/class/net/%s/brport/learning' % pname
)
303 bportattrs
['arp-nd-suppress'] = self
.read_file_oneline(
304 '/sys/class/net/%s/brport/neigh_suppress' % pname
)
305 # bportattrs['mcrouters'] = bplines[6].split('mc router')[1].split()[0].strip()
306 # bportattrs['mc fast leave'] = bplines[6].split('mc fast leave')[1].strip()
308 self
.logger
.warn('%s: error while processing bridge attributes: %s' % (bridgename
, str(e
)))
309 bports
[pname
] = bportattrs
310 linkCache
.update_attrdict([bridgename
, 'linkinfo', 'ports'], bports
)
312 _bridge_sysfs_mcattrs
= {
313 'mclmc': 'multicast_last_member_count',
314 'mcrouter': 'multicast_router',
315 'mcsnoop': 'multicast_snooping',
316 'mcsqc': 'multicast_startup_query_count',
317 'mcqifaddr': 'multicast_query_use_ifaddr',
318 'mcquerier': 'multicast_querier',
319 'hashel': 'hash_elasticity',
320 'hashmax': 'hash_max',
321 'mclmi': 'multicast_last_member_interval',
322 'mcmi': 'multicast_membership_interval',
323 'mcqpi': 'multicast_querier_interval',
324 'mcqi': 'multicast_query_interval',
325 'mcqri': 'multicast_query_response_interval',
326 'mcsqi': 'multicast_startup_query_interval',
327 'igmp-version': 'multicast_igmp_version',
328 'mld-version': 'multicast_mld_version',
329 'vlan-stats': 'vlan_stats_enabled',
330 'mcstats': 'multicast_stats_enabled',
333 def _bridge_get_mcattrs_from_sysfs(self
, bridgename
):
334 mcattrsdivby100
= ['mclmi', 'mcmi', 'mcqpi', 'mcqi', 'mcqri', 'mcsqi']
337 for m
, s
in self
._bridge
_sysfs
_mcattrs
.items():
338 n
= self
.read_file_oneline('/sys/class/net/%s/bridge/%s' % (bridgename
, s
))
339 if m
in mcattrsdivby100
:
344 self
.logger
.warn('error getting mc attr %s (%s)' % (m
, str(e
)))
350 def _fill_bond_info(self
, ifacename
):
351 bonding_masters
= self
.read_file_oneline('/sys/class/net/bonding_masters')
352 if not bonding_masters
:
355 bond_masters_list
= bonding_masters
.split()
358 if ifacename
in bond_masters_list
:
359 bond_masters_list
= [ifacename
]
361 # we want to refresh this interface only if it's a bond master
364 for bondname
in bond_masters_list
:
366 if bondname
not in linkCache
.links
:
367 linkCache
.set_attr([bondname
], {'linkinfo': {}})
368 linkCache
.set_attr([bondname
, 'linkinfo', 'slaves'],
369 self
.read_file_oneline('/sys/class/net/%s/bonding/slaves'
372 # if some attribute are missing we try to get the bond attributes via sysfs
373 bond_linkinfo
= linkCache
.links
[bondname
]['linkinfo']
374 for attr
in [Link
.IFLA_BOND_MODE
, Link
.IFLA_BOND_XMIT_HASH_POLICY
, Link
.IFLA_BOND_MIN_LINKS
]:
375 if attr
not in bond_linkinfo
:
376 self
._fill
_bond
_info
_sysfs
(bondname
)
377 # after we fill in the cache we can continue to the next bond
380 self
._fill
_bond
_info
_sysfs
(bondname
)
382 except Exception as e
:
383 self
.logger
.debug('LinkUtils: bond cache error: %s' % str(e
))
385 def _fill_bond_info_sysfs(self
, bondname
):
387 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_MIN_LINKS
],
388 self
.read_file_oneline(
389 '/sys/class/net/%s/bonding/min_links'
391 except Exception as e
:
392 self
.logger
.debug(str(e
))
395 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_MODE
],
396 self
.read_file_oneline('/sys/class/net/%s/bonding/mode'
397 % bondname
).split()[0])
398 except Exception as e
:
399 self
.logger
.debug(str(e
))
401 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_XMIT_HASH_POLICY
],
402 self
.read_file_oneline(
403 '/sys/class/net/%s/bonding/xmit_hash_policy'
404 % bondname
).split()[0])
405 except Exception as e
:
406 self
.logger
.debug(str(e
))
408 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_LACP_RATE
],
409 self
.read_file_oneline('/sys/class/net/%s/bonding/lacp_rate'
410 % bondname
).split()[1])
411 except Exception as e
:
412 self
.logger
.debug(str(e
))
414 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_ACTOR_SYS_PRIO
],
415 self
.read_file_oneline('/sys/class/net/%s/bonding/ad_actor_sys_prio'
417 except Exception as e
:
418 self
.logger
.debug(str(e
))
420 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_ACTOR_SYSTEM
],
421 self
.read_file_oneline('/sys/class/net/%s/bonding/ad_actor_system'
423 except Exception as e
:
424 self
.logger
.debug(str(e
))
426 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_LACP_BYPASS
],
427 self
.read_file_oneline('/sys/class/net/%s/bonding/lacp_bypass'
428 % bondname
).split()[1])
429 except Exception as e
:
430 self
.logger
.debug(str(e
))
432 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_UPDELAY
],
433 self
.read_file_oneline('/sys/class/net/%s/bonding/updelay'
435 except Exception as e
:
436 self
.logger
.debug(str(e
))
438 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_DOWNDELAY
],
439 self
.read_file_oneline('/sys/class/net/%s/bonding/downdelay'
441 except Exception as e
:
442 self
.logger
.debug(str(e
))
445 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_USE_CARRIER
],
446 self
.read_file_oneline('/sys/class/net/%s/bonding/use_carrier' % bondname
))
447 except Exception as e
:
448 self
.logger
.debug(str(e
))
451 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_MIIMON
],
452 self
.read_file_oneline('/sys/class/net/%s/bonding/miimon' % bondname
))
453 except Exception as e
:
454 self
.logger
.debug(str(e
))
457 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_NUM_PEER_NOTIF
],
458 self
.read_file_oneline('/sys/class/net/%s/bonding/num_unsol_na' % bondname
))
459 except Exception as e
:
460 self
.logger
.debug(str(e
))
463 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_NUM_PEER_NOTIF
],
464 self
.read_file_oneline('/sys/class/net/%s/bonding/num_grat_arp' % bondname
))
465 except Exception as e
:
466 self
.logger
.debug(str(e
))
469 def _link_fill_iproute2_cmd(self
, ifacename
=None, refresh
=False):
472 if LinkUtils
._CACHE
_FILL
_DONE
and not refresh
:
475 # if ifacename already present, return
476 if (ifacename
and not refresh
and
477 linkCache
.get_attr([ifacename
, 'ifflag'])):
481 cmdout
= self
.link_show(ifacename
=ifacename
)
484 for c
in cmdout
.splitlines():
486 ifnamenlink
= citems
[1].split('@')
487 if len(ifnamenlink
) > 1:
488 ifname
= ifnamenlink
[0]
489 iflink
= ifnamenlink
[1].strip(':')
491 ifname
= ifnamenlink
[0].strip(':')
494 linkattrs
['link'] = iflink
495 linkattrs
['ifindex'] = citems
[0].strip(':')
496 flags
= citems
[2].strip('<>').split(',')
497 linkattrs
['flags'] = flags
498 linkattrs
['ifflag'] = 'UP' if 'UP' in flags
else 'DOWN'
499 for i
in range(0, len(citems
)):
501 if citems
[i
] == 'mtu':
502 linkattrs
['mtu'] = citems
[i
+ 1]
503 elif citems
[i
] == 'state':
504 linkattrs
['state'] = citems
[i
+ 1]
505 elif citems
[i
] == 'link/ether':
506 linkattrs
['hwaddress'] = citems
[i
+ 1]
507 elif citems
[i
] == 'vlan':
508 vlanid
= self
._get
_vland
_id
(citems
, i
, warn
)
510 linkattrs
['linkinfo'] = {'vlanid': vlanid
}
511 linkattrs
['kind'] = 'vlan'
512 elif citems
[i
] == 'dummy':
513 linkattrs
['kind'] = 'dummy'
514 elif citems
[i
] == 'vxlan' and citems
[i
+ 1] == 'id':
515 linkattrs
['kind'] = 'vxlan'
516 vattrs
= {'vxlanid': citems
[i
+ 2],
519 'ageing': citems
[i
+ 2],
521 for j
in range(i
+ 2, len(citems
)):
522 if citems
[j
] == 'local':
523 vattrs
['local'] = citems
[j
+ 1]
524 elif citems
[j
] == 'remote':
525 vattrs
['svcnode'] = citems
[j
+ 1]
526 elif citems
[j
] == 'ageing':
527 vattrs
['ageing'] = citems
[j
+ 1]
528 elif citems
[j
] == 'nolearning':
529 vattrs
['learning'] = 'off'
530 linkattrs
['linkinfo'] = vattrs
532 elif citems
[i
] == 'vrf' and citems
[i
+ 1] == 'table':
533 vattrs
= {'table': citems
[i
+ 2]}
534 linkattrs
['linkinfo'] = vattrs
535 linkattrs
['kind'] = 'vrf'
536 linkCache
.vrfs
[ifname
] = vattrs
538 elif citems
[i
] == 'veth':
539 linkattrs
['kind'] = 'veth'
540 elif citems
[i
] == 'vrf_slave':
541 linkattrs
['slave_kind'] = 'vrf_slave'
543 elif citems
[i
] == 'macvlan' and citems
[i
+ 1] == 'mode':
544 linkattrs
['kind'] = 'macvlan'
545 except Exception as e
:
547 self
.logger
.debug('%s: parsing error: id, mtu, state, '
548 'link/ether, vlan, dummy, vxlan, local, '
549 'remote, ageing, nolearning, vrf, table, '
550 'vrf_slave are reserved keywords: %s' %
553 # linkattrs['alias'] = self.read_file_oneline(
554 # '/sys/class/net/%s/ifalias' %ifname)
555 linkout
[ifname
] = linkattrs
556 [linkCache
.update_attrdict([ifname
], linkattrs
)
557 for ifname
, linkattrs
in linkout
.items()]
560 def _addr_filter(ifname
, addr
, scope
=None):
561 default_addrs
= ['127.0.0.1/8', '::1/128', '0.0.0.0']
562 if ifname
== 'lo' and addr
in default_addrs
:
564 if scope
and scope
== 'link':
568 def _addr_fill(self
, ifacename
=None, refresh
=False):
569 """ fills cache with address information
571 if ifacename argument given, fill cache for ifacename, else
572 fill cache for all interfaces in the system
574 if LinkUtils
._CACHE
_FILL
_DONE
and not refresh
:
577 # Check if ifacename is already full, in which case, return
578 if ifacename
and not refresh
:
579 linkCache
.get_attr([ifacename
, 'addrs'])
586 [linkCache
.update_attrdict([ifname
], linkattrs
)
587 for ifname
, linkattrs
in netlink
.addr_dump(ifname
=ifacename
).items()]
588 except Exception as e
:
589 self
.logger
.info(str(e
))
591 # this netlink call replaces the call to _addr_fill_iproute2_cmd()
592 # We shouldn't have netlink calls in the iproute2 module, this will
593 # be removed in the future. We plan to release, a flexible backend
594 # (netlink+iproute2) by default we will use netlink backend but with
595 # a CLI arg we can switch to iproute2 backend.
596 # Until we decide to create this "backend" switch capability,
597 # we have to put the netlink call inside the iproute2 module.
600 self
._addr
_fill
_iproute
2_cmd
(ifacename
, refresh
)
602 def _addr_fill_iproute2_cmd(self
, ifacename
=None, refresh
=False):
603 """ fills cache with address information
605 if ifacename argument given, fill cache for ifacename, else
606 fill cache for all interfaces in the system
609 if LinkUtils
._CACHE
_FILL
_DONE
and not refresh
:
612 # Check if ifacename is already full, in which case, return
613 if ifacename
and not refresh
:
614 linkCache
.get_attr([ifacename
, 'addrs'])
618 cmdout
= self
.addr_show(ifacename
=ifacename
)
621 for c
in cmdout
.splitlines():
623 ifnamenlink
= citems
[1].split('@')
624 if len(ifnamenlink
) > 1:
625 ifname
= ifnamenlink
[0]
627 ifname
= ifnamenlink
[0].strip(':')
628 if not linkout
.get(ifname
):
630 linkattrs
['addrs'] = OrderedDict({})
632 linkout
[ifname
].update(linkattrs
)
634 linkout
[ifname
] = linkattrs
635 if citems
[2] == 'inet':
636 if self
._addr
_filter
(ifname
, citems
[3], scope
=citems
[5]):
639 addrattrs
['scope'] = citems
[5]
640 addrattrs
['type'] = 'inet'
641 linkout
[ifname
]['addrs'][citems
[3]] = addrattrs
642 elif citems
[2] == 'inet6':
643 if self
._addr
_filter
(ifname
, citems
[3], scope
=citems
[5]):
645 if citems
[5] == 'link':
646 continue # skip 'link' addresses
648 addrattrs
['scope'] = citems
[5]
649 addrattrs
['type'] = 'inet6'
650 linkout
[ifname
]['addrs'][citems
[3]] = addrattrs
651 [linkCache
.update_attrdict([ifname
], linkattrs
)
652 for ifname
, linkattrs
in linkout
.items()]
654 def cache_get(self
, t
, attrlist
, refresh
=False):
655 return self
._cache
_get
(t
, attrlist
, refresh
)
657 def _cache_get(self
, t
, attrlist
, refresh
=False):
659 if ifupdownflags
.flags
.DRYRUN
:
661 if ifupdownflags
.flags
.CACHE
:
662 if self
._fill
_cache
():
663 # if we filled the cache, return new data
664 return linkCache
.get_attr(attrlist
)
666 return linkCache
.get_attr(attrlist
)
668 self
._link
_fill
(attrlist
[0], refresh
)
670 self
._addr
_fill
(attrlist
[0], refresh
)
672 self
._link
_fill
(attrlist
[0], refresh
)
673 self
._addr
_fill
(attrlist
[0], refresh
)
674 return linkCache
.get_attr(attrlist
)
676 self
.logger
.debug('_cache_get(%s) : [%s]' % (str(attrlist
), str(e
)))
679 def cache_check(self
, attrlist
, value
, refresh
=False):
680 return self
._cache
_check
('link', attrlist
, value
, refresh
=refresh
)
682 def _cache_check(self
, t
, attrlist
, value
, refresh
=False):
684 return self
._cache
_get
(t
, attrlist
, refresh
) == value
686 self
.logger
.debug('_cache_check(%s) : [%s]'
687 % (str(attrlist
), str(e
)))
690 def cache_update(self
, attrlist
, value
):
691 return self
._cache
_update
(attrlist
, value
)
694 def _cache_update(attrlist
, value
):
695 if ifupdownflags
.flags
.DRYRUN
:
698 if attrlist
[-1] == 'slaves':
699 linkCache
.append_to_attrlist(attrlist
, value
)
701 linkCache
.set_attr(attrlist
, value
)
706 def _cache_delete(attrlist
, value
=None):
707 if ifupdownflags
.flags
.DRYRUN
:
711 linkCache
.remove_from_attrlist(attrlist
, value
)
713 linkCache
.del_attr(attrlist
)
718 def _cache_invalidate():
719 linkCache
.invalidate()
720 LinkUtils
._CACHE
_FILL
_DONE
= False
724 LinkUtils
.ipbatcbuf
= ''
725 LinkUtils
.ipbatch
= True
726 LinkUtils
.ipbatch_pause
= False
729 def add_to_batch(cmd
):
730 LinkUtils
.ipbatchbuf
+= cmd
+ '\n'
734 LinkUtils
.ipbatch_pause
= True
738 LinkUtils
.ipbatch_pause
= False
740 def batch_commit(self
):
741 if not LinkUtils
.ipbatchbuf
:
742 LinkUtils
.ipbatchbuf
= ''
743 LinkUtils
.ipbatch
= False
744 LinkUtils
.ipbatch_pause
= False
747 utils
.exec_command('%s -force -batch -' % utils
.ip_cmd
,
748 stdin
=self
.ipbatchbuf
)
752 LinkUtils
.ipbatchbuf
= ''
753 LinkUtils
.ipbatch
= False
754 LinkUtils
.ipbatch_pause
= False
756 def bridge_batch_commit(self
):
757 if not LinkUtils
.ipbatchbuf
:
758 LinkUtils
.ipbatchbuf
= ''
759 LinkUtils
.ipbatch
= False
760 LinkUtils
.ipbatch_pause
= False
763 utils
.exec_command('%s -force -batch -'
764 % utils
.bridge_cmd
, stdin
=self
.ipbatchbuf
)
768 LinkUtils
.ipbatchbuf
= ''
769 LinkUtils
.ipbatch
= False
770 LinkUtils
.ipbatch_pause
= False
772 def addr_show(self
, ifacename
=None):
774 if not self
.link_exists(ifacename
):
776 return utils
.exec_commandl([utils
.ip_cmd
,
777 '-o', 'addr', 'show', 'dev', ifacename
])
779 return utils
.exec_commandl([utils
.ip_cmd
,
780 '-o', 'addr', 'show'])
783 def link_show(ifacename
=None):
785 return utils
.exec_commandl([utils
.ip_cmd
,
786 '-o', '-d', 'link', 'show', 'dev', ifacename
])
788 return utils
.exec_commandl([utils
.ip_cmd
,
789 '-o', '-d', 'link', 'show'])
791 def addr_add(self
, ifacename
, address
, broadcast
=None,
792 peer
=None, scope
=None, preferred_lifetime
=None):
795 cmd
= 'addr add %s' % address
797 cmd
+= ' broadcast %s' % broadcast
799 cmd
+= ' peer %s' % peer
801 cmd
+= ' scope %s' % scope
802 if preferred_lifetime
:
803 cmd
+= ' preferred_lft %s' % preferred_lifetime
804 cmd
+= ' dev %s' % ifacename
805 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
806 self
.add_to_batch(cmd
)
808 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
809 self
._cache
_update
([ifacename
, 'addrs', address
], {})
811 def addr_del(self
, ifacename
, address
, broadcast
=None,
812 peer
=None, scope
=None):
813 """ Delete ipv4 address """
816 if not self
._cache
_get
('addr', [ifacename
, 'addrs', address
]):
818 cmd
= 'addr del %s' % address
820 cmd
+= 'broadcast %s' % broadcast
822 cmd
+= 'peer %s' % peer
824 cmd
+= 'scope %s' % scope
825 cmd
+= ' dev %s' % ifacename
826 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
827 self
._cache
_delete
([ifacename
, 'addrs', address
])
829 def addr_flush(self
, ifacename
):
830 cmd
= 'addr flush dev %s' % ifacename
831 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
832 self
.add_to_batch(cmd
)
834 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
835 self
._cache
_delete
([ifacename
, 'addrs'])
837 def del_addr_all(self
, ifacename
, skip_addrs
=[]):
840 runningaddrsdict
= self
.get_running_addrs(ifname
=ifacename
)
842 # XXX: ignore errors. Fix this to delete secondary addresses
844 [self
.addr_del(ifacename
, a
) for a
in
845 set(runningaddrsdict
.keys()).difference(skip_addrs
)]
850 def addr_get(self
, ifacename
, details
=True, refresh
=False):
851 addrs
= self
._cache
_get
('addr', [ifacename
, 'addrs'], refresh
=refresh
)
858 def get_running_addrs(self
, ifaceobj
=None, ifname
=None, details
=True, addr_virtual_ifaceobj
=None):
860 We now support addr with link scope. Since the kernel may add it's
861 own link address to some interfaces we need to filter them out and
862 make sure we only deal with the addresses set by ifupdown2.
864 To do so we look at the previous configuration made by ifupdown2
865 (with the help of the statemanager) together with the addresses
866 specified by the user in /etc/network/interfaces, these addresses
867 are then compared to the running state of the intf (ip addr show)
868 made via a netlink addr dump.
869 For each configured addresses of scope link, we check if it was
870 previously configured by ifupdown2 to create a final set of the
871 addresses watched by ifupdown2
873 if not ifaceobj
and not ifname
:
879 interface_name
= ifaceobj
.name
881 interface_name
= ifname
883 if addr_virtual_ifaceobj
:
884 for virtual
in addr_virtual_ifaceobj
.get_attr_value('address-virtual') or []:
885 for ip
in virtual
.split():
892 saved_ifaceobjs
= statemanager
.statemanager_api
.get_ifaceobjs(addr_virtual_ifaceobj
.name
)
893 for saved_ifaceobj
in saved_ifaceobjs
or []:
894 for virtual
in saved_ifaceobj
.get_attr_value('address-virtual') or []:
895 for ip
in virtual
.split():
903 for addr
in ifaceobj
.get_attr_value('address') or []:
904 config_addrs
.add(addr
)
906 saved_ifaceobjs
= statemanager
.statemanager_api
.get_ifaceobjs(interface_name
)
907 for saved_ifaceobj
in saved_ifaceobjs
or []:
908 for addr
in saved_ifaceobj
.get_attr_value('address') or []:
909 config_addrs
.add(addr
)
911 running_addrs
= OrderedDict()
912 cached_addrs
= self
.addr_get(interface_name
)
914 for addr
, addr_details
in cached_addrs
.items():
916 scope
= int(addr_details
['scope'])
920 addr_obj
= IPNetwork(addr
)
921 if isinstance(addr_obj
, IPv6Network
):
922 d
['family'] = 'inet6'
925 running_addrs
[addr
] = d
927 running_addrs
[addr
] = {}
929 if (scope
& Route
.RT_SCOPE_LINK
and addr
in config_addrs
) or not scope
& Route
.RT_SCOPE_LINK
:
930 running_addrs
[addr
] = addr_details
936 return running_addrs
.keys()
939 def compare_user_config_vs_running_state(running_addrs
, user_addrs
):
943 for ip
in user_addrs
or []:
946 if type(obj
) == IPv6Network
:
952 for ip
in running_addrs
or []:
953 running_ipobj
.append(IPNetwork(ip
))
955 return running_ipobj
== (ip4
+ ip6
)
957 def addr_add_multiple(self
, ifaceobj
, ifacename
, addrs
, purge_existing
=False):
960 # if perfmode is not set and also if iface has no sibling
961 # objects, purge addresses that are not present in the new
963 runningaddrs
= self
.get_running_addrs(
966 addr_virtual_ifaceobj
=ifaceobj
968 addrs
= utils
.get_normalized_ip_addr(ifacename
, addrs
)
970 if self
.compare_user_config_vs_running_state(runningaddrs
, addrs
):
973 # if primary address is not same, there is no need to keep any.
974 # reset all addresses
975 if (addrs
and runningaddrs
and
976 (addrs
[0] != runningaddrs
[0])):
977 self
.del_addr_all(ifacename
)
979 self
.del_addr_all(ifacename
, addrs
)
981 self
.logger
.warning('%s: %s' % (ifacename
, str(e
)))
984 self
.addr_add(ifacename
, a
)
986 self
.logger
.error(str(e
))
988 def _link_set_ifflag(self
, ifacename
, value
):
989 # Dont look at the cache, the cache may have stale value
990 # because link status can be changed by external
991 # entity (One such entity is ifupdown main program)
992 cmd
= 'link set dev %s %s' % (ifacename
, value
.lower())
993 if LinkUtils
.ipbatch
:
994 self
.add_to_batch(cmd
)
996 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
998 def link_up(self
, ifacename
):
999 self
._link
_set
_ifflag
(ifacename
, 'UP')
1001 def link_down(self
, ifacename
):
1002 self
._link
_set
_ifflag
(ifacename
, 'DOWN')
1004 def link_set(self
, ifacename
, key
, value
=None,
1005 force
=False, t
=None, state
=None):
1007 if (key
not in ['master', 'nomaster'] and
1008 self
._cache
_check
('link', [ifacename
, key
], value
)):
1010 cmd
= 'link set dev %s' % ifacename
1012 cmd
+= ' type %s' % t
1015 cmd
+= ' %s' % value
1017 cmd
+= ' %s' % state
1018 if LinkUtils
.ipbatch
:
1019 self
.add_to_batch(cmd
)
1021 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1022 if key
not in ['master', 'nomaster']:
1023 self
._cache
_update
([ifacename
, key
], value
)
1025 def link_set_hwaddress(self
, ifacename
, hwaddress
, force
=False):
1027 if self
._cache
_check
('link', [ifacename
, 'hwaddress'], hwaddress
):
1029 self
.link_down(ifacename
)
1030 cmd
= 'link set dev %s address %s' % (ifacename
, hwaddress
)
1031 if LinkUtils
.ipbatch
:
1032 self
.add_to_batch(cmd
)
1034 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1035 self
.link_up(ifacename
)
1036 self
._cache
_update
([ifacename
, 'hwaddress'], hwaddress
)
1038 def link_set_mtu(self
, ifacename
, mtu
):
1039 if ifupdownflags
.flags
.DRYRUN
:
1041 if not mtu
or not ifacename
: return
1042 self
.write_file('/sys/class/net/%s/mtu' % ifacename
, mtu
)
1043 self
._cache
_update
([ifacename
, 'mtu'], mtu
)
1045 def link_set_alias(self
, ifacename
, alias
):
1046 self
.write_file('/sys/class/net/%s/ifalias' % ifacename
,
1047 '\n' if not alias
else alias
)
1049 def link_get_alias(self
, ifacename
):
1050 return self
.read_file_oneline('/sys/class/net/%s/ifalias'
1053 def link_isloopback(self
, ifacename
):
1054 flags
= self
._cache
_get
('link', [ifacename
, 'flags'])
1057 if 'LOOPBACK' in flags
:
1061 def link_get_status(self
, ifacename
):
1062 return self
._cache
_get
('link', [ifacename
, 'ifflag'], refresh
=True)
1065 def route_add_gateway(ifacename
, gateway
, vrf
=None, metric
=None):
1069 cmd
= '%s route add default via %s proto kernel' % (utils
.ip_cmd
,
1072 cmd
= ('%s route add table %s default via %s proto kernel' %
1073 (utils
.ip_cmd
, vrf
, gateway
))
1076 cmd
+= 'metric %s' % metric
1077 cmd
+= ' dev %s' % ifacename
1078 utils
.exec_command(cmd
)
1081 def route_del_gateway(ifacename
, gateway
, vrf
=None, metric
=None):
1086 cmd
= ('%s route del default via %s proto kernel' %
1087 (utils
.ip_cmd
, gateway
))
1089 cmd
= ('%s route del table %s default via %s proto kernel' %
1090 (utils
.ip_cmd
, vrf
, gateway
))
1092 cmd
+= ' metric %s' % metric
1093 cmd
+= ' dev %s' % ifacename
1094 utils
.exec_command(cmd
)
1097 def _get_vrf_id(ifacename
):
1099 return linkCache
.vrfs
[ifacename
]['table']
1101 dump
= netlink
.link_dump(ifacename
)
1103 [linkCache
.update_attrdict([ifname
], linkattrs
)
1104 for ifname
, linkattrs
in dump
.items()]
1106 if dump
and dump
.get(ifacename
, {}).get('kind') == 'vrf':
1107 vrf_table
= dump
.get(ifacename
, {}).get('linkinfo', {}).get('table')
1108 linkCache
.vrfs
[ifacename
] = {'table': vrf_table
}
1113 def fix_ipv6_route_metric(self
, ifaceobj
, macvlan_ifacename
, ips
):
1116 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.VRF_SLAVE
:
1118 for upper_iface
in ifaceobj
.upperifaces
:
1119 vrf_table
= self
._get
_vrf
_id
(upper_iface
)
1127 ip_network_obj
= IPNetwork(ip
)
1129 if type(ip_network_obj
) == IPv6Network
:
1130 route_prefix
= '%s/%d' % (ip_network_obj
.network
, ip_network_obj
.prefixlen
)
1133 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1134 LinkUtils
.add_to_batch('route del %s table %s dev %s' % (route_prefix
, vrf_table
, macvlan_ifacename
))
1136 utils
.exec_commandl([utils
.ip_cmd
, 'route', 'del', route_prefix
, 'table', vrf_table
, 'dev', macvlan_ifacename
])
1138 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1139 LinkUtils
.add_to_batch('route del %s dev %s' % (route_prefix
, macvlan_ifacename
))
1141 utils
.exec_commandl([utils
.ip_cmd
, 'route', 'del', route_prefix
, 'dev', macvlan_ifacename
])
1142 ip_route_del
.append((route_prefix
, vrf_table
))
1144 for ip
, vrf_table
in ip_route_del
:
1146 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1147 LinkUtils
.add_to_batch('route add %s table %s dev %s proto kernel metric 9999' % (ip
, vrf_table
, macvlan_ifacename
))
1149 utils
.exec_commandl([utils
.ip_cmd
, 'route', 'add', ip
, 'table', vrf_table
, 'dev', macvlan_ifacename
, 'proto', 'kernel' 'metric', '9999'])
1151 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1152 LinkUtils
.add_to_batch('route add %s dev %s proto kernel metric 9999' % (ip
, macvlan_ifacename
))
1154 utils
.exec_commandl([utils
.ip_cmd
, 'route', 'add', ip
, 'dev', macvlan_ifacename
, 'proto', 'kernel' 'metric', '9999'])
1156 def link_create_vlan(self
, vlan_device_name
, vlan_raw_device
, vlanid
):
1157 if self
.link_exists(vlan_device_name
):
1159 utils
.exec_command('%s link add link %s name %s type vlan id %d' %
1161 vlan_raw_device
, vlan_device_name
, vlanid
))
1162 self
._cache
_update
([vlan_device_name
], {})
1164 def link_create_vlan_from_name(self
, vlan_device_name
):
1165 v
= vlan_device_name
.split('.')
1167 self
.logger
.warn('invalid vlan device name %s' % vlan_device_name
)
1169 self
.link_create_vlan(vlan_device_name
, v
[0], v
[1])
1171 def link_create_macvlan(self
, name
, linkdev
, mode
='private'):
1172 if self
.link_exists(name
):
1174 cmd
= ('link add link %s' % linkdev
+
1176 ' type macvlan mode %s' % mode
)
1177 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1178 self
.add_to_batch(cmd
)
1180 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1181 self
._cache
_update
([name
], {})
1183 def get_vxlan_peers(self
, dev
, svcnodeip
):
1184 cmd
= '%s fdb show brport %s' % (utils
.bridge_cmd
,
1188 ps
= subprocess
.Popen(shlex
.split(cmd
), stdout
=subprocess
.PIPE
, close_fds
=False)
1189 utils
.enable_subprocess_signal_forwarding(ps
, signal
.SIGINT
)
1190 output
= subprocess
.check_output(('grep', '00:00:00:00:00:00'), stdin
=ps
.stdout
)
1192 utils
.disable_subprocess_signal_forwarding(signal
.SIGINT
)
1194 ppat
= re
.compile('\s+dst\s+(\d+.\d+.\d+.\d+)\s+')
1195 for l
in output
.split('\n'):
1197 if m
and m
.group(1) != svcnodeip
:
1198 cur_peers
.append(m
.group(1))
1200 self
.logger
.warn('error parsing ip link output')
1201 except subprocess
.CalledProcessError
as e
:
1202 if e
.returncode
!= 1:
1203 self
.logger
.error(str(e
))
1205 utils
.disable_subprocess_signal_forwarding(signal
.SIGINT
)
1209 def link_create_vxlan(self
, name
, vxlanid
,
1216 if svcnodeip
and remoteips
:
1217 raise Exception("svcnodeip and remoteip is mutually exclusive")
1220 args
+= ' remote %s' % svcnodeip
1222 args
+= ' ageing %s' % ageing
1223 if learning
== 'off':
1224 args
+= ' nolearning'
1226 if self
.link_exists(name
):
1227 cmd
= 'link set dev %s type vxlan dstport %d' % (name
, LinkUtils
.VXLAN_UDP_PORT
)
1228 vxlanattrs
= self
.get_vxlandev_attrs(name
)
1229 # on ifreload do not overwrite anycast_ip to individual ip if clagd
1232 running_localtunnelip
= vxlanattrs
.get('local')
1233 if anycastip
and running_localtunnelip
and anycastip
== running_localtunnelip
:
1234 localtunnelip
= running_localtunnelip
1235 running_svcnode
= vxlanattrs
.get('svcnode')
1236 if running_svcnode
and not svcnodeip
:
1239 cmd
= 'link add dev %s type vxlan id %s dstport %d' % (name
, vxlanid
, LinkUtils
.VXLAN_UDP_PORT
)
1242 args
+= ' local %s' % localtunnelip
1245 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1246 self
.add_to_batch(cmd
)
1248 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1250 # XXX: update linkinfo correctly
1251 #self._cache_update([name], {})
1254 def link_exists(ifacename
):
1255 if ifupdownflags
.flags
.DRYRUN
:
1257 return os
.path
.exists('/sys/class/net/%s' % ifacename
)
1259 def link_get_ifindex(self
, ifacename
):
1260 if ifupdownflags
.flags
.DRYRUN
:
1262 return self
.read_file_oneline('/sys/class/net/%s/ifindex' % ifacename
)
1264 def is_vlan_device_by_name(self
, ifacename
):
1265 if re
.search(r
'\.', ifacename
):
1270 def link_add_macvlan(ifname
, macvlan_ifacename
):
1271 utils
.exec_commandl(['ip', 'link', 'add', 'link', ifname
, 'name', macvlan_ifacename
, 'type', 'macvlan', 'mode', 'private'])
1274 def route_add(route
):
1275 utils
.exec_command('%s route add %s' % (utils
.ip_cmd
,
1279 def route6_add(route
):
1280 utils
.exec_command('%s -6 route add %s' % (utils
.ip_cmd
,
1283 def get_vlandev_attrs(self
, ifacename
):
1284 return (self
._cache
_get
('link', [ifacename
, 'link']),
1285 self
._cache
_get
('link', [ifacename
, 'linkinfo', 'vlanid']),
1286 self
._cache
_get
('link', [ifacename
, 'linkinfo', 'vlan_protocol']))
1288 def get_vlan_protocol(self
, ifacename
):
1289 return self
._cache
_get
('link', [ifacename
, 'linkinfo', 'vlan_protocol'])
1291 def get_vxlandev_attrs(self
, ifacename
):
1292 return self
._cache
_get
('link', [ifacename
, 'linkinfo'])
1294 def get_vxlandev_learning(self
, ifacename
):
1295 return self
._cache
_get
('link', [ifacename
, 'linkinfo', Link
.IFLA_VXLAN_LEARNING
])
1297 def set_vxlandev_learning(self
, ifacename
, learn
):
1299 utils
.exec_command('%s link set dev %s type vxlan learning' %
1300 (utils
.ip_cmd
, ifacename
))
1301 self
._cache
_update
([ifacename
, 'linkinfo', 'learning'], 'on')
1303 utils
.exec_command('%s link set dev %s type vxlan nolearning' %
1304 (utils
.ip_cmd
, ifacename
))
1305 self
._cache
_update
([ifacename
, 'linkinfo', 'learning'], 'off')
1307 def link_get_linkinfo_attrs(self
, ifacename
):
1308 return self
._cache
_get
('link', [ifacename
, 'linkinfo'])
1310 def link_get_mtu(self
, ifacename
, refresh
=False):
1311 return self
._cache
_get
('link', [ifacename
, 'mtu'], refresh
=refresh
)
1313 def link_get_mtu_sysfs(self
, ifacename
):
1314 return self
.read_file_oneline('/sys/class/net/%s/mtu'
1317 def link_get_kind(self
, ifacename
):
1318 return self
._cache
_get
('link', [ifacename
, 'kind'])
1320 def link_get_slave_kind(self
, ifacename
):
1321 return self
._cache
_get
('link', [ifacename
, 'slave_kind'])
1323 def link_get_hwaddress(self
, ifacename
):
1324 address
= self
._cache
_get
('link', [ifacename
, 'hwaddress'])
1325 # newly created logical interface addresses dont end up in the cache
1326 # read hwaddress from sysfs file for these interfaces
1328 address
= self
.read_file_oneline('/sys/class/net/%s/address'
1332 def link_create(self
, ifacename
, t
, attrs
={}):
1333 """ generic link_create function """
1334 if self
.link_exists(ifacename
):
1337 cmd
+= ' name %s type %s' % (ifacename
, t
)
1339 for k
, v
in attrs
.iteritems():
1343 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1344 self
.add_to_batch(cmd
)
1346 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1347 self
._cache
_update
([ifacename
], {})
1349 def link_delete(self
, ifacename
):
1350 if not self
.link_exists(ifacename
):
1352 cmd
= 'link del %s' % ifacename
1353 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1354 self
.add_to_batch(cmd
)
1356 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1357 self
._cache
_invalidate
()
1359 def link_get_master(self
, ifacename
):
1360 sysfs_master_path
= '/sys/class/net/%s/master' % ifacename
1361 if os
.path
.exists(sysfs_master_path
):
1362 link_path
= os
.readlink(sysfs_master_path
)
1364 return os
.path
.basename(link_path
)
1368 return self
._cache
_get
('link', [ifacename
, 'master'])
1370 def get_brport_peer_link(self
, bridgename
):
1372 return self
._cache
_get
('link', [bridgename
, 'info_slave_data', Link
.IFLA_BRPORT_PEER_LINK
])
1377 def bridge_port_vids_add(bridgeportname
, vids
):
1378 [utils
.exec_command('%s vlan add vid %s dev %s' %
1380 v
, bridgeportname
)) for v
in vids
]
1383 def bridge_port_vids_del(bridgeportname
, vids
):
1386 [utils
.exec_command('%s vlan del vid %s dev %s' %
1388 v
, bridgeportname
)) for v
in vids
]
1391 def bridge_port_vids_flush(bridgeportname
, vid
):
1392 utils
.exec_command('%s vlan del vid %s dev %s' %
1394 vid
, bridgeportname
))
1397 def bridge_port_vids_get(bridgeportname
):
1398 bridgeout
= utils
.exec_command('%s vlan show dev %s' %
1403 brvlanlines
= bridgeout
.readlines()[2:]
1404 vids
= [l
.strip() for l
in brvlanlines
]
1405 return [v
for v
in vids
if v
]
1408 def bridge_port_vids_get_all():
1410 bridgeout
= utils
.exec_command('%s -c vlan show'
1414 brvlanlines
= bridgeout
.splitlines()
1416 for l
in brvlanlines
[1:]:
1417 if l
and not l
.startswith(' ') and not l
.startswith('\t'):
1419 brportname
= attrs
[0].strip()
1420 brvlaninfo
[brportname
] = {'pvid': None, 'vlan': []}
1421 l
= ' '.join(attrs
[1:])
1422 if not brportname
or not l
:
1426 brvlaninfo
[brportname
]['pvid'] = l
.split()[0]
1427 elif 'Egress Untagged' not in l
:
1428 brvlaninfo
[brportname
]['vlan'].append(l
)
1431 def bridge_port_vids_get_all_json(self
):
1432 if not self
.supported_command
['%s -c -json vlan show'
1433 % utils
.bridge_cmd
]:
1437 bridgeout
= utils
.exec_command('%s -c -json vlan show'
1440 self
.supported_command
['%s -c -json vlan show'
1441 % utils
.bridge_cmd
] = False
1442 self
.logger
.info('%s -c -json vlan show: skipping unsupported command'
1445 return self
.get_bridge_vlan_nojson()
1446 except Exception as e
:
1447 self
.logger
.info('bridge: get_bridge_vlan_nojson: %s' % str(e
))
1450 if not bridgeout
: return brvlaninfo
1452 vlan_json_dict
= json
.loads(bridgeout
, encoding
="utf-8")
1453 except Exception, e
:
1454 self
.logger
.info('json loads failed with (%s)' % str(e
))
1456 return vlan_json_dict
1459 def get_bridge_vlan_nojson():
1461 bridgeout
= utils
.exec_commandl([utils
.bridge_cmd
, '-c', 'vlan', 'show'])
1463 output
= [line
.split('\n') for line
in bridgeout
.split('\n\n')]
1464 output
[0] = output
[0][1:]
1472 prefix
, vlan
= entry
.split('\t')
1474 current_swp
= prefix
1475 vlan_json
[prefix
] = []
1479 v
['vlan'] = int(vlan
)
1483 start
, end
= vlan
.split('-')
1485 end
= end
[0:end
.index(' ')]
1486 v
['vlan'] = int(start
)
1487 v
['vlanEnd'] = int(end
)
1489 v
['vlan'] = int(vlan
[0:vlan
.index(' ')])
1492 flags
.append('PVID')
1493 if 'Egress Untagged' in vlan
:
1494 flags
.append('Egress Untagged')
1498 vlan_json
[current_swp
].append(v
)
1501 def bridge_vlan_cache_get(self
, ifacename
, refresh
=False):
1502 if not self
.bridge_vlan_cache_fill_done
or refresh
:
1503 self
.bridge_vlan_cache
= self
.bridge_port_vids_get_all_json()
1504 self
.bridge_vlan_cache_fill_done
= True
1505 return self
.bridge_vlan_cache
.get(ifacename
, {})
1507 def bridge_vlan_get_pvid(self
, ifacename
, refresh
=False):
1510 for vinfo
in self
.bridge_vlan_cache_get(ifacename
, refresh
):
1511 v
= vinfo
.get('vlan')
1512 pvid
= v
if 'PVID' in vinfo
.get('flags', []) else 0
1517 def bridge_vlan_get_vids(self
, ifacename
, refresh
=False):
1520 for vinfo
in self
.bridge_vlan_cache_get(ifacename
, refresh
):
1521 v
= vinfo
.get('vlan')
1522 ispvid
= True if 'PVID' in vinfo
.get('flags', []) else False
1524 pvid
= v
if 'PVID' in vinfo
.get('flags', []) else 0
1527 vEnd
= vinfo
.get('vlanEnd')
1529 vids
.extend(range(v
, vEnd
+ 1))
1534 def bridge_vlan_get_vids_n_pvid(self
, ifacename
, refresh
=False):
1538 for vinfo
in self
.bridge_vlan_cache_get(ifacename
, refresh
):
1539 v
= vinfo
.get('vlan')
1540 ispvid
= True if 'PVID' in vinfo
.get('flags', []) else False
1542 pvid
= v
if 'PVID' in vinfo
.get('flags', []) else 0
1543 vEnd
= vinfo
.get('vlanEnd')
1545 vids
.extend(range(v
, vEnd
+ 1))
1550 def bridge_port_pvid_add(self
, bridgeportname
, pvid
):
1551 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1552 self
.add_to_batch('vlan add vid %s untagged pvid dev %s' %
1553 (pvid
, bridgeportname
))
1555 utils
.exec_command('%s vlan add vid %s untagged pvid dev %s' %
1557 pvid
, bridgeportname
))
1559 def bridge_port_pvid_del(self
, bridgeportname
, pvid
):
1560 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1561 self
.add_to_batch('vlan del vid %s untagged pvid dev %s' %
1562 (pvid
, bridgeportname
))
1564 utils
.exec_command('%s vlan del vid %s untagged pvid dev %s' %
1566 pvid
, bridgeportname
))
1568 def bridge_port_pvids_get(self
, bridgeportname
):
1569 return self
.read_file_oneline('/sys/class/net/%s/brport/pvid'
1572 def bridge_vids_add(self
, bridgeportname
, vids
, bridge
=True):
1573 target
= 'self' if bridge
else ''
1574 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1575 [self
.add_to_batch('vlan add vid %s dev %s %s' %
1576 (v
, bridgeportname
, target
)) for v
in vids
]
1578 [utils
.exec_command('%s vlan add vid %s dev %s %s' %
1580 v
, bridgeportname
, target
)) for v
in vids
]
1582 def bridge_vids_del(self
, bridgeportname
, vids
, bridge
=True):
1583 target
= 'self' if bridge
else ''
1584 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1585 [self
.add_to_batch('vlan del vid %s dev %s %s' %
1586 (v
, bridgeportname
, target
)) for v
in vids
]
1588 [utils
.exec_command('%s vlan del vid %s dev %s %s' %
1590 v
, bridgeportname
, target
)) for v
in vids
]
1593 def bridge_fdb_add(dev
, address
, vlan
=None, bridge
=True, remote
=None):
1594 target
= 'self' if bridge
else ''
1597 vlan_str
= 'vlan %s ' % vlan
1601 dst_str
= 'dst %s ' % remote
1603 utils
.exec_command('%s fdb replace %s dev %s %s %s %s' %
1605 address
, dev
, vlan_str
, target
, dst_str
))
1608 def bridge_fdb_append(dev
, address
, vlan
=None, bridge
=True, remote
=None):
1609 target
= 'self' if bridge
else ''
1612 vlan_str
= 'vlan %s ' % vlan
1616 dst_str
= 'dst %s ' % remote
1618 utils
.exec_command('%s fdb append %s dev %s %s %s %s' %
1620 address
, dev
, vlan_str
, target
, dst_str
))
1623 def bridge_fdb_del(dev
, address
, vlan
=None, bridge
=True, remote
=None):
1624 target
= 'self' if bridge
else ''
1627 vlan_str
= 'vlan %s ' % vlan
1631 dst_str
= 'dst %s ' % remote
1632 utils
.exec_command('%s fdb del %s dev %s %s %s %s' %
1634 address
, dev
, vlan_str
, target
, dst_str
))
1636 def bridge_is_vlan_aware(self
, bridgename
):
1637 filename
= '/sys/class/net/%s/bridge/vlan_filtering' % bridgename
1638 if os
.path
.exists(filename
) and self
.read_file_oneline(filename
) == '1':
1643 def bridge_port_get_bridge_name(bridgeport
):
1644 filename
= '/sys/class/net/%s/brport/bridge' % bridgeport
1646 return os
.path
.basename(os
.readlink(filename
))
1651 def bridge_port_exists(bridge
, bridgeportname
):
1653 return os
.path
.exists('/sys/class/net/%s/brif/%s'
1654 % (bridge
, bridgeportname
))
1658 def bridge_fdb_show_dev(self
, dev
):
1661 output
= utils
.exec_command('%s fdb show dev %s'
1662 % (utils
.bridge_cmd
, dev
))
1664 for fdb_entry
in output
.splitlines():
1666 entries
= fdb_entry
.split()
1667 fdbs
.setdefault(entries
[2], []).append(entries
[0])
1669 self
.logger
.debug('%s: invalid fdb line \'%s\''
1676 def is_bridge(bridge
):
1677 return os
.path
.exists('/sys/class/net/%s/bridge' % bridge
)
1679 def is_link_up(self
, ifacename
):
1682 flags
= self
.read_file_oneline('/sys/class/net/%s/flags' % ifacename
)
1683 iflags
= int(flags
, 16)
1690 def ip_route_get_dev(self
, prefix
):
1692 output
= utils
.exec_command('%s route get %s' %
1693 (utils
.ip_cmd
, prefix
))
1695 rline
= output
.splitlines()[0]
1697 rattrs
= rline
.split()
1698 return rattrs
[rattrs
.index('dev') + 1]
1699 except Exception, e
:
1700 self
.logger
.debug('ip_route_get_dev: failed .. %s' % str(e
))
1704 def link_get_lowers(ifacename
):
1706 lowers
= glob
.glob("/sys/class/net/%s/lower_*" % ifacename
)
1709 return [os
.path
.basename(l
)[6:] for l
in lowers
]
1714 def link_get_uppers(ifacename
):
1716 uppers
= glob
.glob("/sys/class/net/%s/upper_*" % ifacename
)
1719 return [os
.path
.basename(u
)[6:] for u
in uppers
]
1723 def link_get_vrfs(self
):
1724 if not LinkUtils
._CACHE
_FILL
_DONE
:
1726 return linkCache
.vrfs
1729 def cache_get_info_slave(attrlist
):
1731 return linkCache
.get_attr(attrlist
)
1735 def get_brport_learning(self
, ifacename
):
1736 learn
= self
.read_file_oneline('/sys/class/net/%s/brport/learning'
1738 if learn
and learn
== '1':
1743 def get_brport_learning_bool(self
, ifacename
):
1744 return utils
.get_boolean_from_string(self
.read_file_oneline('/sys/class/net/%s/brport/learning' % ifacename
))
1746 def set_brport_learning(self
, ifacename
, learn
):
1748 return self
.write_file('/sys/class/net/%s/brport/learning'
1751 return self
.write_file('/sys/class/net/%s/brport/learning'
1754 #################################################################################
1755 ################################### BOND UTILS ##################################
1756 #################################################################################
1758 def _link_cache_get(self
, attrlist
, refresh
=False):
1759 return self
._cache
_get
('link', attrlist
, refresh
)
1761 def cache_delete(self
, attrlist
, value
=None):
1762 return self
._cache
_delete
(attrlist
, value
)
1764 def link_cache_get(self
, attrlist
, refresh
=False):
1765 return self
._link
_cache
_get
(attrlist
, refresh
)
1767 def link_cache_check(self
, attrlist
, value
, refresh
=False):
1768 return self
._link
_cache
_check
(attrlist
, value
, refresh
)
1770 def _link_cache_check(self
, attrlist
, value
, refresh
=False):
1772 return self
._link
_cache
_get
(attrlist
, refresh
) == value
1773 except Exception, e
:
1774 self
.logger
.debug('_cache_check(%s) : [%s]'
1775 % (str(attrlist
), str(e
)))
1780 Link
.IFLA_BOND_MODE
: 'mode',
1781 Link
.IFLA_BOND_MIIMON
: 'miimon',
1782 Link
.IFLA_BOND_USE_CARRIER
: 'use_carrier',
1783 Link
.IFLA_BOND_AD_LACP_RATE
: 'lacp_rate',
1784 Link
.IFLA_BOND_XMIT_HASH_POLICY
: 'xmit_hash_policy',
1785 Link
.IFLA_BOND_MIN_LINKS
: 'min_links',
1786 Link
.IFLA_BOND_NUM_PEER_NOTIF
: 'num_grat_arp',
1787 Link
.IFLA_BOND_AD_ACTOR_SYSTEM
: 'ad_actor_system',
1788 Link
.IFLA_BOND_AD_ACTOR_SYS_PRIO
: 'ad_actor_sys_prio',
1789 Link
.IFLA_BOND_AD_LACP_BYPASS
: 'lacp_bypass',
1790 Link
.IFLA_BOND_UPDELAY
: 'updelay',
1791 Link
.IFLA_BOND_DOWNDELAY
: 'downdelay',
1794 def bond_set_attrs_nl(self
, bondname
, ifla_info_data
):
1795 bond_attr_name
= 'None' # for log purpose (in case an exception raised)
1796 for nl_attr
, value
in ifla_info_data
.items():
1798 bond_attr_name
= self
.bondcmd_attrmap
[nl_attr
]
1799 file_path
= '/sys/class/net/%s/bonding/%s' % (bondname
, bond_attr_name
)
1800 if os
.path
.exists(file_path
):
1801 self
.write_file(file_path
, str(value
))
1802 except Exception as e
:
1803 exception_str
= '%s: %s %s: %s' % (bondname
, bond_attr_name
, value
, str(e
))
1804 if ifupdownflags
.flags
.FORCE
:
1805 self
.logger
.warning(exception_str
)
1807 self
.logger
.debug(exception_str
)
1809 def bond_set_attrs(self
, bondname
, attrdict
, prehook
):
1810 for attrname
, attrval
in attrdict
.items():
1811 if (self
._link
_cache
_check
([bondname
, 'linkinfo',
1812 attrname
], attrval
)):
1814 if (attrname
== 'mode'
1815 or attrname
== 'xmit_hash_policy'
1816 or attrname
== 'lacp_rate' or attrname
== 'min_links'):
1820 if ((attrname
not in ['lacp_rate',
1822 self
._link
_cache
_check
([bondname
, 'linkinfo', 'mode'], '802.3ad',
1824 self
.write_file('/sys/class/net/%s/bonding/%s'
1825 % (bondname
, attrname
), attrval
)
1826 except Exception, e
:
1827 if ifupdownflags
.flags
.FORCE
:
1828 self
.logger
.warn(str(e
))
1833 def bond_set_use_carrier(self
, bondname
, use_carrier
):
1834 if not use_carrier
or (use_carrier
!= '0' and use_carrier
!= '1'):
1836 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'use_carrier'],
1839 self
.write_file('/sys/class/net/%s' % bondname
+
1840 '/bonding/use_carrier', use_carrier
)
1841 self
._cache
_update
([bondname
, 'linkinfo',
1842 'use_carrier'], use_carrier
)
1844 def bond_get_use_carrier(self
, bondname
):
1845 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'use_carrier'])
1847 def bond_get_use_carrier_nl(self
, bondname
):
1848 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_USE_CARRIER
])
1850 def bond_set_xmit_hash_policy(self
, bondname
, hash_policy
, prehook
=None):
1851 valid_values
= ['layer2', 'layer3+4', 'layer2+3']
1854 if hash_policy
not in valid_values
:
1855 raise Exception('invalid hash policy value %s' % hash_policy
)
1856 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'xmit_hash_policy'],
1861 self
.write_file('/sys/class/net/%s' % bondname
+
1862 '/bonding/xmit_hash_policy', hash_policy
)
1863 self
._cache
_update
([bondname
, 'linkinfo', 'xmit_hash_policy'],
1866 def bond_get_xmit_hash_policy(self
, bondname
):
1867 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'xmit_hash_policy'])
1869 def bond_get_xmit_hash_policy_nl(self
, bondname
):
1870 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_XMIT_HASH_POLICY
])
1872 def bond_set_miimon(self
, bondname
, miimon
):
1873 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'miimon'],
1876 self
.write_file('/sys/class/net/%s' % bondname
+
1877 '/bonding/miimon', miimon
)
1878 self
._cache
_update
([bondname
, 'linkinfo', 'miimon'], miimon
)
1880 def bond_get_miimon(self
, bondname
):
1881 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'miimon'])
1883 def bond_get_miimon_nl(self
, bondname
):
1884 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_MIIMON
])
1886 def bond_set_mode(self
, bondname
, mode
, prehook
=None):
1887 valid_modes
= ['balance-rr', 'active-backup', 'balance-xor',
1888 'broadcast', '802.3ad', 'balance-tlb', 'balance-alb']
1891 if mode
not in valid_modes
:
1892 raise Exception('invalid mode %s' % mode
)
1893 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'mode'],
1898 self
.write_file('/sys/class/net/%s' % bondname
+ '/bonding/mode', mode
)
1899 self
._cache
_update
([bondname
, 'linkinfo', 'mode'], mode
)
1901 def bond_get_mode(self
, bondname
):
1902 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'mode'])
1904 def bond_get_mode_nl(self
, bondname
):
1905 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_MODE
])
1907 def bond_set_lacp_rate(self
, bondname
, lacp_rate
, prehook
=None, posthook
=None):
1908 if not lacp_rate
or (lacp_rate
!= '0' and lacp_rate
!= '1'):
1910 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'lacp_rate'],
1916 self
.write_file('/sys/class/net/%s' % bondname
+
1917 '/bonding/lacp_rate', lacp_rate
)
1923 self
._cache
_update
([bondname
, 'linkinfo',
1924 'lacp_rate'], lacp_rate
)
1926 def bond_get_lacp_rate(self
, bondname
):
1927 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'lacp_rate'])
1929 def bond_get_lacp_rate_nl(self
, bondname
):
1930 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_LACP_RATE
])
1932 def bond_set_lacp_bypass_allow(self
, bondname
, allow
, prehook
=None, posthook
=None):
1933 if self
._link
_cache
_check
([bondname
, 'linkinfo', 'lacp_bypass'], allow
):
1938 self
.write_file('/sys/class/net/%s' % bondname
+
1939 '/bonding/lacp_bypass', allow
)
1945 self
._cache
_update
([bondname
, 'linkinfo',
1946 'lacp_bypass'], allow
)
1948 def bond_get_lacp_bypass_allow(self
, bondname
):
1949 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'lacp_bypass'])
1951 def bond_get_lacp_bypass_allow_nl(self
, bondname
):
1952 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_LACP_BYPASS
])
1954 def bond_set_min_links(self
, bondname
, min_links
, prehook
=None):
1955 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'min_links'],
1960 self
.write_file('/sys/class/net/%s/bonding/min_links' % bondname
,
1962 self
._cache
_update
([bondname
, 'linkinfo', 'min_links'], min_links
)
1964 def bond_get_min_links(self
, bondname
):
1965 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'min_links'])
1967 def get_min_links_nl(self
, bondname
):
1968 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_MIN_LINKS
])
1970 def bond_get_ad_actor_system(self
, bondname
):
1971 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'ad_actor_system'])
1973 def bond_get_ad_actor_system_nl(self
, bondname
):
1974 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_ACTOR_SYSTEM
])
1976 def bond_get_ad_actor_sys_prio(self
, bondname
):
1977 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'ad_actor_sys_prio'])
1979 def bond_get_ad_actor_sys_prio_nl(self
, bondname
):
1980 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_ACTOR_SYS_PRIO
])
1982 def bond_get_num_unsol_na(self
, bondname
):
1983 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'num_unsol_na'])
1985 def bond_get_num_unsol_na_nl(self
, bondname
):
1986 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_NUM_PEER_NOTIF
])
1988 def bond_get_num_grat_arp(self
, bondname
):
1989 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'num_grat_arp'])
1991 def bond_get_num_grat_arp_nl(self
, bondname
):
1992 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_NUM_PEER_NOTIF
])
1994 def bond_get_updelay(self
, bondname
):
1995 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'updelay'])
1997 def bond_get_updelay_nl(self
, bondname
):
1998 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_UPDELAY
])
2000 def bond_get_downdelay(self
, bondname
):
2001 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'downdelay'])
2003 def bond_get_downdelay_nl(self
, bondname
):
2004 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_DOWNDELAY
])
2006 def bond_enslave_slave(self
, bondname
, slave
, prehook
=None, posthook
=None):
2007 slaves
= self
._link
_cache
_get
([bondname
, 'linkinfo', 'slaves'])
2008 if slaves
and slave
in slaves
:
2012 self
.write_file('/sys/class/net/%s' % bondname
+
2013 '/bonding/slaves', '+' + slave
)
2016 self
._cache
_update
([bondname
, 'linkinfo', 'slaves'], slave
)
2018 def bond_remove_slave(self
, bondname
, slave
):
2019 slaves
= self
._link
_cache
_get
([bondname
, 'linkinfo', 'slaves'])
2020 if not slaves
or slave
not in slaves
:
2022 sysfs_bond_path
= ('/sys/class/net/%s' % bondname
+
2024 if not os
.path
.exists(sysfs_bond_path
):
2026 self
.write_file(sysfs_bond_path
, '-' + slave
)
2027 self
._cache
_delete
([bondname
, 'linkinfo', 'slaves'], slave
)
2029 def bond_remove_slaves_all(self
, bondname
):
2030 if not self
._link
_cache
_get
([bondname
, 'linkinfo', 'slaves']):
2033 sysfs_bond_path
= ('/sys/class/net/%s' % bondname
+
2036 with
open(sysfs_bond_path
, 'r') as f
:
2037 slaves
= f
.readline().strip().split()
2039 raise Exception('error reading slaves of bond %s (%s)' % (bondname
, str(e
)))
2040 for slave
in slaves
:
2041 self
.link_down(slave
)
2043 self
.bond_remove_slave(bondname
, slave
)
2044 except Exception, e
:
2045 if not ifupdownflags
.flags
.FORCE
:
2046 raise Exception('error removing slave %s from bond %s (%s)' % (slave
, bondname
, str(e
)))
2049 self
._cache
_delete
([bondname
, 'linkinfo', 'slaves'])
2052 def bond_load_bonding_module():
2053 return utils
.exec_command('%s -q bonding' % utils
.modprobe_cmd
)
2055 def create_bond(self
, bondname
):
2056 if self
.bond_exists(bondname
):
2058 # load_bonding_module() has already been run
2059 self
.write_file('/sys/class/net/bonding_masters', '+' + bondname
)
2060 self
._cache
_update
([bondname
], {})
2062 def delete_bond(self
, bondname
):
2063 if not os
.path
.exists('/sys/class/net/%s' % bondname
):
2065 self
.write_file('/sys/class/net/bonding_masters', '-' + bondname
)
2066 self
._cache
_delete
([bondname
])
2068 def bond_get_slaves(self
, bondname
):
2069 slaves
= self
._link
_cache
_get
([bondname
, 'linkinfo', 'slaves'])
2072 slavefile
= '/sys/class/net/%s/bonding/slaves' % bondname
2073 if os
.path
.exists(slavefile
):
2074 buf
= self
.read_file_oneline(slavefile
)
2076 slaves
= buf
.split()
2079 self
._cache
_update
([bondname
, 'linkinfo', 'slaves'], slaves
)
2082 def bond_slave_exists(self
, bond
, slave
):
2083 slaves
= self
.bond_get_slaves(bond
)
2086 return slave
in slaves
2089 def bond_exists(bondname
):
2090 return os
.path
.exists('/sys/class/net/%s/bonding' % bondname
)
2092 #################################################################################
2093 ################################## BRIDGE UTILS #################################
2094 #################################################################################
2096 def create_bridge(self
, bridgename
):
2097 if not LinkUtils
.bridge_utils_is_installed
:
2099 if self
.bridge_exists(bridgename
):
2101 utils
.exec_command('%s addbr %s' % (utils
.brctl_cmd
, bridgename
))
2102 self
._cache
_update
([bridgename
], {})
2104 def delete_bridge(self
, bridgename
):
2105 if not LinkUtils
.bridge_utils_is_installed
:
2107 if not self
.bridge_exists(bridgename
):
2109 utils
.exec_command('%s delbr %s' % (utils
.brctl_cmd
, bridgename
))
2110 self
._cache
_invalidate
()
2112 def add_bridge_port(self
, bridgename
, bridgeportname
):
2113 """ Add port to bridge """
2114 if not LinkUtils
.bridge_utils_is_installed
:
2116 ports
= self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports'])
2117 if ports
and ports
.get(bridgeportname
):
2119 utils
.exec_command('%s addif %s %s' % (utils
.brctl_cmd
, bridgename
, bridgeportname
))
2120 self
._cache
_update
([bridgename
, 'linkinfo', 'ports', bridgeportname
], {})
2122 def delete_bridge_port(self
, bridgename
, bridgeportname
):
2123 """ Delete port from bridge """
2124 if not LinkUtils
.bridge_utils_is_installed
:
2126 ports
= self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports'])
2127 if not ports
or not ports
.get(bridgeportname
):
2129 utils
.exec_command('%s delif %s %s' % (utils
.brctl_cmd
, bridgename
, bridgeportname
))
2130 self
._cache
_delete
([bridgename
, 'linkinfo', 'ports', 'bridgeportname'])
2132 def set_bridgeport_attrs(self
, bridgename
, bridgeportname
, attrdict
):
2133 portattrs
= self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports', bridgeportname
])
2134 if portattrs
== None:
2136 for k
, v
in attrdict
.iteritems():
2137 if ifupdownflags
.flags
.CACHE
:
2138 curval
= portattrs
.get(k
)
2139 if curval
and curval
== v
:
2141 if k
== 'unicast-flood':
2142 self
.write_file('/sys/class/net/%s/brport/unicast_flood' % bridgeportname
, v
)
2143 elif k
== 'multicast-flood':
2144 self
.write_file('/sys/class/net/%s/brport/multicast_flood' % bridgeportname
, v
)
2145 elif k
== 'learning':
2146 self
.write_file('/sys/class/net/%s/brport/learning' % bridgeportname
, v
)
2147 elif k
== 'arp-nd-suppress':
2148 self
.write_file('/sys/class/net/%s/brport/neigh_suppress' % bridgeportname
, v
)
2150 if not LinkUtils
.bridge_utils_is_installed
:
2152 utils
.exec_command('%s set%s %s %s %s' % (utils
.brctl_cmd
, k
, bridgename
, bridgeportname
, v
))
2154 def set_bridgeport_attr(self
, bridgename
, bridgeportname
,
2156 if not LinkUtils
.bridge_utils_is_installed
:
2158 if self
._link
_cache
_check
([bridgename
, 'linkinfo', 'ports', bridgeportname
, attrname
], attrval
):
2160 utils
.exec_command('%s set%s %s %s %s' %
2167 def set_bridge_attrs(self
, bridgename
, attrdict
):
2168 for k
, v
in attrdict
.iteritems():
2171 if self
._link
_cache
_check
([bridgename
, 'linkinfo', k
], v
):
2174 if k
== 'igmp-version':
2175 self
.write_file('/sys/class/net/%s/bridge/'
2176 'multicast_igmp_version' % bridgename
, v
)
2177 elif k
== 'mld-version':
2178 self
.write_file('/sys/class/net/%s/bridge/'
2179 'multicast_mld_version' % bridgename
, v
)
2180 elif k
== 'vlan-protocol':
2181 self
.write_file('/sys/class/net/%s/bridge/'
2182 'vlan_protocol' % bridgename
,
2183 VlanProtocols
.ETHERTYPES_TO_ID
.get(v
.upper(),
2185 elif k
== 'vlan-stats':
2186 self
.write_file('/sys/class/net/%s/bridge/'
2187 'vlan_stats_enabled' % bridgename
, v
)
2188 elif k
== 'mcstats':
2189 self
.write_file('/sys/class/net/%s/bridge/'
2190 'multicast_stats_enabled' % bridgename
, v
)
2192 if not LinkUtils
.bridge_utils_is_installed
:
2194 cmd
= ('%s set%s %s %s' %
2195 (utils
.brctl_cmd
, k
, bridgename
, v
))
2196 utils
.exec_command(cmd
)
2197 except Exception, e
:
2198 self
.logger
.warn('%s: %s' % (bridgename
, str(e
)))
2201 def set_bridge_attr(self
, bridgename
, attrname
, attrval
):
2202 if self
._link
_cache
_check
([bridgename
, 'linkinfo', attrname
], attrval
):
2204 if attrname
== 'igmp-version':
2205 self
.write_file('/sys/class/net/%s/bridge/multicast_igmp_version'
2206 % bridgename
, attrval
)
2207 elif attrname
== 'mld-version':
2208 self
.write_file('/sys/class/net/%s/bridge/multicast_mld_version'
2209 % bridgename
, attrval
)
2210 elif attrname
== 'vlan-protocol':
2211 self
.write_file('/sys/class/net/%s/bridge/vlan_protocol'
2212 % bridgename
, VlanProtocols
.ETHERTYPES_TO_ID
[attrval
.upper()])
2213 elif attrname
== 'vlan-stats':
2214 self
.write_file('/sys/class/net/%s/bridge/vlan_stats_enabled'
2215 % bridgename
, attrval
)
2216 elif attrname
== 'mcstats':
2217 self
.write_file('/sys/class/net/%s/bridge/multicast_stats_enabled'
2218 % bridgename
, attrval
)
2220 if not LinkUtils
.bridge_utils_is_installed
:
2222 cmd
= '%s set%s %s %s' % (utils
.brctl_cmd
,
2223 attrname
, bridgename
, attrval
)
2224 utils
.exec_command(cmd
)
2226 def get_bridge_attrs(self
, bridgename
):
2227 attrs
= self
._link
_cache
_get
([bridgename
, 'linkinfo'])
2229 for key
, value
in attrs
.items():
2230 if type(key
) == str:
2231 no_ints_attrs
[key
] = value
2232 return no_ints_attrs
2234 def get_bridgeport_attrs(self
, bridgename
, bridgeportname
):
2235 return self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports',
2238 def get_bridgeport_attr(self
, bridgename
, bridgeportname
, attrname
):
2239 return self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports',
2240 bridgeportname
, attrname
])
2243 def bridge_set_stp(bridge
, stp_state
):
2244 if not LinkUtils
.bridge_utils_is_installed
:
2246 utils
.exec_command('%s stp %s %s' % (utils
.brctl_cmd
, bridge
, stp_state
))
2248 def bridge_get_stp(self
, bridge
):
2249 sysfs_stpstate
= '/sys/class/net/%s/bridge/stp_state' % bridge
2250 if not os
.path
.exists(sysfs_stpstate
):
2252 stpstate
= self
.read_file_oneline(sysfs_stpstate
)
2256 if int(stpstate
) > 0:
2258 elif int(stpstate
) == 0:
2264 def _conv_value_to_user(s
):
2271 def read_value_from_sysfs(self
, filename
, preprocess_func
):
2272 value
= self
.read_file_oneline(filename
)
2275 return preprocess_func(value
)
2278 def bridge_set_ageing(bridge
, ageing
):
2279 if not LinkUtils
.bridge_utils_is_installed
:
2281 utils
.exec_command('%s setageing %s %s' % (utils
.brctl_cmd
, bridge
, ageing
))
2283 def bridge_get_ageing(self
, bridge
):
2284 return self
.read_value_from_sysfs('/sys/class/net/%s/bridge/ageing_time'
2285 % bridge
, self
._conv
_value
_to
_user
)
2288 def set_bridgeprio(bridge
, prio
):
2289 if not LinkUtils
.bridge_utils_is_installed
:
2291 utils
.exec_command('%s setbridgeprio %s %s' % (utils
.brctl_cmd
, bridge
, prio
))
2293 def get_bridgeprio(self
, bridge
):
2294 return self
.read_file_oneline(
2295 '/sys/class/net/%s/bridge/priority' % bridge
)
2298 def bridge_set_fd(bridge
, fd
):
2299 if not LinkUtils
.bridge_utils_is_installed
:
2301 utils
.exec_command('%s setfd %s %s' % (utils
.brctl_cmd
, bridge
, fd
))
2303 def bridge_get_fd(self
, bridge
):
2304 return self
.read_value_from_sysfs(
2305 '/sys/class/net/%s/bridge/forward_delay'
2306 % bridge
, self
._conv
_value
_to
_user
)
2308 def bridge_set_gcint(self
, bridge
, gcint
):
2309 raise Exception('set_gcint not implemented')
2312 def bridge_set_hello(bridge
, hello
):
2313 if not LinkUtils
.bridge_utils_is_installed
:
2315 utils
.exec_command('%s sethello %s %s' % (utils
.brctl_cmd
, bridge
, hello
))
2317 def bridge_get_hello(self
, bridge
):
2318 return self
.read_value_from_sysfs('/sys/class/net/%s/bridge/hello_time'
2319 % bridge
, self
._conv
_value
_to
_user
)
2322 def bridge_set_maxage(bridge
, maxage
):
2323 if not LinkUtils
.bridge_utils_is_installed
:
2325 utils
.exec_command('%s setmaxage %s %s' % (utils
.brctl_cmd
, bridge
, maxage
))
2327 def bridge_get_maxage(self
, bridge
):
2328 return self
.read_value_from_sysfs('/sys/class/net/%s/bridge/max_age'
2329 % bridge
, self
._conv
_value
_to
_user
)
2332 def bridge_set_pathcost(bridge
, port
, pathcost
):
2333 if not LinkUtils
.bridge_utils_is_installed
:
2335 utils
.exec_command('%s setpathcost %s %s %s' % (utils
.brctl_cmd
, bridge
, port
, pathcost
))
2337 def bridge_get_pathcost(self
, bridge
, port
):
2338 return self
.read_file_oneline('/sys/class/net/%s/brport/path_cost'
2342 def bridge_set_portprio(bridge
, port
, prio
):
2343 if not LinkUtils
.bridge_utils_is_installed
:
2345 utils
.exec_command('%s setportprio %s %s %s' % (utils
.brctl_cmd
, bridge
, port
, prio
))
2347 def bridge_get_portprio(self
, bridge
, port
):
2348 return self
.read_file_oneline('/sys/class/net/%s/brport/priority'
2352 def bridge_set_hashmax(bridge
, hashmax
):
2353 if not LinkUtils
.bridge_utils_is_installed
:
2355 utils
.exec_command('%s sethashmax %s %s' % (utils
.brctl_cmd
, bridge
, hashmax
))
2357 def bridge_get_hashmax(self
, bridge
):
2358 return self
.read_file_oneline('/sys/class/net/%s/bridge/hash_max'
2362 def bridge_set_hashel(bridge
, hashel
):
2363 if not LinkUtils
.bridge_utils_is_installed
:
2365 utils
.exec_command('%s sethashel %s %s' % (utils
.brctl_cmd
, bridge
, hashel
))
2367 def bridge_get_hashel(self
, bridge
):
2368 return self
.read_file_oneline('/sys/class/net/%s/bridge/hash_elasticity'
2372 def bridge_set_mclmc(bridge
, mclmc
):
2373 if not LinkUtils
.bridge_utils_is_installed
:
2375 utils
.exec_command('%s setmclmc %s %s' % (utils
.brctl_cmd
, bridge
, mclmc
))
2377 def bridge_get_mclmc(self
, bridge
):
2378 return self
.read_file_oneline(
2379 '/sys/class/net/%s/bridge/multicast_last_member_count'
2383 def bridge_set_mcrouter(bridge
, mcrouter
):
2384 if not LinkUtils
.bridge_utils_is_installed
:
2386 utils
.exec_command('%s setmcrouter %s %s' % (utils
.brctl_cmd
, bridge
, mcrouter
))
2388 def bridge_get_mcrouter(self
, bridge
):
2389 return self
.read_file_oneline(
2390 '/sys/class/net/%s/bridge/multicast_router' % bridge
)
2393 def bridge_set_mcsnoop(bridge
, mcsnoop
):
2394 if not LinkUtils
.bridge_utils_is_installed
:
2396 utils
.exec_command('%s setmcsnoop %s %s' % (utils
.brctl_cmd
, bridge
, mcsnoop
))
2398 def bridge_get_mcsnoop(self
, bridge
):
2399 return self
.read_file_oneline(
2400 '/sys/class/net/%s/bridge/multicast_snooping' % bridge
)
2403 def bridge_set_mcsqc(bridge
, mcsqc
):
2404 if not LinkUtils
.bridge_utils_is_installed
:
2406 utils
.exec_command('%s setmcsqc %s %s' % (utils
.brctl_cmd
, bridge
, mcsqc
))
2408 def bridge_get_mcsqc(self
, bridge
):
2409 return self
.read_file_oneline(
2410 '/sys/class/net/%s/bridge/multicast_startup_query_count'
2414 def bridge_set_mcqifaddr(bridge
, mcqifaddr
):
2415 if not LinkUtils
.bridge_utils_is_installed
:
2417 utils
.exec_command('%s setmcqifaddr %s %s' % (utils
.brctl_cmd
, bridge
, mcqifaddr
))
2419 def bridge_get_mcqifaddr(self
, bridge
):
2420 return self
.read_file_oneline(
2421 '/sys/class/net/%s/bridge/multicast_startup_query_use_ifaddr'
2425 def bridge_set_mcquerier(bridge
, mcquerier
):
2426 if not LinkUtils
.bridge_utils_is_installed
:
2428 utils
.exec_command('%s setmcquerier %s %s' % (utils
.brctl_cmd
, bridge
, mcquerier
))
2430 def bridge_get_mcquerier(self
, bridge
):
2431 return self
.read_file_oneline(
2432 '/sys/class/net/%s/bridge/multicast_querier' % bridge
)
2434 def bridge_set_mcqv4src(self
, bridge
, vlan
, mcquerier
):
2438 self
.logger
.info('%s: set mcqv4src vlan: invalid parameter %s: %s' %(bridge
, vlan
, str(e
)))
2440 if vlan
== 0 or vlan
> 4095:
2441 self
.logger
.warn('mcqv4src vlan \'%d\' invalid range' % vlan
)
2444 ip
= mcquerier
.split('.')
2446 self
.logger
.warn('mcqv4src \'%s\' invalid IPv4 address' % mcquerier
)
2449 if not k
.isdigit() or int(k
, 10) < 0 or int(k
, 10) > 255:
2450 self
.logger
.warn('mcqv4src \'%s\' invalid IPv4 address' % mcquerier
)
2453 if not LinkUtils
.bridge_utils_is_installed
:
2456 utils
.exec_command('%s setmcqv4src %s %d %s' %
2457 (utils
.brctl_cmd
, bridge
, vlan
, mcquerier
))
2459 def bridge_del_mcqv4src(self
, bridge
, vlan
):
2460 if not LinkUtils
.bridge_utils_is_installed
:
2465 self
.logger
.info('%s: del mcqv4src vlan: invalid parameter %s: %s' %(bridge
, vlan
, str(e
)))
2467 utils
.exec_command('%s delmcqv4src %s %d' % (utils
.brctl_cmd
, bridge
, vlan
))
2469 def bridge_get_mcqv4src(self
, bridge
, vlan
=None):
2470 if not LinkUtils
.bridge_utils_is_installed
:
2472 if not self
.supported_command
['showmcqv4src']:
2476 mcqout
= utils
.exec_command('%s showmcqv4src %s' %
2477 (utils
.brctl_cmd
, bridge
))
2478 except Exception as e
:
2480 if 'never heard' in s
:
2481 msg
= ('%s showmcqv4src: skipping unsupported command'
2483 self
.logger
.info(msg
)
2484 self
.supported_command
['showmcqv4src'] = False
2489 mcqlines
= mcqout
.splitlines()
2490 for l
in mcqlines
[1:]:
2492 k
, d
, v
= l
.split('\t')
2497 return mcqv4src
.get(vlan
)
2501 def bridge_set_mclmi(bridge
, mclmi
):
2502 if not LinkUtils
.bridge_utils_is_installed
:
2504 utils
.exec_command('%s setmclmi %s %s' % (utils
.brctl_cmd
, bridge
, mclmi
))
2506 def bridge_get_mclmi(self
, bridge
):
2507 return self
.read_file_oneline(
2508 '/sys/class/net/%s/bridge/multicast_last_member_interval'
2512 def bridge_set_mcmi(bridge
, mcmi
):
2513 if not LinkUtils
.bridge_utils_is_installed
:
2515 utils
.exec_command('%s setmcmi %s %s' % (utils
.brctl_cmd
, bridge
, mcmi
))
2517 def bridge_get_mcmi(self
, bridge
):
2518 return self
.read_file_oneline(
2519 '/sys/class/net/%s/bridge/multicast_membership_interval'
2523 def bridge_exists(bridge
):
2524 return os
.path
.exists('/sys/class/net/%s/bridge' % bridge
)
2527 def is_bridge_port(ifacename
):
2528 return os
.path
.exists('/sys/class/net/%s/brport' % ifacename
)
2531 def bridge_port_exists(bridge
, bridgeportname
):
2533 return os
.path
.exists('/sys/class/net/%s/brif/%s' % (bridge
, bridgeportname
))
2538 def get_bridge_ports(bridgename
):
2540 return os
.listdir('/sys/class/net/%s/brif/' % bridgename
)