]> git.proxmox.com Git - mirror_ifupdown2.git/blob - ifupdown2/addons/addressvirtual.py
addons: addressvirtual: ifquery -r doesn't display link-local address
[mirror_ifupdown2.git] / ifupdown2 / addons / addressvirtual.py
1 #!/usr/bin/python
2 #
3 # Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
4 # Author: Roopa Prabhu, roopa@cumulusnetworks.com
5 #
6
7 import os
8 import glob
9 import socket
10
11 from ipaddr import IPNetwork, IPv6Network
12
13 try:
14 from ifupdown2.ifupdown.iface import *
15 from ifupdown2.ifupdown.utils import utils
16 from ifupdown2.ifupdown.netlink import netlink
17
18 from ifupdown2.ifupdownaddons.LinkUtils import LinkUtils
19 from ifupdown2.ifupdownaddons.modulebase import moduleBase
20
21 import ifupdown2.ifupdown.statemanager as statemanager
22 import ifupdown2.ifupdown.policymanager as policymanager
23 import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
24 import ifupdown2.ifupdown.ifupdownconfig as ifupdownconfig
25 except ImportError:
26 from ifupdown.iface import *
27 from ifupdown.utils import utils
28 from ifupdown.netlink import netlink
29
30 from ifupdownaddons.LinkUtils import LinkUtils
31 from ifupdownaddons.modulebase import moduleBase
32
33 import ifupdown.statemanager as statemanager
34 import ifupdown.policymanager as policymanager
35 import ifupdown.ifupdownflags as ifupdownflags
36 import ifupdown.ifupdownconfig as ifupdownconfig
37
38
39 class addressvirtual(moduleBase):
40 """ ifupdown2 addon module to configure virtual addresses """
41
42 _modinfo = {'mhelp' : 'address module configures virtual addresses for ' +
43 'interfaces. It creates a macvlan interface for ' +
44 'every mac ip address-virtual line',
45 'attrs' : {
46 'address-virtual' :
47 { 'help' : 'bridge router virtual mac and ips',
48 'multivalue' : True,
49 'validvals' : ['<mac-ip/prefixlen-list>',],
50 'example': ['address-virtual 00:11:22:33:44:01 11.0.1.1/24 11.0.1.2/24']
51 },
52 'address-virtual-ipv6-addrgen': {
53 'help': 'enable disable ipv6 link addrgenmode',
54 'validvals': ['on', 'off'],
55 'default': 'on',
56 'example': [
57 'address-virtual-ipv6-addrgen on',
58 'address-virtual-ipv6-addrgen off'
59 ]
60 }
61 }}
62
63
64 def __init__(self, *args, **kargs):
65 moduleBase.__init__(self, *args, **kargs)
66 self.ipcmd = None
67 self._bridge_fdb_query_cache = {}
68 self.addressvirtual_with_route_metric = utils.get_boolean_from_string(
69 policymanager.policymanager_api.get_module_globals(
70 module_name=self.__class__.__name__,
71 attr='addressvirtual_with_route_metric'
72 ),
73 default=True
74 )
75
76 self.address_virtual_ipv6_addrgen_value_dict = {'on': 0, 'yes': 0, '0': 0, 'off': 1, 'no': 1, '1': 1}
77
78 def get_dependent_ifacenames(self, ifaceobj, ifacenames_all=None):
79 if ifaceobj.get_attr_value('address-virtual'):
80 ifaceobj.link_privflags |= ifaceLinkPrivFlags.ADDRESS_VIRTUAL_SLAVE
81
82 def _get_macvlan_prefix(self, ifaceobj):
83 return '%s-v' %ifaceobj.name[0:13].replace('.', '-')
84
85 def _add_addresses_to_bridge(self, ifaceobj, hwaddress):
86 # XXX: batch the addresses
87 if ifaceobj.link_kind & ifaceLinkKind.VLAN:
88 bridgename = ifaceobj.lowerifaces[0]
89 vlan = self._get_vlan_id(ifaceobj)
90 if self.ipcmd.bridge_is_vlan_aware(bridgename):
91 [self.ipcmd.bridge_fdb_add(bridgename, addr,
92 vlan) for addr in hwaddress]
93 elif self.ipcmd.is_bridge(ifaceobj.name):
94 [self.ipcmd.bridge_fdb_add(ifaceobj.name, addr)
95 for addr in hwaddress]
96
97 def _remove_addresses_from_bridge(self, ifaceobj, hwaddress):
98 # XXX: batch the addresses
99 if ifaceobj.link_kind & ifaceLinkKind.VLAN:
100 bridgename = ifaceobj.lowerifaces[0]
101 vlan = self._get_vlan_id(ifaceobj)
102 if self.ipcmd.bridge_is_vlan_aware(bridgename):
103 for addr in hwaddress:
104 try:
105 self.ipcmd.bridge_fdb_del(bridgename, addr, vlan)
106 except Exception, e:
107 self.logger.debug("%s: %s" %(ifaceobj.name, str(e)))
108 pass
109 elif self.ipcmd.is_bridge(ifaceobj.name):
110 for addr in hwaddress:
111 try:
112 self.ipcmd.bridge_fdb_del(ifaceobj.name, addr)
113 except Exception, e:
114 self.logger.debug("%s: %s" %(ifaceobj.name, str(e)))
115 pass
116
117 def _get_bridge_fdbs(self, bridgename, vlan):
118 fdbs = self._bridge_fdb_query_cache.get(bridgename)
119 if not fdbs:
120 fdbs = self.ipcmd.bridge_fdb_show_dev(bridgename)
121 if not fdbs:
122 return
123 self._bridge_fdb_query_cache[bridgename] = fdbs
124 return fdbs.get(vlan)
125
126 def _check_addresses_in_bridge(self, ifaceobj, hwaddress):
127 """ If the device is a bridge, make sure the addresses
128 are in the bridge """
129 if ifaceobj.link_kind & ifaceLinkKind.VLAN:
130 bridgename = ifaceobj.lowerifaces[0]
131 vlan = self._get_vlan_id(ifaceobj)
132 if self.ipcmd.bridge_is_vlan_aware(bridgename):
133 fdb_addrs = self._get_bridge_fdbs(bridgename, str(vlan))
134 if not fdb_addrs or hwaddress not in fdb_addrs:
135 return False
136 return True
137
138 def _fix_connected_route(self, ifaceobj, vifacename, addr):
139 #
140 # XXX: Hack to make sure the primary address
141 # is the first in the routing table.
142 #
143 # We use `ip route get` on the vrr network to see which
144 # device the kernel returns. if it is the mac vlan device,
145 # flap the macvlan device to adjust the routing table entry.
146 #
147 # flapping the macvlan device makes sure the macvlan
148 # connected route goes through delete + add, hence adjusting
149 # the order in the routing table.
150 #
151 try:
152 self.logger.info('%s: checking route entry ...' %ifaceobj.name)
153 ip = IPNetwork(addr)
154
155 # we don't support ip6 route fix yet
156 if type(ip) == IPv6Network:
157 return
158
159 route_prefix = '%s/%d' %(ip.network, ip.prefixlen)
160
161 if ifaceobj.link_privflags & ifaceLinkPrivFlags.VRF_SLAVE:
162 vrf_master = self.ipcmd.link_get_master(ifaceobj.name)
163 else:
164 vrf_master = None
165
166 dev = self.ipcmd.ip_route_get_dev(route_prefix, vrf_master=vrf_master)
167
168 if dev and dev != ifaceobj.name:
169 self.logger.info('%s: preferred routing entry ' %ifaceobj.name +
170 'seems to be of the macvlan dev %s'
171 %vifacename +
172 ' .. flapping macvlan dev to fix entry.')
173 self.ipcmd.link_down(vifacename)
174 self.ipcmd.link_up(vifacename)
175 except Exception, e:
176 self.logger.debug('%s: fixing route entry failed (%s)'
177 % (ifaceobj.name, str(e)))
178 pass
179
180 def _handle_vrf_slaves(self, macvlan_ifacename, ifaceobj):
181 vrfname = self.ipcmd.link_get_master(ifaceobj.name)
182 if vrfname:
183 self.ipcmd.link_set(macvlan_ifacename, 'master', vrfname)
184
185 def _get_macs_from_old_config(self, ifaceobj=None):
186 """ This method returns a list of the mac addresses
187 in the address-virtual attribute for the bridge. """
188 maclist = []
189 saved_ifaceobjs = statemanager.statemanager_api.get_ifaceobjs(ifaceobj.name)
190 if not saved_ifaceobjs:
191 return maclist
192 # we need the old saved configs from the statemanager
193 for oldifaceobj in saved_ifaceobjs:
194 if not oldifaceobj.get_attr_value('address-virtual'):
195 continue
196 for av in oldifaceobj.get_attr_value('address-virtual'):
197 macip = av.split()
198 if len(macip) < 2:
199 self.logger.debug("%s: incorrect old address-virtual attrs '%s'"
200 %(oldifaceobj.name, av))
201 continue
202 maclist.append(macip[0])
203 return maclist
204
205 def get_addressvirtual_ipv6_addrgen_user_conf(self, ifaceobj):
206 ipv6_addrgen = ifaceobj.get_attr_value_first('address-virtual-ipv6-addrgen')
207
208 if ipv6_addrgen:
209 # IFLA_INET6_ADDR_GEN_MODE values:
210 # 0 = eui64
211 # 1 = none
212 ipv6_addrgen_nl = self.address_virtual_ipv6_addrgen_value_dict.get(ipv6_addrgen.lower(), None)
213
214 if ipv6_addrgen_nl is None:
215 self.logger.warning('%s: invalid value "%s" for attribute address-virtual-ipv6-addrgen' % (ifaceobj.name, ipv6_addrgen))
216 else:
217 return True, ipv6_addrgen_nl
218
219 else:
220 # if user didn't configure ipv6-addrgen, should we reset to default?
221 ipv6_addrgen_nl = self.address_virtual_ipv6_addrgen_value_dict.get(
222 self.get_attr_default_value('address-virtual-ipv6-addrgen'),
223 None
224 )
225 if ipv6_addrgen_nl is not None:
226 return True, ipv6_addrgen_nl
227
228 return False, None
229
230 def _apply_address_config(self, ifaceobj, address_virtual_list):
231 purge_existing = False if ifupdownflags.flags.PERFMODE else True
232
233 lower_iface_mtu = update_mtu = None
234 if ifupdownconfig.config.get('adjust_logical_dev_mtu', '1') != '0':
235 if ifaceobj.lowerifaces and address_virtual_list:
236 update_mtu = True
237
238 user_configured_ipv6_addrgenmode, ipv6_addrgen_user_value = self.get_addressvirtual_ipv6_addrgen_user_conf(ifaceobj)
239
240 hwaddress = []
241 self.ipcmd.batch_start()
242 av_idx = 0
243 macvlan_prefix = self._get_macvlan_prefix(ifaceobj)
244 for av in address_virtual_list:
245 av_attrs = av.split()
246 if len(av_attrs) < 2:
247 self.log_error("%s: incorrect address-virtual attrs '%s'"
248 %(ifaceobj.name, av), ifaceobj,
249 raise_error=False)
250 av_idx += 1
251 continue
252
253 mac = av_attrs[0]
254 if not self.check_mac_address(ifaceobj, mac):
255 continue
256 # Create a macvlan device on this device and set the virtual
257 # router mac and ip on it
258 link_created = False
259 macvlan_ifacename = '%s%d' %(macvlan_prefix, av_idx)
260 if not self.ipcmd.link_exists(macvlan_ifacename):
261 try:
262 netlink.link_add_macvlan(ifaceobj.name, macvlan_ifacename)
263 except:
264 self.ipcmd.link_add_macvlan(ifaceobj.name, macvlan_ifacename)
265 link_created = True
266
267 # first thing we need to handle vrf enslavement
268 if (ifaceobj.link_privflags & ifaceLinkPrivFlags.VRF_SLAVE):
269 self._handle_vrf_slaves(macvlan_ifacename, ifaceobj)
270
271 if user_configured_ipv6_addrgenmode:
272 self.ipcmd.ipv6_addrgen(macvlan_ifacename, ipv6_addrgen_user_value, link_created)
273
274 ips = av_attrs[1:]
275 if mac != 'None':
276 mac = mac.lower()
277 # customer could have used UPPERCASE for MAC
278 self.ipcmd.link_set_hwaddress(macvlan_ifacename, mac)
279 hwaddress.append(mac)
280
281 if self.addressvirtual_with_route_metric and self.ipcmd.addr_metric_support():
282 metric = self.ipcmd.get_default_ip_metric()
283 else:
284 metric = None
285
286 self.ipcmd.addr_add_multiple(
287 ifaceobj,
288 macvlan_ifacename,
289 ips,
290 purge_existing,
291 metric=metric
292 )
293
294 # If link existed before, flap the link
295 if not link_created:
296
297 if not self.addressvirtual_with_route_metric or not self.ipcmd.addr_metric_support():
298 # if the system doesn't support ip addr set METRIC
299 # we need to do manually check the ordering of the ip4 routes
300 self._fix_connected_route(ifaceobj, macvlan_ifacename, ips[0])
301
302 if update_mtu:
303 lower_iface_mtu = self.ipcmd.link_get_mtu(ifaceobj.name, refresh=True)
304 update_mtu = False
305
306 if lower_iface_mtu and lower_iface_mtu != self.ipcmd.link_get_mtu(macvlan_ifacename, refresh=True):
307 try:
308 self.ipcmd.link_set_mtu(macvlan_ifacename,
309 lower_iface_mtu)
310 except Exception as e:
311 self.logger.info('%s: failed to set mtu %s: %s' %
312 (macvlan_ifacename, lower_iface_mtu, e))
313
314 # set macvlan device to up in anycase.
315 # since we auto create them here..we are responsible
316 # to bring them up here in the case they were brought down
317 # by some other entity in the system.
318 netlink.link_set_updown(macvlan_ifacename, "up")
319 else:
320 try:
321 if not self.addressvirtual_with_route_metric or not self.ipcmd.addr_metric_support():
322 # if the system doesn't support ip addr set METRIC
323 # we need to do manually check the ordering of the ip6 routes
324 self.ipcmd.fix_ipv6_route_metric(ifaceobj, macvlan_ifacename, ips)
325 except Exception as e:
326 self.logger.debug('fix_vrf_slave_ipv6_route_metric: failed: %s' % e)
327
328 # Disable IPv6 duplicate address detection on VRR interfaces
329 for key, sysval in { 'accept_dad' : '0', 'dad_transmits' : '0' }.iteritems():
330 syskey = 'net.ipv6.conf.%s.%s' % (macvlan_ifacename, key)
331 if self.sysctl_get(syskey) != sysval:
332 self.sysctl_set(syskey, sysval)
333
334 av_idx += 1
335 self.ipcmd.batch_commit()
336
337 # check the statemanager for old configs.
338 # We need to remove only the previously configured FDB entries
339 oldmacs = self._get_macs_from_old_config(ifaceobj)
340 # get a list of fdbs in old that are not in new config meaning they should
341 # be removed since they are gone from the config
342 removed_macs = [mac for mac in oldmacs if mac.lower() not in hwaddress]
343 self._remove_addresses_from_bridge(ifaceobj, removed_macs)
344 # if ifaceobj is a bridge and bridge is a vlan aware bridge
345 # add the vid to the bridge
346 self._add_addresses_to_bridge(ifaceobj, hwaddress)
347
348 def _remove_running_address_config(self, ifaceobj):
349 if not self.ipcmd.link_exists(ifaceobj.name):
350 return
351 hwaddress = []
352 self.ipcmd.batch_start()
353 macvlan_prefix = self._get_macvlan_prefix(ifaceobj)
354 for macvlan_ifacename in glob.glob("/sys/class/net/%s*" %macvlan_prefix):
355 macvlan_ifacename = os.path.basename(macvlan_ifacename)
356 if not self.ipcmd.link_exists(macvlan_ifacename):
357 continue
358 hwaddress.append(self.ipcmd.link_get_hwaddress(macvlan_ifacename))
359 self.ipcmd.link_delete(os.path.basename(macvlan_ifacename))
360 # XXX: Also delete any fdb addresses. This requires, checking mac address
361 # on individual macvlan interfaces and deleting the vlan from that.
362 self.ipcmd.batch_commit()
363 if any(hwaddress):
364 self._remove_addresses_from_bridge(ifaceobj, hwaddress)
365
366 def _remove_address_config(self, ifaceobj, address_virtual_list=None):
367 if not address_virtual_list:
368 self._remove_running_address_config(ifaceobj)
369 return
370
371 if not self.ipcmd.link_exists(ifaceobj.name):
372 return
373 hwaddress = []
374 self.ipcmd.batch_start()
375 av_idx = 0
376 macvlan_prefix = self._get_macvlan_prefix(ifaceobj)
377 for av in address_virtual_list:
378 av_attrs = av.split()
379 if len(av_attrs) < 2:
380 self.log_error("%s: incorrect address-virtual attrs '%s'"
381 %(ifaceobj.name, av), ifaceobj,
382 raise_error=False)
383 av_idx += 1
384 continue
385
386 # Delete the macvlan device on this device
387 macvlan_ifacename = '%s%d' %(macvlan_prefix, av_idx)
388 self.ipcmd.link_delete(os.path.basename(macvlan_ifacename))
389 if av_attrs[0] != 'None':
390 hwaddress.append(av_attrs[0])
391 av_idx += 1
392 self.ipcmd.batch_commit()
393 self._remove_addresses_from_bridge(ifaceobj, hwaddress)
394
395 def check_mac_address(self, ifaceobj, mac):
396 if mac == 'None':
397 return True
398 mac = mac.lower()
399 try:
400 if int(mac.split(":")[0], 16) & 1 :
401 self.log_error("%s: Multicast bit is set in the virtual mac address '%s'"
402 % (ifaceobj.name, mac), ifaceobj=ifaceobj)
403 return False
404 return True
405 except ValueError:
406 return False
407
408 def _fixup_vrf_enslavements(self, ifaceobj, ifaceobj_getfunc=None):
409 """ This function fixes up address virtual interfaces
410 (macvlans) on vrf slaves. Since this fixup is an overhead,
411 this must be called only in cases when ifupdown2 is
412 called on the vrf device or its slave and not when
413 ifupdown2 is called for all devices. When all
414 interfaces are brought up, the expectation is that
415 the normal path will fix up a vrf device or its slaves"""
416
417 if not ifaceobj_getfunc:
418 return
419 if ((ifaceobj.link_kind & ifaceLinkKind.VRF) and
420 self.ipcmd.link_exists(ifaceobj.name)):
421 # if I am a vrf device and I have slaves
422 # that have address virtual config,
423 # enslave the slaves 'address virtual
424 # interfaces (macvlans)' to myself:
425 running_slaves = self.ipcmd.link_get_lowers(ifaceobj.name)
426 if running_slaves:
427 # pick up any existing slaves of a vrf device and
428 # look for their upperdevices and enslave them to the
429 # vrf device:
430 for s in running_slaves:
431 sobjs = ifaceobj_getfunc(s)
432 if (sobjs and
433 (sobjs[0].link_privflags & ifaceLinkPrivFlags.ADDRESS_VIRTUAL_SLAVE)):
434 # enslave all its upper devices to
435 # the vrf device
436 upperdevs = self.ipcmd.link_get_uppers(sobjs[0].name)
437 if not upperdevs:
438 continue
439 for u in upperdevs:
440 # skip vrf device which
441 # will also show up in the
442 # upper device list
443 if u == ifaceobj.name:
444 continue
445 self.ipcmd.link_set(u, 'master', ifaceobj.name,
446 state='up')
447 elif ((ifaceobj.link_privflags & ifaceLinkPrivFlags.ADDRESS_VIRTUAL_SLAVE) and
448 (ifaceobj.link_privflags & ifaceLinkPrivFlags.VRF_SLAVE) and
449 self.ipcmd.link_exists(ifaceobj.name)):
450 # If I am a vrf slave and I have 'address virtual'
451 # config, make sure my addrress virtual interfaces
452 # (macvlans) are also enslaved to the vrf device
453 vrfname = ifaceobj.get_attr_value_first('vrf')
454 if not vrfname or not self.ipcmd.link_exists(vrfname):
455 return
456 running_uppers = self.ipcmd.link_get_uppers(ifaceobj.name)
457 if not running_uppers:
458 return
459 macvlan_prefix = self._get_macvlan_prefix(ifaceobj)
460 if not macvlan_prefix:
461 return
462 for u in running_uppers:
463 if u == vrfname:
464 continue
465 if u.startswith(macvlan_prefix):
466 self.ipcmd.link_set(u, 'master', vrfname,
467 state='up')
468
469 def _up(self, ifaceobj, ifaceobj_getfunc=None):
470 if not ifupdownflags.flags.ALL:
471 self._fixup_vrf_enslavements(ifaceobj, ifaceobj_getfunc)
472 address_virtual_list = ifaceobj.get_attr_value('address-virtual')
473 if not address_virtual_list:
474 # XXX: address virtual is not present. In which case,
475 # delete stale macvlan devices.
476 self._remove_address_config(ifaceobj, address_virtual_list)
477 return
478
479 if (ifaceobj.upperifaces and
480 not ifaceobj.link_privflags & ifaceLinkPrivFlags.VRF_SLAVE):
481 self.log_error('%s: invalid placement of address-virtual lines (must be configured under an interface with no upper interfaces or parent interfaces)'
482 % (ifaceobj.name), ifaceobj)
483 return
484
485 if not self.ipcmd.link_exists(ifaceobj.name):
486 return
487 self._apply_address_config(ifaceobj, address_virtual_list)
488
489 def _down(self, ifaceobj, ifaceobj_getfunc=None):
490 try:
491 self._remove_address_config(ifaceobj,
492 ifaceobj.get_attr_value('address-virtual'))
493 except Exception, e:
494 self.log_warn(str(e))
495
496 def _query_check(self, ifaceobj, ifaceobjcurr):
497 address_virtual_list = ifaceobj.get_attr_value('address-virtual')
498 if not address_virtual_list:
499 return
500 if not self.ipcmd.link_exists(ifaceobj.name):
501 return
502
503 user_config_address_virtual_ipv6_addr = ifaceobj.get_attr_value_first('address-virtual-ipv6-addrgen')
504 if user_config_address_virtual_ipv6_addr and user_config_address_virtual_ipv6_addr not in utils._string_values:
505 ifaceobjcurr.update_config_with_status('address-virtual-ipv6-addrgen', user_config_address_virtual_ipv6_addr, 1)
506 user_config_address_virtual_ipv6_addr = None
507 macvlans_running_ipv6_addr = []
508
509 av_idx = 0
510 macvlan_prefix = self._get_macvlan_prefix(ifaceobj)
511 for address_virtual in address_virtual_list:
512 av_attrs = address_virtual.split()
513 if len(av_attrs) < 2:
514 self.logger.warn("%s: incorrect address-virtual attrs '%s'"
515 %(ifaceobj.name, address_virtual))
516 av_idx += 1
517 continue
518
519 # Check if the macvlan device on this interface
520 macvlan_ifacename = '%s%d' %(macvlan_prefix, av_idx)
521 if not self.ipcmd.link_exists(macvlan_ifacename):
522 ifaceobjcurr.update_config_with_status('address-virtual',
523 '', 1)
524 av_idx += 1
525 continue
526
527 if user_config_address_virtual_ipv6_addr:
528 macvlans_running_ipv6_addr.append(self.ipcmd.get_ipv6_addrgen_mode(macvlan_ifacename))
529
530 # Check mac and ip address
531 rhwaddress = self.ipcmd.link_get_hwaddress(macvlan_ifacename)
532 raddrs = self.ipcmd.get_running_addrs(
533 ifname=macvlan_ifacename,
534 details=False,
535 addr_virtual_ifaceobj=ifaceobj
536 )
537 if not raddrs or not rhwaddress:
538 ifaceobjcurr.update_config_with_status('address-virtual', '', 1)
539 av_idx += 1
540 continue
541 try:
542 av_attrs[0] = ':'.join([i if len(i) == 2 else '0%s' % i
543 for i in av_attrs[0].split(':')])
544 except:
545 self.logger.info('%s: %s: invalid value for address-virtual (%s)'
546 % (ifaceobj.name,
547 macvlan_ifacename,
548 ' '.join(av_attrs)))
549 try:
550 if (rhwaddress == av_attrs[0].lower() and
551 self.ipcmd.compare_user_config_vs_running_state(raddrs, av_attrs[1:]) and
552 self._check_addresses_in_bridge(ifaceobj, av_attrs[0].lower())):
553 ifaceobjcurr.update_config_with_status('address-virtual',
554 address_virtual, 0)
555 else:
556 raddress_virtual = '%s %s' % (rhwaddress, ' '.join(raddrs))
557 ifaceobjcurr.update_config_with_status('address-virtual',
558 raddress_virtual, 1)
559 except:
560 raddress_virtual = '%s %s' % (rhwaddress, ' '.join(raddrs))
561 ifaceobjcurr.update_config_with_status('address-virtual',
562 raddress_virtual, 1)
563 av_idx += 1
564
565 if user_config_address_virtual_ipv6_addr:
566 bool_user_ipv6_addrgen = utils.get_boolean_from_string(user_config_address_virtual_ipv6_addr)
567 for running_ipv6_addrgen in macvlans_running_ipv6_addr:
568 if (not bool_user_ipv6_addrgen) != running_ipv6_addrgen:
569 ifaceobjcurr.update_config_with_status('address-virtual-ipv6-addrgen', user_config_address_virtual_ipv6_addr, 1)
570 return
571 ifaceobjcurr.update_config_with_status('address-virtual-ipv6-addrgen', user_config_address_virtual_ipv6_addr, 0)
572
573 def _query_running(self, ifaceobjrunning, ifaceobj_getfunc=None):
574 macvlan_prefix = self._get_macvlan_prefix(ifaceobjrunning)
575 address_virtuals = glob.glob("/sys/class/net/%s*" %macvlan_prefix)
576 macvlans_ipv6_addrgen_list = []
577 for av in address_virtuals:
578 macvlan_ifacename = os.path.basename(av)
579 rhwaddress = self.ipcmd.link_get_hwaddress(macvlan_ifacename)
580
581 raddress = []
582 for obj in ifaceobj_getfunc(ifaceobjrunning.name) or []:
583 raddress.extend(self.ipcmd.get_running_addrs(None, macvlan_ifacename, addr_virtual_ifaceobj=obj) or [])
584
585 raddress = list(set(raddress))
586
587 if not raddress:
588 self.logger.warn('%s: no running addresses'
589 %ifaceobjrunning.name)
590 raddress = []
591 ifaceobjrunning.update_config('address-virtual',
592 '%s %s' %(rhwaddress, ' '.join(raddress)))
593
594 macvlans_ipv6_addrgen_list.append((macvlan_ifacename, self.ipcmd.get_ipv6_addrgen_mode(macvlan_ifacename)))
595
596 macvlan_count = len(address_virtuals)
597 if not macvlan_count:
598 return
599 ipv6_addrgen = macvlans_ipv6_addrgen_list[0][1]
600
601 for macvlan_ifname, macvlan_ipv6_addrgen in macvlans_ipv6_addrgen_list:
602 if macvlan_ipv6_addrgen != ipv6_addrgen:
603 # one macvlan has a different ipv6-addrgen configuration
604 # we simply return, ifquery-running will print the macvlan
605 # stanzas with the ipv6-addrgen on/off attribute
606 return
607 ifaceobjrunning.update_config('address-virtual-ipv6-addrgen', 'off' if ipv6_addrgen else 'on')
608
609
610 _run_ops = {'up' : _up,
611 'down' : _down,
612 'query-checkcurr' : _query_check,
613 'query-running' : _query_running}
614
615 def get_ops(self):
616 """ returns list of ops supported by this module """
617 return self._run_ops.keys()
618
619 def _init_command_handlers(self):
620 if not self.ipcmd:
621 self.ipcmd = LinkUtils()
622
623 def run(self, ifaceobj, operation, query_ifaceobj=None,
624 ifaceobj_getfunc=None, **extra_args):
625 """ run vlan configuration on the interface object passed as argument
626
627 Args:
628 **ifaceobj** (object): iface object
629
630 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
631 'query-running'
632 Kwargs:
633 **query_ifaceobj** (object): query check ifaceobject. This is only
634 valid when op is 'query-checkcurr'. It is an object same as
635 ifaceobj, but contains running attribute values and its config
636 status. The modules can use it to return queried running state
637 of interfaces. status is success if the running state is same
638 as user required state in ifaceobj. error otherwise.
639 """
640 if ifaceobj.type == ifaceType.BRIDGE_VLAN:
641 return
642 op_handler = self._run_ops.get(operation)
643 if not op_handler:
644 return
645 self._init_command_handlers()
646 if operation == 'query-checkcurr':
647 op_handler(self, ifaceobj, query_ifaceobj)
648 else:
649 op_handler(self, ifaceobj, ifaceobj_getfunc=ifaceobj_getfunc)