]> git.proxmox.com Git - mirror_ifupdown2.git/blame - ifupdown2/addons/addressvirtual.py
addons: addressvirtual: ifquery -r doesn't display link-local address
[mirror_ifupdown2.git] / ifupdown2 / addons / addressvirtual.py
CommitLineData
15ef32ea
RP
1#!/usr/bin/python
2#
d486dd0d 3# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
15ef32ea
RP
4# Author: Roopa Prabhu, roopa@cumulusnetworks.com
5#
6
15ef32ea
RP
7import os
8import glob
007cae35 9import socket
15ef32ea 10
d486dd0d
JF
11from ipaddr import IPNetwork, IPv6Network
12
13try:
14 from ifupdown2.ifupdown.iface import *
7b711dc5 15 from ifupdown2.ifupdown.utils import utils
d486dd0d
JF
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
23e8546d 22 import ifupdown2.ifupdown.policymanager as policymanager
d486dd0d
JF
23 import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
24 import ifupdown2.ifupdown.ifupdownconfig as ifupdownconfig
25except ImportError:
26 from ifupdown.iface import *
7b711dc5 27 from ifupdown.utils import utils
d486dd0d
JF
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
23e8546d 34 import ifupdown.policymanager as policymanager
d486dd0d
JF
35 import ifupdown.ifupdownflags as ifupdownflags
36 import ifupdown.ifupdownconfig as ifupdownconfig
37
38
15ef32ea
RP
39class 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' :
482b2fab 47 { 'help' : 'bridge router virtual mac and ips',
100ab3ea 48 'multivalue' : True,
2c592263 49 'validvals' : ['<mac-ip/prefixlen-list>',],
7b711dc5
JF
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': [
b478792b
JF
57 'address-virtual-ipv6-addrgen on',
58 'address-virtual-ipv6-addrgen off'
7b711dc5
JF
59 ]
60 }
61 }}
15ef32ea 62
8e113d63 63
15ef32ea
RP
64 def __init__(self, *args, **kargs):
65 moduleBase.__init__(self, *args, **kargs)
66 self.ipcmd = None
8e113d63 67 self._bridge_fdb_query_cache = {}
23e8546d
JF
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 )
15ef32ea 75
17da0561
JF
76 self.address_virtual_ipv6_addrgen_value_dict = {'on': 0, 'yes': 0, '0': 0, 'off': 1, 'no': 1, '1': 1}
77
42e85fc8
RP
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
15ef32ea 81
aaef0a79
RP
82 def _get_macvlan_prefix(self, ifaceobj):
83 return '%s-v' %ifaceobj.name[0:13].replace('.', '-')
84
e1601369 85 def _add_addresses_to_bridge(self, ifaceobj, hwaddress):
8e113d63 86 # XXX: batch the addresses
d486dd0d
JF
87 if ifaceobj.link_kind & ifaceLinkKind.VLAN:
88 bridgename = ifaceobj.lowerifaces[0]
89 vlan = self._get_vlan_id(ifaceobj)
e1601369
RP
90 if self.ipcmd.bridge_is_vlan_aware(bridgename):
91 [self.ipcmd.bridge_fdb_add(bridgename, addr,
92 vlan) for addr in hwaddress]
8e113d63
RP
93 elif self.ipcmd.is_bridge(ifaceobj.name):
94 [self.ipcmd.bridge_fdb_add(ifaceobj.name, addr)
95 for addr in hwaddress]
e1601369
RP
96
97 def _remove_addresses_from_bridge(self, ifaceobj, hwaddress):
8e113d63 98 # XXX: batch the addresses
d486dd0d
JF
99 if ifaceobj.link_kind & ifaceLinkKind.VLAN:
100 bridgename = ifaceobj.lowerifaces[0]
101 vlan = self._get_vlan_id(ifaceobj)
e1601369 102 if self.ipcmd.bridge_is_vlan_aware(bridgename):
55072bd1
ST
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
8e113d63 109 elif self.ipcmd.is_bridge(ifaceobj.name):
55072bd1
ST
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
8e113d63
RP
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 """
d486dd0d
JF
129 if ifaceobj.link_kind & ifaceLinkKind.VLAN:
130 bridgename = ifaceobj.lowerifaces[0]
131 vlan = self._get_vlan_id(ifaceobj)
8e113d63 132 if self.ipcmd.bridge_is_vlan_aware(bridgename):
d486dd0d 133 fdb_addrs = self._get_bridge_fdbs(bridgename, str(vlan))
8e113d63
RP
134 if not fdb_addrs or hwaddress not in fdb_addrs:
135 return False
136 return True
e1601369 137
00f6105d
RP
138 def _fix_connected_route(self, ifaceobj, vifacename, addr):
139 #
d486dd0d 140 # XXX: Hack to make sure the primary address
00f6105d
RP
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.
d486dd0d 146 #
00f6105d
RP
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)
d486dd0d
JF
154
155 # we don't support ip6 route fix yet
156 if type(ip) == IPv6Network:
157 return
158
00f6105d
RP
159 route_prefix = '%s/%d' %(ip.network, ip.prefixlen)
160
aa895ecd
JF
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
d486dd0d 168 if dev and dev != ifaceobj.name:
00f6105d
RP
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)'
d486dd0d 177 % (ifaceobj.name, str(e)))
00f6105d
RP
178 pass
179
1b284018
RP
180 def _handle_vrf_slaves(self, macvlan_ifacename, ifaceobj):
181 vrfname = self.ipcmd.link_get_master(ifaceobj.name)
182 if vrfname:
d486dd0d 183 self.ipcmd.link_set(macvlan_ifacename, 'master', vrfname)
1b284018 184
55072bd1
ST
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
7b711dc5
JF
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:
007cae35
JF
209 # IFLA_INET6_ADDR_GEN_MODE values:
210 # 0 = eui64
211 # 1 = none
17da0561 212 ipv6_addrgen_nl = self.address_virtual_ipv6_addrgen_value_dict.get(ipv6_addrgen.lower(), None)
007cae35
JF
213
214 if ipv6_addrgen_nl is None:
007cae35
JF
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
7b711dc5 218
17da0561
JF
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
7b711dc5
JF
228 return False, None
229
e1601369 230 def _apply_address_config(self, ifaceobj, address_virtual_list):
fc5e1735 231 purge_existing = False if ifupdownflags.flags.PERFMODE else True
15ef32ea 232
9e0be374 233 lower_iface_mtu = update_mtu = None
d486dd0d 234 if ifupdownconfig.config.get('adjust_logical_dev_mtu', '1') != '0':
9e0be374
JF
235 if ifaceobj.lowerifaces and address_virtual_list:
236 update_mtu = True
237
007cae35 238 user_configured_ipv6_addrgenmode, ipv6_addrgen_user_value = self.get_addressvirtual_ipv6_addrgen_user_conf(ifaceobj)
7b711dc5 239
e1601369 240 hwaddress = []
15ef32ea
RP
241 self.ipcmd.batch_start()
242 av_idx = 0
aaef0a79 243 macvlan_prefix = self._get_macvlan_prefix(ifaceobj)
15ef32ea
RP
244 for av in address_virtual_list:
245 av_attrs = av.split()
246 if len(av_attrs) < 2:
bf3eda91
RP
247 self.log_error("%s: incorrect address-virtual attrs '%s'"
248 %(ifaceobj.name, av), ifaceobj,
249 raise_error=False)
15ef32ea
RP
250 av_idx += 1
251 continue
252
4d3dc0f7
N
253 mac = av_attrs[0]
254 if not self.check_mac_address(ifaceobj, mac):
255 continue
15ef32ea
RP
256 # Create a macvlan device on this device and set the virtual
257 # router mac and ip on it
00f6105d 258 link_created = False
cb46a208 259 macvlan_ifacename = '%s%d' %(macvlan_prefix, av_idx)
e74d01e1 260 if not self.ipcmd.link_exists(macvlan_ifacename):
d486dd0d
JF
261 try:
262 netlink.link_add_macvlan(ifaceobj.name, macvlan_ifacename)
263 except:
264 self.ipcmd.link_add_macvlan(ifaceobj.name, macvlan_ifacename)
00f6105d 265 link_created = True
d486dd0d
JF
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
007cae35
JF
271 if user_configured_ipv6_addrgenmode:
272 self.ipcmd.ipv6_addrgen(macvlan_ifacename, ipv6_addrgen_user_value, link_created)
7b711dc5 273
5df79763
ST
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)
23e8546d
JF
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
dfaa8a2d
JF
286 self.ipcmd.addr_add_multiple(
287 ifaceobj,
288 macvlan_ifacename,
289 ips,
290 purge_existing,
23e8546d 291 metric=metric
dfaa8a2d 292 )
9e0be374 293
00f6105d
RP
294 # If link existed before, flap the link
295 if not link_created:
20e547e7 296
23e8546d 297 if not self.addressvirtual_with_route_metric or not self.ipcmd.addr_metric_support():
20e547e7
JF
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
9e0be374 302 if update_mtu:
0493bac6 303 lower_iface_mtu = self.ipcmd.link_get_mtu(ifaceobj.name, refresh=True)
9e0be374
JF
304 update_mtu = False
305
d486dd0d 306 if lower_iface_mtu and lower_iface_mtu != self.ipcmd.link_get_mtu(macvlan_ifacename, refresh=True):
0493bac6
JF
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))
9e0be374 313
dc3f4c45
RP
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")
d486dd0d
JF
319 else:
320 try:
23e8546d 321 if not self.addressvirtual_with_route_metric or not self.ipcmd.addr_metric_support():
dfaa8a2d
JF
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)
d486dd0d
JF
325 except Exception as e:
326 self.logger.debug('fix_vrf_slave_ipv6_route_metric: failed: %s' % e)
1b284018 327
f8ad40ce
SE
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
15ef32ea
RP
334 av_idx += 1
335 self.ipcmd.batch_commit()
336
55072bd1
ST
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
5df79763 342 removed_macs = [mac for mac in oldmacs if mac.lower() not in hwaddress]
55072bd1 343 self._remove_addresses_from_bridge(ifaceobj, removed_macs)
e1601369
RP
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):
15ef32ea 350 return
e1601369 351 hwaddress = []
15ef32ea 352 self.ipcmd.batch_start()
aaef0a79 353 macvlan_prefix = self._get_macvlan_prefix(ifaceobj)
55072bd1 354 for macvlan_ifacename in glob.glob("/sys/class/net/%s*" %macvlan_prefix):
e1601369
RP
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))
15ef32ea 359 self.ipcmd.link_delete(os.path.basename(macvlan_ifacename))
e1601369
RP
360 # XXX: Also delete any fdb addresses. This requires, checking mac address
361 # on individual macvlan interfaces and deleting the vlan from that.
15ef32ea 362 self.ipcmd.batch_commit()
e1601369
RP
363 if any(hwaddress):
364 self._remove_addresses_from_bridge(ifaceobj, hwaddress)
15ef32ea 365
e1601369
RP
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
aaef0a79 376 macvlan_prefix = self._get_macvlan_prefix(ifaceobj)
e1601369
RP
377 for av in address_virtual_list:
378 av_attrs = av.split()
379 if len(av_attrs) < 2:
bf3eda91
RP
380 self.log_error("%s: incorrect address-virtual attrs '%s'"
381 %(ifaceobj.name, av), ifaceobj,
382 raise_error=False)
e1601369
RP
383 av_idx += 1
384 continue
385
386 # Delete the macvlan device on this device
cb46a208 387 macvlan_ifacename = '%s%d' %(macvlan_prefix, av_idx)
e1601369
RP
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)
15ef32ea 394
4d3dc0f7
N
395 def check_mac_address(self, ifaceobj, mac):
396 if mac == 'None':
d486dd0d 397 return True
4d3dc0f7
N
398 mac = mac.lower()
399 try:
586535e8 400 if int(mac.split(":")[0], 16) & 1 :
5b1fffaf
JF
401 self.log_error("%s: Multicast bit is set in the virtual mac address '%s'"
402 % (ifaceobj.name, mac), ifaceobj=ifaceobj)
4d3dc0f7
N
403 return False
404 return True
5b1fffaf 405 except ValueError:
4d3dc0f7
N
406 return False
407
42e85fc8
RP
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
d486dd0d
JF
445 self.ipcmd.link_set(u, 'master', ifaceobj.name,
446 state='up')
42e85fc8
RP
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):
d486dd0d
JF
466 self.ipcmd.link_set(u, 'master', vrfname,
467 state='up')
42e85fc8
RP
468
469 def _up(self, ifaceobj, ifaceobj_getfunc=None):
470 if not ifupdownflags.flags.ALL:
471 self._fixup_vrf_enslavements(ifaceobj, ifaceobj_getfunc)
15ef32ea
RP
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,
00f6105d 475 # delete stale macvlan devices.
e1601369 476 self._remove_address_config(ifaceobj, address_virtual_list)
15ef32ea
RP
477 return
478
1b284018
RP
479 if (ifaceobj.upperifaces and
480 not ifaceobj.link_privflags & ifaceLinkPrivFlags.VRF_SLAVE):
f466af7a
JF
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
e1601369 485 if not self.ipcmd.link_exists(ifaceobj.name):
15ef32ea 486 return
e1601369 487 self._apply_address_config(ifaceobj, address_virtual_list)
15ef32ea 488
42e85fc8 489 def _down(self, ifaceobj, ifaceobj_getfunc=None):
15ef32ea 490 try:
cb46a208
RP
491 self._remove_address_config(ifaceobj,
492 ifaceobj.get_attr_value('address-virtual'))
15ef32ea
RP
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
cb46a208
RP
500 if not self.ipcmd.link_exists(ifaceobj.name):
501 return
007cae35
JF
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
15ef32ea 509 av_idx = 0
aaef0a79 510 macvlan_prefix = self._get_macvlan_prefix(ifaceobj)
15ef32ea
RP
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
cb46a208
RP
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
007cae35
JF
526
527 if user_config_address_virtual_ipv6_addr:
528 macvlans_running_ipv6_addr.append(self.ipcmd.get_ipv6_addrgen_mode(macvlan_ifacename))
529
cb46a208
RP
530 # Check mac and ip address
531 rhwaddress = self.ipcmd.link_get_hwaddress(macvlan_ifacename)
d486dd0d
JF
532 raddrs = self.ipcmd.get_running_addrs(
533 ifname=macvlan_ifacename,
534 details=False,
535 addr_virtual_ifaceobj=ifaceobj
536 )
cb46a208
RP
537 if not raddrs or not rhwaddress:
538 ifaceobjcurr.update_config_with_status('address-virtual', '', 1)
539 av_idx += 1
540 continue
b6688146
JF
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)))
90649d37 549 try:
d486dd0d
JF
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())):
90649d37
JF
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)
15ef32ea 563 av_idx += 1
007cae35
JF
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)
15ef32ea 572
42e85fc8 573 def _query_running(self, ifaceobjrunning, ifaceobj_getfunc=None):
aaef0a79 574 macvlan_prefix = self._get_macvlan_prefix(ifaceobjrunning)
8e113d63 575 address_virtuals = glob.glob("/sys/class/net/%s*" %macvlan_prefix)
007cae35 576 macvlans_ipv6_addrgen_list = []
8e113d63
RP
577 for av in address_virtuals:
578 macvlan_ifacename = os.path.basename(av)
579 rhwaddress = self.ipcmd.link_get_hwaddress(macvlan_ifacename)
c3175b31
JF
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
8e113d63
RP
587 if not raddress:
588 self.logger.warn('%s: no running addresses'
589 %ifaceobjrunning.name)
590 raddress = []
591 ifaceobjrunning.update_config('address-virtual',
c3175b31 592 '%s %s' %(rhwaddress, ' '.join(raddress)))
007cae35
JF
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
15ef32ea
RP
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:
d486dd0d 621 self.ipcmd = LinkUtils()
15ef32ea 622
42e85fc8
RP
623 def run(self, ifaceobj, operation, query_ifaceobj=None,
624 ifaceobj_getfunc=None, **extra_args):
15ef32ea
RP
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 """
84ca006f
RP
640 if ifaceobj.type == ifaceType.BRIDGE_VLAN:
641 return
15ef32ea
RP
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:
42e85fc8 649 op_handler(self, ifaceobj, ifaceobj_getfunc=ifaceobj_getfunc)