3 # Copyright 2014 Cumulus Networks, Inc. All rights reserved.
4 # Author: Roopa Prabhu, roopa@cumulusnetworks.com
10 from ipaddr
import IPNetwork
, IPv4Network
, IPv6Network
, IPv4Address
, IPv6Address
12 from ifupdown
.iface
import *
13 from ifupdown
.utils
import utils
14 from ifupdownaddons
.modulebase
import moduleBase
15 from ifupdownaddons
.iproute2
import iproute2
16 from ifupdownaddons
.dhclient
import dhclient
17 import ifupdown
.policymanager
as policymanager
18 from ifupdown
.netlink
import netlink
19 import ifupdown
.ifupdownconfig
as ifupdownConfig
20 import ifupdown
.ifupdownflags
as ifupdownflags
21 import ifupdown
.statemanager
as statemanager
22 except ImportError, e
:
23 raise ImportError (str(e
) + "- required module not found")
25 class address(moduleBase
):
26 """ ifupdown2 addon module to configure address, mtu, hwaddress, alias
27 (description) on an interface """
29 _modinfo
= {'mhelp' : 'address configuration module for interfaces',
32 {'help' : 'ipv4 or ipv6 addresses',
33 'validvals' : ['<ipv4/prefixlen>', '<ipv6/prefixlen>'],
35 'example' : ['address 10.0.12.3/24',
36 'address 2000:1000:1000:1000:3::5/128']},
39 'example' : ['netmask 255.255.255.0'],
42 {'help': 'broadcast address',
43 'validvals' : ['<ipv4>', ],
44 'example' : ['broadcast 10.0.1.255']},
47 'validvals' : ['universe', 'site', 'link', 'host', 'nowhere'],
48 'example' : ['scope host']},
49 'preferred-lifetime' :
50 {'help': 'preferred lifetime',
51 'validrange' : ['0', '65535'],
52 'example' : ['preferred-lifetime forever',
53 'preferred-lifetime 10']},
55 {'help': 'default gateway',
56 'validvals' : ['<ipv4>', '<ipv6>'],
58 'example' : ['gateway 255.255.255.0']},
60 { 'help': 'interface mtu',
61 'validrange' : ['552', '9216'],
62 'example' : ['mtu 1600'],
65 {'help' : 'hw address',
66 'validvals' : ['<mac>',],
67 'example': ['hwaddress 44:38:39:00:27:b8']},
69 { 'help': 'description/alias',
70 'example' : ['alias testnetwork']},
72 { 'help': 'purge existing addresses. By default ' +
73 'any existing ip addresses on an interface are ' +
74 'purged to match persistant addresses in the ' +
75 'interfaces file. Set this attribute to \'no\'' +
76 'if you want to preserve existing addresses',
77 'validvals' : ['yes', 'no'],
79 'example' : ['address-purge yes/no']},
80 'clagd-vxlan-anycast-ip' :
81 { 'help' : 'Anycast local IP address for ' +
82 'dual connected VxLANs',
83 'validvals' : ['<ipv4>', ],
84 'example' : ['clagd-vxlan-anycast-ip 36.0.0.11']}}}
86 def __init__(self
, *args
, **kargs
):
87 moduleBase
.__init
__(self
, *args
, **kargs
)
89 self
._bridge
_fdb
_query
_cache
= {}
90 self
.default_mtu
= policymanager
.policymanager_api
.get_attr_default(module_name
=self
.__class
__.__name
__, attr
='mtu')
91 self
.max_mtu
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='max_mtu')
93 if not self
.default_mtu
:
94 self
.default_mtu
= '1500'
96 self
.logger
.info('address: using default mtu %s' %self
.default_mtu
)
99 self
.logger
.info('address: using max mtu %s' %self
.max_mtu
)
101 def syntax_check(self
, ifaceobj
, ifaceobj_getfunc
=None):
102 return (self
.syntax_check_multiple_gateway(ifaceobj
)
103 and self
.syntax_check_addr_allowed_on(ifaceobj
, True)
104 and self
.syntax_check_mtu(ifaceobj
, ifaceobj_getfunc
))
106 def syntax_check_mtu(self
, ifaceobj
, ifaceobj_getfunc
):
107 mtu
= ifaceobj
.get_attr_value_first('mtu')
109 return self
._check
_mtu
_config
(ifaceobj
, mtu
, ifaceobj_getfunc
,
113 def syntax_check_addr_allowed_on(self
, ifaceobj
, syntax_check
=False):
114 if ifaceobj
.get_attr_value('address'):
115 return utils
.is_addr_ip_allowed_on(ifaceobj
, syntax_check
=syntax_check
)
118 def _syntax_check_multiple_gateway(self
, family
, found
, addr
, type_obj
):
119 if type(IPNetwork(addr
)) == type_obj
:
121 raise Exception('%s: multiple gateways for %s family'
126 def syntax_check_multiple_gateway(self
, ifaceobj
):
130 gateways
= ifaceobj
.get_attr_value('gateway')
131 for addr
in gateways
if gateways
else []:
133 if self
._syntax
_check
_multiple
_gateway
('inet', inet
, addr
,
136 if self
._syntax
_check
_multiple
_gateway
('inet6', inet6
, addr
,
139 except Exception as e
:
140 self
.logger
.warning('%s: address: %s' % (ifaceobj
.name
, str(e
)))
144 def _address_valid(self
, addrs
):
147 if any(map(lambda a
: True if a
[:7] != '0.0.0.0'
152 def _get_hwaddress(self
, ifaceobj
):
153 hwaddress
= ifaceobj
.get_attr_value_first('hwaddress')
154 if hwaddress
and hwaddress
.startswith("ether"):
155 hwaddress
= hwaddress
[5:].strip()
158 def _process_bridge(self
, ifaceobj
, up
):
159 hwaddress
= self
._get
_hwaddress
(ifaceobj
)
160 addrs
= ifaceobj
.get_attr_value_first('address')
161 is_vlan_dev_on_vlan_aware_bridge
= False
162 is_bridge
= self
.ipcmd
.is_bridge(ifaceobj
.name
)
164 if '.' in ifaceobj
.name
:
165 (bridgename
, vlan
) = ifaceobj
.name
.split('.')
166 is_vlan_dev_on_vlan_aware_bridge
= self
.ipcmd
.bridge_is_vlan_aware(bridgename
)
167 if ((is_bridge
and not self
.ipcmd
.bridge_is_vlan_aware(ifaceobj
.name
))
168 or is_vlan_dev_on_vlan_aware_bridge
):
169 if self
._address
_valid
(addrs
):
171 self
.write_file('/proc/sys/net/ipv4/conf/%s' %ifaceobj
.name
+
174 self
.write_file('/proc/sys/net/ipv4/conf/%s' %ifaceobj
.name
+
176 if hwaddress
and is_vlan_dev_on_vlan_aware_bridge
:
178 self
.ipcmd
.bridge_fdb_add(bridgename
, hwaddress
, vlan
)
180 self
.ipcmd
.bridge_fdb_del(bridgename
, hwaddress
, vlan
)
182 def _get_anycast_addr(self
, ifaceobjlist
):
183 for ifaceobj
in ifaceobjlist
:
184 anycast_addr
= ifaceobj
.get_attr_value_first('clagd-vxlan-anycast-ip')
186 anycast_addr
= anycast_addr
+'/32'
190 def _inet_address_convert_to_cidr(self
, ifaceobjlist
):
194 for ifaceobj
in ifaceobjlist
:
195 addrs
= ifaceobj
.get_attr_value('address')
199 if not self
.syntax_check_addr_allowed_on(ifaceobj
,
201 return (False, newaddrs
, newaddr_attrs
)
202 # If user address is not in CIDR notation, convert them to CIDR
203 for addr_index
in range(0, len(addrs
)):
204 addr
= addrs
[addr_index
]
206 newaddrs
.append(addr
)
209 netmask
= ifaceobj
.get_attr_value_n('netmask', addr_index
)
211 prefixlen
= IPNetwork('%s' %addr
+
212 '/%s' %netmask
).prefixlen
213 newaddr
= addr
+ '/%s' %prefixlen
215 # we are here because there is no slash (/xx) and no netmask
216 # just let IPNetwork handle the ipv4 or ipv6 address mask
217 prefixlen
= IPNetwork(addr
).prefixlen
218 newaddr
= addr
+ '/%s' %prefixlen
219 newaddrs
.append(newaddr
)
222 for a
in ['broadcast', 'pointopoint', 'scope',
223 'preferred-lifetime']:
224 aval
= ifaceobj
.get_attr_value_n(a
, addr_index
)
229 newaddr_attrs
[newaddr
]= attrs
230 return (True, newaddrs
, newaddr_attrs
)
232 def _inet_address_list_config(self
, ifaceobj
, newaddrs
, newaddr_attrs
):
233 for addr_index
in range(0, len(newaddrs
)):
236 self
.ipcmd
.addr_add(ifaceobj
.name
, newaddrs
[addr_index
],
237 newaddr_attrs
.get(newaddrs
[addr_index
],
238 {}).get('broadcast'),
239 newaddr_attrs
.get(newaddrs
[addr_index
],
240 {}).get('pointopoint'),
241 newaddr_attrs
.get(newaddrs
[addr_index
],
243 newaddr_attrs
.get(newaddrs
[addr_index
],
244 {}).get('preferred-lifetime'))
246 self
.ipcmd
.addr_add(ifaceobj
.name
, newaddrs
[addr_index
])
248 self
.log_error(str(e
), ifaceobj
)
250 def _inet_address_config(self
, ifaceobj
, ifaceobj_getfunc
=None,
251 force_reapply
=False):
252 squash_addr_config
= (True if \
253 ifupdownConfig
.config
.get('addr_config_squash', \
254 '0') == '1' else False)
256 if (squash_addr_config
and
257 not (ifaceobj
.flags
& ifaceobj
.YOUNGEST_SIBLING
)):
260 purge_addresses
= ifaceobj
.get_attr_value_first('address-purge')
261 if not purge_addresses
:
262 purge_addresses
= 'yes'
264 if squash_addr_config
and ifaceobj
.flags
& iface
.HAS_SIBLINGS
:
265 ifaceobjlist
= ifaceobj_getfunc(ifaceobj
.name
)
267 ifaceobjlist
= [ifaceobj
]
269 (addr_supported
, newaddrs
, newaddr_attrs
) = self
._inet
_address
_convert
_to
_cidr
(ifaceobjlist
)
270 newaddrs
= utils
.get_normalized_ip_addr(ifaceobj
.name
, newaddrs
)
271 if not addr_supported
:
273 if (not squash_addr_config
and (ifaceobj
.flags
& iface
.HAS_SIBLINGS
)):
274 # if youngest sibling and squash addr is not set
275 # print a warning that addresses will not be purged
276 if (ifaceobj
.flags
& iface
.YOUNGEST_SIBLING
):
277 self
.logger
.warn('%s: interface has multiple ' %ifaceobj
.name
+
278 'iface stanzas, skip purging existing addresses')
279 purge_addresses
= 'no'
281 if not ifupdownflags
.flags
.PERFMODE
and purge_addresses
== 'yes':
282 # if perfmode is not set and purge addresses is not set to 'no'
283 # lets purge addresses not in the config
284 runningaddrs
= utils
.get_normalized_ip_addr(ifaceobj
.name
, self
.ipcmd
.addr_get(ifaceobj
.name
, details
=False))
286 # if anycast address is configured on 'lo' and is in running config
287 # add it to newaddrs so that ifreload doesn't wipe it out
288 anycast_addr
= utils
.get_normalized_ip_addr(ifaceobj
.name
, self
._get
_anycast
_addr
(ifaceobjlist
))
290 if runningaddrs
and anycast_addr
and anycast_addr
in runningaddrs
:
291 newaddrs
.append(anycast_addr
)
292 if newaddrs
== runningaddrs
:
294 self
._inet
_address
_list
_config
(ifaceobj
, newaddrs
, newaddr_attrs
)
297 # if primary address is not same, there is no need to keep any.
298 # reset all addresses
299 if (newaddrs
and runningaddrs
and
300 (newaddrs
[0] != runningaddrs
[0])):
301 self
.ipcmd
.del_addr_all(ifaceobj
.name
)
303 self
.ipcmd
.del_addr_all(ifaceobj
.name
, newaddrs
)
305 self
.log_warn(str(e
))
308 self
._inet
_address
_list
_config
(ifaceobj
, newaddrs
, newaddr_attrs
)
310 def _add_delete_gateway(self
, ifaceobj
, gateways
=[], prev_gw
=[]):
311 vrf
= ifaceobj
.get_attr_value_first('vrf')
312 metric
= ifaceobj
.get_attr_value_first('metric')
313 for del_gw
in list(set(prev_gw
) - set(gateways
)):
315 self
.ipcmd
.route_del_gateway(ifaceobj
.name
, del_gw
, vrf
, metric
)
318 for add_gw
in list(set(gateways
) - set(prev_gw
)):
320 self
.ipcmd
.route_add_gateway(ifaceobj
.name
, add_gw
, vrf
)
324 def _get_prev_gateway(self
, ifaceobj
, gateways
):
326 saved_ifaceobjs
= statemanager
.statemanager_api
.get_ifaceobjs(ifaceobj
.name
)
327 if not saved_ifaceobjs
:
329 prev_gateways
= saved_ifaceobjs
[0].get_attr_value('gateway')
330 if not prev_gateways
:
334 def _check_mtu_config(self
, ifaceobj
, mtu
, ifaceobj_getfunc
, syntaxcheck
=False):
336 if (ifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
):
338 self
.logger
.warn('%s: bridge inherits mtu from its ports. There is no need to assign mtu on a bridge' %ifaceobj
.name
)
341 self
.logger
.info('%s: bridge inherits mtu from its ports. There is no need to assign mtu on a bridge' %ifaceobj
.name
)
342 elif ifaceobj_getfunc
:
343 if ((ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BOND_SLAVE
) and
344 ifaceobj
.upperifaces
):
345 masterobj
= ifaceobj_getfunc(ifaceobj
.upperifaces
[0])
347 master_mtu
= masterobj
[0].get_attr_value_first('mtu')
348 if master_mtu
and master_mtu
!= mtu
:
350 self
.logger
.warn('%s: bond slave mtu %s is different from bond master %s mtu %s. There is no need to configure mtu on a bond slave.' %(ifaceobj
.name
, mtu
, masterobj
[0].name
, master_mtu
))
353 self
.logger
.info('%s: bond slave mtu %s is different from bond master %s mtu %s. There is no need to configure mtu on a bond slave.' %(ifaceobj
.name
, mtu
, masterobj
[0].name
, master_mtu
))
354 elif ((ifaceobj
.link_kind
& ifaceLinkKind
.VLAN
) and
355 ifaceobj
.lowerifaces
):
356 lowerobj
= ifaceobj_getfunc(ifaceobj
.lowerifaces
[0])
359 lowerdev_mtu
= lowerobj
[0].get_attr_value_first('mtu')
361 lowerdev_mtu
= self
.ipcmd
.link_get_mtu(lowerobj
[0].name
)
362 if lowerdev_mtu
and int(mtu
) > int(lowerdev_mtu
):
363 self
.logger
.warn('%s: vlan dev mtu %s is greater than lower realdev %s mtu %s'
364 %(ifaceobj
.name
, mtu
, lowerobj
[0].name
, lowerdev_mtu
))
366 elif (not lowerobj
[0].link_kind
and
367 not (lowerobj
[0].link_privflags
& ifaceLinkPrivFlags
.LOOPBACK
) and
368 self
.default_mtu
and (int(mtu
) > int(self
.default_mtu
))):
369 # only check default mtu on lower device which is a physical interface
370 self
.logger
.warn('%s: vlan dev mtu %s is greater than lower realdev %s mtu %s'
371 %(ifaceobj
.name
, mtu
, lowerobj
[0].name
, self
.default_mtu
))
373 if self
.max_mtu
and mtu
> self
.max_mtu
:
374 self
.logger
.warn('%s: specified mtu %s is greater than max mtu %s'
375 %(ifaceobj
.name
, mtu
, self
.max_mtu
))
379 def _propagate_mtu_to_upper_devs(self
, ifaceobj
, mtu
, ifaceobj_getfunc
):
380 if (not ifaceobj
.upperifaces
or
381 (ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BOND_SLAVE
) or
382 (ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.VRF_SLAVE
) or
383 (ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
)):
385 for u
in ifaceobj
.upperifaces
:
386 upperobjs
= ifaceobj_getfunc(u
)
388 not (upperobjs
[0].link_kind
& ifaceLinkKind
.VLAN
)):
390 # only adjust mtu for vlan devices on ifaceobj
391 umtu
= upperobjs
[0].get_attr_value_first('mtu')
393 running_mtu
= self
.ipcmd
.link_get_mtu(upperobjs
[0].name
)
394 if not running_mtu
or (running_mtu
!= mtu
):
395 self
.ipcmd
.link_set(u
, 'mtu', mtu
)
397 def _process_mtu_config(self
, ifaceobj
, ifaceobj_getfunc
):
398 mtu
= ifaceobj
.get_attr_value_first('mtu')
400 if not self
._check
_mtu
_config
(ifaceobj
, mtu
, ifaceobj_getfunc
):
402 running_mtu
= self
.ipcmd
.link_get_mtu(ifaceobj
.name
)
403 if not running_mtu
or (running_mtu
and running_mtu
!= mtu
):
404 self
.ipcmd
.link_set(ifaceobj
.name
, 'mtu', mtu
)
405 if (not ifupdownflags
.flags
.ALL
and
406 not ifaceobj
.link_kind
and
407 ifupdownConfig
.config
.get('adjust_logical_dev_mtu', '1') != '0'):
408 # This is additional cost to us, so do it only when
409 # ifupdown2 is called on a particular interface and
410 # it is a physical interface
411 self
._propagate
_mtu
_to
_upper
_devs
(ifaceobj
, mtu
, ifaceobj_getfunc
)
414 if ifaceobj
.link_kind
:
415 # bonds and vxlan devices need an explicit set of mtu.
416 # bridges don't need mtu set
417 if (ifaceobj
.link_kind
& ifaceLinkKind
.BOND
or
418 ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
):
419 running_mtu
= self
.ipcmd
.link_get_mtu(ifaceobj
.name
)
420 if (self
.default_mtu
and running_mtu
!= self
.default_mtu
):
421 self
.ipcmd
.link_set(ifaceobj
.name
, 'mtu', self
.default_mtu
)
423 if (ifupdownConfig
.config
.get('adjust_logical_dev_mtu', '1') != '0'
424 and ifaceobj
.lowerifaces
):
425 # set vlan interface mtu to lower device mtu
426 if (ifaceobj
.link_kind
& ifaceLinkKind
.VLAN
):
427 lower_iface_mtu
= self
.ipcmd
.link_get_mtu(ifaceobj
.lowerifaces
[0], refresh
=True)
428 if not lower_iface_mtu
== self
.ipcmd
.link_get_mtu(ifaceobj
.name
):
429 self
.ipcmd
.link_set_mtu(ifaceobj
.name
, lower_iface_mtu
)
431 elif (not (ifaceobj
.name
== 'lo') and not ifaceobj
.link_kind
and
432 not (ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BOND_SLAVE
) and
434 # logical devices like bridges and vlan devices rely on mtu
435 # from their lower devices. ie mtu travels from
436 # lower devices to upper devices. For bonds mtu travels from
437 # upper to lower devices. running mtu depends on upper and
438 # lower device mtu. With all this implicit mtu
439 # config by the kernel in play, we try to be cautious here
440 # on which devices we want to reset mtu to default.
441 # essentially only physical interfaces which are not bond slaves
442 running_mtu
= self
.ipcmd
.link_get_mtu(ifaceobj
.name
)
443 if running_mtu
!= self
.default_mtu
:
444 self
.ipcmd
.link_set(ifaceobj
.name
, 'mtu', self
.default_mtu
)
446 def _up(self
, ifaceobj
, ifaceobj_getfunc
=None):
447 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
449 addr_method
= ifaceobj
.addr_method
450 force_reapply
= False
452 # release any stale dhcp addresses if present
453 if (addr_method
!= "dhcp" and not ifupdownflags
.flags
.PERFMODE
and
454 not (ifaceobj
.flags
& iface
.HAS_SIBLINGS
)):
455 # if not running in perf mode and ifaceobj does not have
456 # any sibling iface objects, kill any stale dhclient
458 dhclientcmd
= dhclient()
459 if dhclientcmd
.is_running(ifaceobj
.name
):
460 # release any dhcp leases
461 dhclientcmd
.release(ifaceobj
.name
)
463 elif dhclientcmd
.is_running6(ifaceobj
.name
):
464 dhclientcmd
.release6(ifaceobj
.name
)
469 self
.ipcmd
.batch_start()
470 if addr_method
!= "dhcp":
471 self
._inet
_address
_config
(ifaceobj
, ifaceobj_getfunc
,
473 self
._process
_mtu
_config
(ifaceobj
, ifaceobj_getfunc
)
475 alias
= ifaceobj
.get_attr_value_first('alias')
477 self
.ipcmd
.link_set_alias(ifaceobj
.name
, alias
)
479 self
.ipcmd
.batch_commit()
480 except Exception as e
:
481 self
.log_error('%s: %s' % (ifaceobj
.name
, str(e
)), ifaceobj
, raise_error
=False)
484 hwaddress
= self
._get
_hwaddress
(ifaceobj
)
486 running_hwaddress
= None
487 if not ifupdownflags
.flags
.PERFMODE
: # system is clean
488 running_hwaddress
= self
.ipcmd
.link_get_hwaddress(ifaceobj
.name
)
489 if hwaddress
!= running_hwaddress
:
491 netlink
.link_set_updown(ifaceobj
.name
, "down")
492 if ifaceobj
.link_kind
& ifaceLinkKind
.BOND
:
493 # if bond, down all the slaves
494 if ifaceobj
.lowerifaces
:
495 for l
in ifaceobj
.lowerifaces
:
496 netlink
.link_set_updown(l
, "down")
499 self
.ipcmd
.link_set(ifaceobj
.name
, 'address', hwaddress
)
501 netlink
.link_set_updown(ifaceobj
.name
, "up")
503 for l
in ifaceobj
.lowerifaces
:
504 netlink
.link_set_updown(l
, "up")
506 # Handle special things on a bridge
507 self
._process
_bridge
(ifaceobj
, True)
509 self
.log_error('%s: %s' %(ifaceobj
.name
, str(e
)), ifaceobj
)
511 if addr_method
!= "dhcp":
512 gateways
= ifaceobj
.get_attr_value('gateway')
515 prev_gw
= self
._get
_prev
_gateway
(ifaceobj
, gateways
)
516 self
._add
_delete
_gateway
(ifaceobj
, gateways
, prev_gw
)
519 def _down(self
, ifaceobj
, ifaceobj_getfunc
=None):
521 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
523 addr_method
= ifaceobj
.addr_method
524 if addr_method
!= "dhcp":
525 if ifaceobj
.get_attr_value_first('address-purge')=='no':
526 addrlist
= ifaceobj
.get_attr_value('address')
527 for addr
in addrlist
:
528 self
.ipcmd
.addr_del(ifaceobj
.name
, addr
)
529 #self.ipcmd.addr_del(ifaceobj.name, ifaceobj.get_attr_value('address')[0])
531 self
.ipcmd
.del_addr_all(ifaceobj
.name
)
532 mtu
= ifaceobj
.get_attr_value_first('mtu')
533 if (not ifaceobj
.link_kind
and mtu
and
534 self
.default_mtu
and (mtu
!= self
.default_mtu
)):
535 self
.ipcmd
.link_set(ifaceobj
.name
, 'mtu', self
.default_mtu
)
536 alias
= ifaceobj
.get_attr_value_first('alias')
538 filename
= '/sys/class/net/%s/ifalias' %ifaceobj
.name
539 self
.logger
.info('executing echo "" > %s' %filename
)
540 os
.system('echo "" > %s' %filename
)
541 # XXX hwaddress reset cannot happen because we dont know last
544 # Handle special things on a bridge
545 self
._process
_bridge
(ifaceobj
, False)
547 self
.logger
.debug('%s : %s' %(ifaceobj
.name
, str(e
)))
550 def _get_iface_addresses(self
, ifaceobj
):
551 addrlist
= ifaceobj
.get_attr_value('address')
554 if not addrlist
: return None
555 for addrindex
in range(0, len(addrlist
)):
556 addr
= addrlist
[addrindex
]
557 netmask
= ifaceobj
.get_attr_value_n('netmask', addrindex
)
559 prefixlen
= IPNetwork('%s' %addr
+
560 '/%s' %netmask
).prefixlen
561 addr
= addr
+ '/%s' %prefixlen
562 outaddrlist
.append(addr
)
565 def _get_bridge_fdbs(self
, bridgename
, vlan
):
566 fdbs
= self
._bridge
_fdb
_query
_cache
.get(bridgename
)
568 fdbs
= self
.ipcmd
.bridge_fdb_show_dev(bridgename
)
571 self
._bridge
_fdb
_query
_cache
[bridgename
] = fdbs
572 return fdbs
.get(vlan
)
574 def _check_addresses_in_bridge(self
, ifaceobj
, hwaddress
):
575 """ If the device is a bridge, make sure the addresses
576 are in the bridge """
577 if '.' in ifaceobj
.name
:
578 (bridgename
, vlan
) = ifaceobj
.name
.split('.')
579 if self
.ipcmd
.bridge_is_vlan_aware(bridgename
):
580 fdb_addrs
= self
._get
_bridge
_fdbs
(bridgename
, vlan
)
581 if not fdb_addrs
or hwaddress
not in fdb_addrs
:
585 def _query_check(self
, ifaceobj
, ifaceobjcurr
, ifaceobj_getfunc
=None):
586 runningaddrsdict
= None
587 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
588 self
.logger
.debug('iface %s not found' %ifaceobj
.name
)
590 addr_method
= ifaceobj
.addr_method
591 self
.query_n_update_ifaceobjcurr_attr(ifaceobj
, ifaceobjcurr
,
592 'mtu', self
.ipcmd
.link_get_mtu
)
593 hwaddress
= self
._get
_hwaddress
(ifaceobj
)
595 rhwaddress
= self
.ipcmd
.link_get_hwaddress(ifaceobj
.name
)
596 if not rhwaddress
or rhwaddress
!= hwaddress
:
597 ifaceobjcurr
.update_config_with_status('hwaddress', rhwaddress
,
599 elif not self
._check
_addresses
_in
_bridge
(ifaceobj
, hwaddress
):
600 # XXX: hw address is not in bridge
601 ifaceobjcurr
.update_config_with_status('hwaddress', rhwaddress
,
603 ifaceobjcurr
.status_str
= 'bridge fdb error'
605 ifaceobjcurr
.update_config_with_status('hwaddress', rhwaddress
,
607 self
.query_n_update_ifaceobjcurr_attr(ifaceobj
, ifaceobjcurr
,
608 'alias', self
.ipcmd
.link_get_alias
)
610 if addr_method
== 'dhcp':
612 addrs
= utils
.get_normalized_ip_addr(ifaceobj
.name
,
613 self
._get
_iface
_addresses
(ifaceobj
))
614 runningaddrsdict
= self
.ipcmd
.addr_get(ifaceobj
.name
)
615 # if anycast address is configured on 'lo' and is in running config
616 # add it to addrs so that query_check doesn't fail
617 anycast_addr
= utils
.get_normalized_ip_addr(ifaceobj
.name
, ifaceobj
.get_attr_value_first('clagd-vxlan-anycast-ip'))
619 anycast_addr
= anycast_addr
+'/32'
620 if runningaddrsdict
and anycast_addr
and runningaddrsdict
.get(anycast_addr
):
621 addrs
.append(anycast_addr
)
623 # Set ifaceobjcurr method and family
624 ifaceobjcurr
.addr_method
= ifaceobj
.addr_method
625 ifaceobjcurr
.addr_family
= ifaceobj
.addr_family
626 if not runningaddrsdict
and not addrs
:
628 runningaddrs
= runningaddrsdict
.keys() if runningaddrsdict
else []
629 if runningaddrs
!= addrs
:
630 runningaddrsset
= set(runningaddrs
) if runningaddrs
else set([])
631 addrsset
= set(addrs
) if addrs
else set([])
632 if (ifaceobj
.flags
& iface
.HAS_SIBLINGS
):
635 # only check for addresses present in running config
636 addrsdiff
= addrsset
.difference(runningaddrsset
)
638 if addr
in addrsdiff
:
639 ifaceobjcurr
.update_config_with_status('address',
642 ifaceobjcurr
.update_config_with_status('address',
645 addrsdiff
= addrsset
.symmetric_difference(runningaddrsset
)
646 for addr
in addrsset
.union(runningaddrsset
):
647 if addr
in addrsdiff
:
648 ifaceobjcurr
.update_config_with_status('address',
651 ifaceobjcurr
.update_config_with_status('address',
654 [ifaceobjcurr
.update_config_with_status('address',
655 addr
, 0) for addr
in addrs
]
656 #XXXX Check broadcast address, scope, etc
659 def _query_running(self
, ifaceobjrunning
, ifaceobj_getfunc
=None):
660 if not self
.ipcmd
.link_exists(ifaceobjrunning
.name
):
661 self
.logger
.debug('iface %s not found' %ifaceobjrunning
.name
)
663 dhclientcmd
= dhclient()
664 if (dhclientcmd
.is_running(ifaceobjrunning
.name
) or
665 dhclientcmd
.is_running6(ifaceobjrunning
.name
)):
666 # If dhcp is configured on the interface, we skip it
668 isloopback
= self
.ipcmd
.link_isloopback(ifaceobjrunning
.name
)
670 default_addrs
= ['127.0.0.1/8', '::1/128']
671 ifaceobjrunning
.addr_family
.append('inet')
672 ifaceobjrunning
.addr_method
= 'loopback'
675 runningaddrsdict
= self
.ipcmd
.addr_get(ifaceobjrunning
.name
)
677 [ifaceobjrunning
.update_config('address', addr
)
678 for addr
, addrattrs
in runningaddrsdict
.items()
679 if addr
not in default_addrs
]
680 mtu
= self
.ipcmd
.link_get_mtu(ifaceobjrunning
.name
)
682 (ifaceobjrunning
.name
== 'lo' and mtu
!= '16436') or
683 (ifaceobjrunning
.name
!= 'lo' and
684 mtu
!= self
.get_mod_subattr('mtu', 'default'))):
685 ifaceobjrunning
.update_config('mtu', mtu
)
686 alias
= self
.ipcmd
.link_get_alias(ifaceobjrunning
.name
)
688 ifaceobjrunning
.update_config('alias', alias
)
691 _run_ops
= {'up' : _up
,
693 'query-checkcurr' : _query_check
,
694 'query-running' : _query_running
}
697 """ returns list of ops supported by this module """
698 return self
._run
_ops
.keys()
700 def _init_command_handlers(self
):
702 self
.ipcmd
= iproute2()
704 def run(self
, ifaceobj
, operation
, query_ifaceobj
=None, ifaceobj_getfunc
=None):
705 """ run address configuration on the interface object passed as argument
708 **ifaceobj** (object): iface object
710 **operation** (str): any of 'up', 'down', 'query-checkcurr',
713 query_ifaceobj (object): query check ifaceobject. This is only
714 valid when op is 'query-checkcurr'. It is an object same as
715 ifaceobj, but contains running attribute values and its config
716 status. The modules can use it to return queried running state
717 of interfaces. status is success if the running state is same
718 as user required state in ifaceobj. error otherwise.
720 if ifaceobj
.type == ifaceType
.BRIDGE_VLAN
:
722 op_handler
= self
._run
_ops
.get(operation
)
725 self
._init
_command
_handlers
()
726 if operation
== 'query-checkcurr':
727 op_handler(self
, ifaceobj
, query_ifaceobj
,
728 ifaceobj_getfunc
=ifaceobj_getfunc
)
730 op_handler(self
, ifaceobj
,
731 ifaceobj_getfunc
=ifaceobj_getfunc
)