]> git.proxmox.com Git - mirror_ifupdown2.git/blame - ifupdown2/addons/addressvirtual.py
SONAR: fix iface.py: Import only needed names or import the module and then use its...
[mirror_ifupdown2.git] / ifupdown2 / addons / addressvirtual.py
CommitLineData
35681c06 1#!/usr/bin/env python3
15ef32ea 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
0e936c3f 9import ipaddress
223ba5af 10import subprocess
15ef32ea 11
5bc963f0 12from collections import deque
d486dd0d
JF
13
14try:
3eb08b79 15 from ifupdown2.lib.addon import AddonWithIpBlackList
421e9573 16 from ifupdown2.ifupdown.iface import ifaceType, ifaceLinkKind, ifaceLinkPrivFlags, ifaceStatus
7b711dc5 17 from ifupdown2.ifupdown.utils import utils
d486dd0d 18
32d448a8
JF
19 from ifupdown2.nlmanager.nlpacket import Link
20
d486dd0d
JF
21 from ifupdown2.ifupdownaddons.modulebase import moduleBase
22
0e936c3f
JF
23 import ifupdown2.nlmanager.ipnetwork as ipnetwork
24
d486dd0d 25 import ifupdown2.ifupdown.statemanager as statemanager
23e8546d 26 import ifupdown2.ifupdown.policymanager as policymanager
d486dd0d
JF
27 import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
28 import ifupdown2.ifupdown.ifupdownconfig as ifupdownconfig
bd441a51 29except (ImportError, ModuleNotFoundError):
3eb08b79 30 from lib.addon import AddonWithIpBlackList
421e9573 31 from ifupdown.iface import ifaceType, ifaceLinkKind, ifaceLinkPrivFlags, ifaceStatus
7b711dc5 32 from ifupdown.utils import utils
d486dd0d 33
32d448a8
JF
34 from nlmanager.nlpacket import Link
35
d486dd0d
JF
36 from ifupdownaddons.modulebase import moduleBase
37
0e936c3f
JF
38 import nlmanager.ipnetwork as ipnetwork
39
d486dd0d 40 import ifupdown.statemanager as statemanager
23e8546d 41 import ifupdown.policymanager as policymanager
d486dd0d
JF
42 import ifupdown.ifupdownflags as ifupdownflags
43 import ifupdown.ifupdownconfig as ifupdownconfig
44
45
3eb08b79 46class addressvirtual(AddonWithIpBlackList, moduleBase):
15ef32ea
RP
47 """ ifupdown2 addon module to configure virtual addresses """
48
223ba5af
JF
49 _modinfo = {
50 "mhelp": "address module configures virtual addresses for interfaces. "
51 "It creates a macvlan interface for every mac ip address-virtual line",
52 "attrs": {
53 "address-virtual": {
54 "help": "bridge router virtual mac and ips",
55 "multivalue": True,
56 "validvals": ["<mac-ip/prefixlen-list>", ],
57 "example": ["address-virtual 00:11:22:33:44:01 11.0.1.1/24 11.0.1.2/24"]
58 },
59 "address-virtual-ipv6-addrgen": {
60 "help": "enable disable ipv6 link addrgenmode",
61 "validvals": ["on", "off"],
62 "default": "on",
63 "example": [
64 "address-virtual-ipv6-addrgen on",
65 "address-virtual-ipv6-addrgen off"
66 ]
67 },
68 "vrrp": {
69 "help": "VRRP support",
70 "multivalue": True,
71 "example": [
72 "vrrp 1 10.0.0.15/24 2001:0db8::0370:7334/64",
73 "vrrp 42 10.0.0.42/24"
74 ]
75 }
76 }
77 }
15ef32ea 78
223ba5af
JF
79 DEFAULT_IP_METRIC = 1024
80 ADDR_METRIC_SUPPORT = None
8e113d63 81
15ef32ea 82 def __init__(self, *args, **kargs):
3eb08b79 83 AddonWithIpBlackList.__init__(self)
15ef32ea 84 moduleBase.__init__(self, *args, **kargs)
8e113d63 85 self._bridge_fdb_query_cache = {}
23e8546d
JF
86 self.addressvirtual_with_route_metric = utils.get_boolean_from_string(
87 policymanager.policymanager_api.get_module_globals(
88 module_name=self.__class__.__name__,
89 attr='addressvirtual_with_route_metric'
90 ),
91 default=True
92 )
15ef32ea 93
17da0561
JF
94 self.address_virtual_ipv6_addrgen_value_dict = {'on': 0, 'yes': 0, '0': 0, 'off': 1, 'no': 1, '1': 1}
95
223ba5af
JF
96 if addressvirtual.ADDR_METRIC_SUPPORT is None:
97 try:
98 cmd = [utils.ip_cmd, 'addr', 'help']
99 self.logger.info('executing %s addr help' % utils.ip_cmd)
100
101 process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
102 stdout, stderr = process.communicate()
db26516e 103 addressvirtual.ADDR_METRIC_SUPPORT = '[ metric METRIC ]' in stderr.decode() or ''
223ba5af
JF
104 self.logger.info('address metric support: %s' % ('OK' if addressvirtual.ADDR_METRIC_SUPPORT else 'KO'))
105 except Exception:
106 addressvirtual.ADDR_METRIC_SUPPORT = False
107 self.logger.info('address metric support: KO')
108
109 @classmethod
2b8aedc9 110 def get_addr_metric_support(cls):
223ba5af
JF
111 return cls.ADDR_METRIC_SUPPORT
112
113 @classmethod
114 def get_default_ip_metric(cls):
115 return cls.DEFAULT_IP_METRIC
116
59ab29fb 117 def get_dependent_ifacenames(self, ifaceobj, ifacenames_all=None, old_ifaceobjs=False):
5bc963f0 118 if ifaceobj.get_attr_value('address-virtual') or ifaceobj.get_attr_value("vrrp"):
42e85fc8 119 ifaceobj.link_privflags |= ifaceLinkPrivFlags.ADDRESS_VIRTUAL_SLAVE
15ef32ea 120
aaef0a79
RP
121 def _get_macvlan_prefix(self, ifaceobj):
122 return '%s-v' %ifaceobj.name[0:13].replace('.', '-')
123
223ba5af
JF
124 def get_vrrp_prefix(self, ifname, family):
125 return "vrrp%s-%s-" % (family, self.cache.get_ifindex(ifname))
8fb6dd67 126
e1601369 127 def _add_addresses_to_bridge(self, ifaceobj, hwaddress):
8e113d63 128 # XXX: batch the addresses
d486dd0d
JF
129 if ifaceobj.link_kind & ifaceLinkKind.VLAN:
130 bridgename = ifaceobj.lowerifaces[0]
131 vlan = self._get_vlan_id(ifaceobj)
223ba5af
JF
132 if self.cache.bridge_is_vlan_aware(bridgename):
133 [self.iproute2.bridge_fdb_add(bridgename, addr,
e1601369 134 vlan) for addr in hwaddress]
223ba5af
JF
135 elif self.cache.link_is_bridge(ifaceobj.name):
136 [self.iproute2.bridge_fdb_add(ifaceobj.name, addr)
8e113d63 137 for addr in hwaddress]
e1601369
RP
138
139 def _remove_addresses_from_bridge(self, ifaceobj, hwaddress):
8e113d63 140 # XXX: batch the addresses
d486dd0d
JF
141 if ifaceobj.link_kind & ifaceLinkKind.VLAN:
142 bridgename = ifaceobj.lowerifaces[0]
143 vlan = self._get_vlan_id(ifaceobj)
223ba5af 144 if self.cache.bridge_is_vlan_aware(bridgename):
55072bd1
ST
145 for addr in hwaddress:
146 try:
223ba5af 147 self.iproute2.bridge_fdb_del(bridgename, addr, vlan)
3b01ed76 148 except Exception as e:
55072bd1
ST
149 self.logger.debug("%s: %s" %(ifaceobj.name, str(e)))
150 pass
223ba5af 151 elif self.cache.link_is_bridge(ifaceobj.name):
55072bd1
ST
152 for addr in hwaddress:
153 try:
223ba5af 154 self.iproute2.bridge_fdb_del(ifaceobj.name, addr)
3b01ed76 155 except Exception as e:
55072bd1
ST
156 self.logger.debug("%s: %s" %(ifaceobj.name, str(e)))
157 pass
8e113d63
RP
158
159 def _get_bridge_fdbs(self, bridgename, vlan):
160 fdbs = self._bridge_fdb_query_cache.get(bridgename)
161 if not fdbs:
223ba5af 162 fdbs = self.iproute2.bridge_fdb_show_dev(bridgename)
8e113d63
RP
163 if not fdbs:
164 return
165 self._bridge_fdb_query_cache[bridgename] = fdbs
166 return fdbs.get(vlan)
167
168 def _check_addresses_in_bridge(self, ifaceobj, hwaddress):
169 """ If the device is a bridge, make sure the addresses
170 are in the bridge """
d486dd0d
JF
171 if ifaceobj.link_kind & ifaceLinkKind.VLAN:
172 bridgename = ifaceobj.lowerifaces[0]
173 vlan = self._get_vlan_id(ifaceobj)
223ba5af 174 if self.cache.bridge_is_vlan_aware(bridgename):
d486dd0d 175 fdb_addrs = self._get_bridge_fdbs(bridgename, str(vlan))
5bc963f0 176 if not fdb_addrs:
8e113d63 177 return False
223ba5af 178 hwaddress_int = utils.mac_str_to_int(hwaddress)
5bc963f0 179 for mac in fdb_addrs:
223ba5af 180 if utils.mac_str_to_int(mac) == hwaddress_int:
5bc963f0
JF
181 return True
182 return False
8e113d63 183 return True
e1601369 184
00f6105d
RP
185 def _fix_connected_route(self, ifaceobj, vifacename, addr):
186 #
d486dd0d 187 # XXX: Hack to make sure the primary address
00f6105d
RP
188 # is the first in the routing table.
189 #
190 # We use `ip route get` on the vrr network to see which
191 # device the kernel returns. if it is the mac vlan device,
192 # flap the macvlan device to adjust the routing table entry.
d486dd0d 193 #
00f6105d
RP
194 # flapping the macvlan device makes sure the macvlan
195 # connected route goes through delete + add, hence adjusting
196 # the order in the routing table.
197 #
198 try:
199 self.logger.info('%s: checking route entry ...' %ifaceobj.name)
0e936c3f
JF
200
201 # here we need to convert the ip address using the standard IPNetwork
202 # object from the ipaddress not the custom IPNetwork object from
203 # python3-nlmanager, because the standard IPNetwork will automatically
204 # convert our ip address with prefixlen:
205 # >>> ipaddress.ip_network("10.10.10.242/10", False)
206 # IPv4Network('10.0.0.0/10')
207 ip = ipaddress.ip_network(addr, False)
d486dd0d
JF
208
209 # we don't support ip6 route fix yet
0e936c3f 210 if ip.version == 6:
d486dd0d
JF
211 return
212
aa895ecd 213 if ifaceobj.link_privflags & ifaceLinkPrivFlags.VRF_SLAVE:
223ba5af 214 vrf_master = self.cache.get_master(ifaceobj.name)
aa895ecd
JF
215 else:
216 vrf_master = None
217
0e936c3f 218 dev = self.iproute2.ip_route_get_dev(ip.with_prefixlen, vrf_master=vrf_master)
aa895ecd 219
d486dd0d 220 if dev and dev != ifaceobj.name:
00f6105d
RP
221 self.logger.info('%s: preferred routing entry ' %ifaceobj.name +
222 'seems to be of the macvlan dev %s'
223 %vifacename +
224 ' .. flapping macvlan dev to fix entry.')
223ba5af
JF
225 self.iproute2.link_down(vifacename)
226 self.iproute2.link_up(vifacename)
3b01ed76 227 except Exception as e:
00f6105d 228 self.logger.debug('%s: fixing route entry failed (%s)'
d486dd0d 229 % (ifaceobj.name, str(e)))
00f6105d
RP
230 pass
231
55072bd1
ST
232 def _get_macs_from_old_config(self, ifaceobj=None):
233 """ This method returns a list of the mac addresses
234 in the address-virtual attribute for the bridge. """
235 maclist = []
236 saved_ifaceobjs = statemanager.statemanager_api.get_ifaceobjs(ifaceobj.name)
237 if not saved_ifaceobjs:
238 return maclist
239 # we need the old saved configs from the statemanager
240 for oldifaceobj in saved_ifaceobjs:
241 if not oldifaceobj.get_attr_value('address-virtual'):
242 continue
243 for av in oldifaceobj.get_attr_value('address-virtual'):
244 macip = av.split()
245 if len(macip) < 2:
246 self.logger.debug("%s: incorrect old address-virtual attrs '%s'"
247 %(oldifaceobj.name, av))
248 continue
249 maclist.append(macip[0])
250 return maclist
251
7b711dc5
JF
252 def get_addressvirtual_ipv6_addrgen_user_conf(self, ifaceobj):
253 ipv6_addrgen = ifaceobj.get_attr_value_first('address-virtual-ipv6-addrgen')
254
255 if ipv6_addrgen:
007cae35
JF
256 # IFLA_INET6_ADDR_GEN_MODE values:
257 # 0 = eui64
258 # 1 = none
17da0561 259 ipv6_addrgen_nl = self.address_virtual_ipv6_addrgen_value_dict.get(ipv6_addrgen.lower(), None)
007cae35
JF
260
261 if ipv6_addrgen_nl is None:
007cae35
JF
262 self.logger.warning('%s: invalid value "%s" for attribute address-virtual-ipv6-addrgen' % (ifaceobj.name, ipv6_addrgen))
263 else:
264 return True, ipv6_addrgen_nl
7b711dc5 265
17da0561
JF
266 else:
267 # if user didn't configure ipv6-addrgen, should we reset to default?
268 ipv6_addrgen_nl = self.address_virtual_ipv6_addrgen_value_dict.get(
269 self.get_attr_default_value('address-virtual-ipv6-addrgen'),
270 None
271 )
272 if ipv6_addrgen_nl is not None:
273 return True, ipv6_addrgen_nl
274
7b711dc5
JF
275 return False, None
276
e1601369 277 def _remove_running_address_config(self, ifaceobj):
223ba5af 278 if not self.cache.link_exists(ifaceobj.name):
15ef32ea 279 return
e1601369 280 hwaddress = []
223ba5af 281
709f7942
JF
282 for macvlan_prefix in [
283 self._get_macvlan_prefix(ifaceobj),
68c8d699
JF
284 self.get_vrrp_prefix(ifaceobj.name, "4"),
285 self.get_vrrp_prefix(ifaceobj.name, "6")
709f7942
JF
286 ]:
287 for macvlan_ifacename in glob.glob("/sys/class/net/%s*" % macvlan_prefix):
288 macvlan_ifacename = os.path.basename(macvlan_ifacename)
e8b9d3ab 289 if not self.cache.link_exists(macvlan_ifacename) or self.cache.get_link_kind(macvlan_ifacename) != "macvlan":
709f7942 290 continue
223ba5af
JF
291 hwaddress.append(self.cache.get_link_address(macvlan_ifacename))
292 self.netlink.link_del(os.path.basename(macvlan_ifacename))
709f7942
JF
293 # XXX: Also delete any fdb addresses. This requires, checking mac address
294 # on individual macvlan interfaces and deleting the vlan from that.
223ba5af 295
e1601369
RP
296 if any(hwaddress):
297 self._remove_addresses_from_bridge(ifaceobj, hwaddress)
15ef32ea 298
e1601369
RP
299 def _remove_address_config(self, ifaceobj, address_virtual_list=None):
300 if not address_virtual_list:
301 self._remove_running_address_config(ifaceobj)
302 return
303
223ba5af 304 if not self.cache.link_exists(ifaceobj.name):
e1601369
RP
305 return
306 hwaddress = []
e1601369 307 av_idx = 0
aaef0a79 308 macvlan_prefix = self._get_macvlan_prefix(ifaceobj)
e1601369
RP
309 for av in address_virtual_list:
310 av_attrs = av.split()
e1601369
RP
311
312 # Delete the macvlan device on this device
cb46a208 313 macvlan_ifacename = '%s%d' %(macvlan_prefix, av_idx)
223ba5af 314 self.netlink.link_del(os.path.basename(macvlan_ifacename))
e1601369
RP
315 if av_attrs[0] != 'None':
316 hwaddress.append(av_attrs[0])
317 av_idx += 1
e1601369 318 self._remove_addresses_from_bridge(ifaceobj, hwaddress)
15ef32ea 319
4d3dc0f7 320 def check_mac_address(self, ifaceobj, mac):
5bc963f0 321 if mac == 'none':
d486dd0d 322 return True
4d3dc0f7 323 try:
586535e8 324 if int(mac.split(":")[0], 16) & 1 :
5b1fffaf
JF
325 self.log_error("%s: Multicast bit is set in the virtual mac address '%s'"
326 % (ifaceobj.name, mac), ifaceobj=ifaceobj)
4d3dc0f7
N
327 return False
328 return True
5b1fffaf 329 except ValueError:
4d3dc0f7
N
330 return False
331
42e85fc8
RP
332 def _fixup_vrf_enslavements(self, ifaceobj, ifaceobj_getfunc=None):
333 """ This function fixes up address virtual interfaces
334 (macvlans) on vrf slaves. Since this fixup is an overhead,
335 this must be called only in cases when ifupdown2 is
336 called on the vrf device or its slave and not when
337 ifupdown2 is called for all devices. When all
338 interfaces are brought up, the expectation is that
339 the normal path will fix up a vrf device or its slaves"""
340
341 if not ifaceobj_getfunc:
342 return
343 if ((ifaceobj.link_kind & ifaceLinkKind.VRF) and
223ba5af 344 self.cache.link_exists(ifaceobj.name)):
42e85fc8
RP
345 # if I am a vrf device and I have slaves
346 # that have address virtual config,
347 # enslave the slaves 'address virtual
348 # interfaces (macvlans)' to myself:
223ba5af 349 running_slaves = self.sysfs.link_get_lowers(ifaceobj.name)
42e85fc8
RP
350 if running_slaves:
351 # pick up any existing slaves of a vrf device and
352 # look for their upperdevices and enslave them to the
353 # vrf device:
354 for s in running_slaves:
355 sobjs = ifaceobj_getfunc(s)
356 if (sobjs and
357 (sobjs[0].link_privflags & ifaceLinkPrivFlags.ADDRESS_VIRTUAL_SLAVE)):
358 # enslave all its upper devices to
359 # the vrf device
223ba5af 360 upperdevs = self.sysfs.link_get_uppers(sobjs[0].name)
42e85fc8
RP
361 if not upperdevs:
362 continue
363 for u in upperdevs:
364 # skip vrf device which
365 # will also show up in the
366 # upper device list
367 if u == ifaceobj.name:
368 continue
223ba5af
JF
369 self.netlink.link_set_master(u, ifaceobj.name)
370 self.netlink.link_up(u)
42e85fc8
RP
371 elif ((ifaceobj.link_privflags & ifaceLinkPrivFlags.ADDRESS_VIRTUAL_SLAVE) and
372 (ifaceobj.link_privflags & ifaceLinkPrivFlags.VRF_SLAVE) and
223ba5af 373 self.cache.link_exists(ifaceobj.name)):
42e85fc8
RP
374 # If I am a vrf slave and I have 'address virtual'
375 # config, make sure my addrress virtual interfaces
376 # (macvlans) are also enslaved to the vrf device
377 vrfname = ifaceobj.get_attr_value_first('vrf')
223ba5af 378 if not vrfname or not self.cache.link_exists(vrfname):
42e85fc8 379 return
223ba5af 380 running_uppers = self.sysfs.link_get_uppers(ifaceobj.name)
42e85fc8
RP
381 if not running_uppers:
382 return
383 macvlan_prefix = self._get_macvlan_prefix(ifaceobj)
384 if not macvlan_prefix:
385 return
386 for u in running_uppers:
387 if u == vrfname:
388 continue
389 if u.startswith(macvlan_prefix):
223ba5af
JF
390 self.netlink.link_set_master(u, vrfname)
391 self.netlink.link_up(u)
42e85fc8 392
a6353bfb
JF
393 def sync_macvlan_forwarding_state(self, ifname, macvlan_ifname):
394 try:
395 self.write_file(
396 "/proc/sys/net/ipv4/conf/%s/forwarding" % macvlan_ifname,
397 self.read_file_oneline("/proc/sys/net/ipv4/conf/%s/forwarding" % ifname)
398 )
399 except Exception as e:
d3796ff1 400 self.logger.info("%s: syncing macvlan forwarding with lower device forwarding state failed: %s" % (ifname, str(e)))
a6353bfb 401
32d448a8 402 def create_macvlan_and_apply_config(self, ifaceobj, intf_config_list, vrrp=False):
223ba5af 403
5bc963f0
JF
404 """
405 intf_config_list = [
406 {
407 "ifname": "macvlan_ifname",
408 "hwaddress": "macvlan_hwaddress",
409 "ips": [str(IPNetwork), ]
410 },
411 ]
412 """
223ba5af
JF
413 hw_address_list = []
414
415 if not intf_config_list:
416 return hw_address_list
417
5bc963f0
JF
418 user_configured_ipv6_addrgenmode, ipv6_addrgen_user_value = self.get_addressvirtual_ipv6_addrgen_user_conf(ifaceobj)
419 purge_existing = False if ifupdownflags.flags.PERFMODE else True
5bc963f0
JF
420 ifname = ifaceobj.name
421
223ba5af 422 update_mtu = lower_iface_mtu = lower_iface_mtu_str = None
4a973d40
JF
423 if ifupdownconfig.config.get("adjust_logical_dev_mtu", "1") != "0" and ifaceobj.lowerifaces and intf_config_list:
424 update_mtu = True
5bc963f0 425
223ba5af
JF
426 if update_mtu:
427 lower_iface_mtu = self.cache.get_link_mtu(ifaceobj.name)
428 lower_iface_mtu_str = str(lower_iface_mtu)
429
430 self.iproute2.batch_start() # TODO: make sure we only do 1 ip link set down and set up (only one flap in the batch)
5bc963f0
JF
431
432 for intf_config_dict in intf_config_list:
433 link_created = False
434 macvlan_ifname = intf_config_dict.get("ifname")
435 macvlan_hwaddr = intf_config_dict.get("hwaddress")
e588acb7 436 macvlan_mode = intf_config_dict.get("mode")
5bc963f0 437 ips = intf_config_dict.get("ips")
3eb08b79 438
75a95030
JF
439 if len(macvlan_ifname) > 15:
440 self.logger.error("%s: macvlan name will exceed the 15 chars limitation - please rename the underlying interface (%s)" % (macvlan_ifname, ifname))
441 ifaceobj.set_status(ifaceStatus.ERROR)
442 continue
443
2f72e99a 444 is_ip6 = False
3eb08b79
JF
445 for ip in ips:
446 self.ip_blacklist_check(ifname, ip)
2f72e99a
TA
447 ip_network_obj = ipnetwork.IPNetwork(ip)
448 is_ip6 |= ip_network_obj.version == 6
5bc963f0 449
223ba5af
JF
450 if not self.cache.link_exists(macvlan_ifname):
451 # When creating VRRP macvlan with bridge mode, the kernel
452 # return an error: 'Invalid argument' (22)
453 # so for now we should only use the iproute2 API.
454 # try:
455 # self.netlink.link_add_macvlan(ifname, macvlan_ifname)
3218f49d 456 # except Exception:
223ba5af 457 self.iproute2.link_add_macvlan(ifname, macvlan_ifname, macvlan_mode)
a6353bfb 458 self.sync_macvlan_forwarding_state(ifname, macvlan_ifname)
5bc963f0
JF
459 link_created = True
460
461 # first thing we need to handle vrf enslavement
462 if ifaceobj.link_privflags & ifaceLinkPrivFlags.VRF_SLAVE:
223ba5af
JF
463 vrf_ifname = self.cache.get_master(ifaceobj.name)
464 if vrf_ifname:
465 self.iproute2.link_set_master(macvlan_ifname, vrf_ifname)
5bc963f0 466
46579015 467 # If we are dealing with a VRRP macvlan we need to set protodown on
2f72e99a
TA
468 # and set addrgenmode appropriately. For IPv4, a VRRP user only
469 # needs the VIP (which is explicitly configured) so addrgenmode
470 # should be NONE. For IPv6, a unique link-local address is needed
471 # as the SIP for vrrp6 hellos, so addrgenmode should be RANDOM.
32d448a8
JF
472 if vrrp:
473 try:
2f72e99a 474 v6_ag_mode = Link.IN6_ADDR_GEN_MODE_RANDOM if is_ip6 else Link.IN6_ADDR_GEN_MODE_NONE
223ba5af 475 self.iproute2.link_set_ipv6_addrgen(
32d448a8 476 macvlan_ifname,
2f72e99a 477 v6_ag_mode,
32d448a8
JF
478 link_created
479 )
480 except Exception as e:
46579015 481 self.logger.warning("%s: %s: ip link set dev %s addrgenmode none: "
32d448a8 482 "operation not supported: %s" % (ifname, macvlan_ifname, macvlan_ifname, str(e)))
92c2d4a9 483 try:
61e63e79 484 if link_created:
223ba5af 485 self.netlink.link_set_protodown_on(macvlan_ifname)
92c2d4a9
QY
486 except Exception as e:
487 self.logger.warning("%s: %s: ip link set dev %s protodown on: operation not supported: %s" % (ifname, macvlan_ifname, macvlan_ifname, str(e)))
32d448a8 488 elif user_configured_ipv6_addrgenmode:
223ba5af 489 self.iproute2.link_set_ipv6_addrgen(macvlan_ifname, ipv6_addrgen_user_value, link_created)
5bc963f0
JF
490
491 if macvlan_hwaddr:
223ba5af
JF
492 self.iproute2.link_set_address_and_keep_down(
493 macvlan_ifname,
494 macvlan_hwaddr,
495 keep_down=ifaceobj.link_privflags & ifaceLinkPrivFlags.KEEP_LINK_DOWN
496 )
5bc963f0
JF
497 hw_address_list.append(macvlan_hwaddr)
498
2b8aedc9 499 if self.addressvirtual_with_route_metric and self.get_addr_metric_support():
223ba5af 500 metric = self.get_default_ip_metric()
5bc963f0
JF
501 else:
502 metric = None
503
223ba5af 504 self.iproute2.add_addresses(
5bc963f0
JF
505 ifaceobj,
506 macvlan_ifname,
507 ips,
508 purge_existing,
509 metric=metric
510 )
511
ee007539
JF
512 if ifaceobj.link_privflags & ifaceLinkPrivFlags.KEEP_LINK_DOWN:
513 self.logger.info("%s: keeping macvlan down - link-down yes on lower device %s" % (macvlan_ifname, ifname))
223ba5af 514 self.netlink.link_down(macvlan_ifname)
ee007539 515
5bc963f0
JF
516 # If link existed before, flap the link
517 if not link_created:
518
2b8aedc9 519 if not self.addressvirtual_with_route_metric or not self.get_addr_metric_support():
5bc963f0
JF
520 # if the system doesn't support ip addr set METRIC
521 # we need to do manually check the ordering of the ip4 routes
522 self._fix_connected_route(ifaceobj, macvlan_ifname, ips[0])
523
524 if update_mtu:
5bc963f0
JF
525 update_mtu = False
526
5bc963f0 527 try:
223ba5af 528 self.sysfs.link_set_mtu(macvlan_ifname, mtu_str=lower_iface_mtu_str, mtu_int=lower_iface_mtu)
5bc963f0 529 except Exception as e:
223ba5af 530 self.logger.info('%s: failed to set mtu %s: %s' % (macvlan_ifname, lower_iface_mtu, e))
5bc963f0
JF
531
532 # set macvlan device to up in anycase.
533 # since we auto create them here..we are responsible
534 # to bring them up here in the case they were brought down
535 # by some other entity in the system.
ee007539 536 if not ifaceobj.link_privflags & ifaceLinkPrivFlags.KEEP_LINK_DOWN:
223ba5af 537 self.netlink.link_up(macvlan_ifname)
5bc963f0
JF
538 else:
539 try:
2b8aedc9 540 if not self.addressvirtual_with_route_metric or not self.get_addr_metric_support():
5bc963f0
JF
541 # if the system doesn't support ip addr set METRIC
542 # we need to do manually check the ordering of the ip6 routes
223ba5af 543 self.iproute2.fix_ipv6_route_metric(ifaceobj, macvlan_ifname, ips)
5bc963f0
JF
544 except Exception as e:
545 self.logger.debug('fix_vrf_slave_ipv6_route_metric: failed: %s' % e)
546
547 # Disable IPv6 duplicate address detection on VRR interfaces
223ba5af
JF
548 sysctl_prefix = "net.ipv6.conf.%s" % macvlan_ifname
549
550 try:
551 syskey = "%s.%s" % (sysctl_prefix, "enhanced_dad")
552 if self.sysctl_get(syskey) != "0":
553 self.sysctl_set(syskey, "0")
554 except Exception as e:
555 self.logger.info("sysctl failure: operation not supported: %s" % str(e))
556
5bc963f0
JF
557 for key, sysval in {
558 "accept_dad": "0",
559 "dad_transmits": "0"
3b01ed76 560 }.items():
223ba5af 561 syskey = "%s.%s" % (sysctl_prefix, key)
5bc963f0
JF
562 if self.sysctl_get(syskey) != sysval:
563 self.sysctl_set(syskey, sysval)
564
223ba5af 565 self.iproute2.batch_commit()
5bc963f0
JF
566 return hw_address_list
567
42e85fc8
RP
568 def _up(self, ifaceobj, ifaceobj_getfunc=None):
569 if not ifupdownflags.flags.ALL:
570 self._fixup_vrf_enslavements(ifaceobj, ifaceobj_getfunc)
5bc963f0 571
15ef32ea 572 address_virtual_list = ifaceobj.get_attr_value('address-virtual')
5bc963f0
JF
573 vrr_config_list = ifaceobj.get_attr_value("vrrp")
574
575 if not address_virtual_list and not vrr_config_list:
15ef32ea 576 # XXX: address virtual is not present. In which case,
00f6105d 577 # delete stale macvlan devices.
5bc963f0 578 self._remove_running_address_config(ifaceobj)
15ef32ea
RP
579 return
580
5bc963f0
JF
581 if ifaceobj.upperifaces and not ifaceobj.link_privflags & ifaceLinkPrivFlags.VRF_SLAVE:
582 self.log_error("%s: invalid placement of address-virtual/vrrp lines "
583 "(must be configured under an interface "
584 "with no upper interfaces or parent interfaces)"
585 % ifaceobj.name, ifaceobj)
f466af7a 586
223ba5af 587 if not self.cache.link_exists(ifaceobj.name):
15ef32ea 588 return
5bc963f0
JF
589
590 addr_virtual_macs = self.create_macvlan_and_apply_config(
591 ifaceobj,
592 self.translate_addrvirtual_user_config_to_list(
593 ifaceobj,
594 address_virtual_list
595 )
596 )
597
598 vrr_macs = self.create_macvlan_and_apply_config(
599 ifaceobj,
600 self.translate_vrr_user_config_to_list(
601 ifaceobj,
602 vrr_config_list
32d448a8
JF
603 ),
604 vrrp=True
5bc963f0
JF
605 )
606
607 hw_address_list = addr_virtual_macs + vrr_macs
608
609 # check the statemanager for old configs.
610 # We need to remove only the previously configured FDB entries
611 oldmacs = self._get_macs_from_old_config(ifaceobj)
612 # get a list of fdbs in old that are not in new config meaning they should
613 # be removed since they are gone from the config
614 removed_macs = [mac for mac in oldmacs if mac.lower() not in hw_address_list]
615 self._remove_addresses_from_bridge(ifaceobj, removed_macs)
616 # if ifaceobj is a bridge and bridge is a vlan aware bridge
617 # add the vid to the bridge
618 self._add_addresses_to_bridge(ifaceobj, hw_address_list)
619
5bc963f0
JF
620 def translate_vrr_user_config_to_list(self, ifaceobj, vrr_config_list, ifquery=False):
621 """
622 If (IPv4 addresses provided):
623 00:00:5e:00:01:<V>
624 else if (IPv6 addresses provided):
625 00:00:5e:00:02:<V>
626
627 vrrp 1 10.0.0.15/24
628 vrrp 1 2001:0db8::0370:7334/64
629
630 # Translate:
631 # vrrp 255 10.0.0.15/24 10.0.0.2/1
632 # To:
633 # [
634 # {
635 # "ifname": "macvlan_ifname",
636 # "hwaddress": "macvlan_hwaddress",
e588acb7 637 # "mode": "macvlan_mode",
5bc963f0
JF
638 # "ips": [str(IPNetwork), ]
639 # },
640 # ]
641 """
642 ifname = ifaceobj.name
643 user_config_list = []
644
8fb6dd67 645 for index, config in enumerate(vrr_config_list or []):
5bc963f0
JF
646 vrrp_id, ip_addrs = config.split(" ", 1)
647 hex_id = '%02x' % int(vrrp_id)
648 ip4 = []
649 ip6 = []
650
651 for ip_addr in ip_addrs.split():
0e936c3f
JF
652 ip_network_obj = ipnetwork.IPNetwork(ip_addr)
653 is_ip6 = ip_network_obj.version == 6
5bc963f0
JF
654
655 if is_ip6:
7a6d8252 656 ip6.append(ip_network_obj)
5bc963f0 657 else:
7a6d8252 658 ip4.append(ip_network_obj)
5bc963f0 659
3e112a1c
JF
660 macvlan_ip4_ifname = "%s%s" % (self.get_vrrp_prefix(ifname, "4"), vrrp_id)
661 macvlan_ip6_ifname = "%s%s" % (self.get_vrrp_prefix(ifname, "6"), vrrp_id)
5bc963f0 662
5bc963f0 663 if ip4 or ifquery:
b994bd39 664 merged_with_existing_obj = False
5bc963f0 665 macvlan_ip4_mac = "00:00:5e:00:01:%s" % hex_id
223ba5af 666 macvlan_ip4_mac_int = utils.mac_str_to_int(macvlan_ip4_mac)
b994bd39
JF
667 # if the vrr config is defined in different lines for the same ID
668 # we need to save the ip4 and ip6 in the objects we previously
669 # created, example:
670 # vrrp 255 10.0.0.15/24 10.0.0.2/15
671 # vrrp 255 fe80::a00:27ff:fe04:42/64
672 for obj in user_config_list:
673 if obj.get("hwaddress_int") == macvlan_ip4_mac_int:
674 obj["ips"] += ip4
675 merged_with_existing_obj = True
676
677 if not merged_with_existing_obj:
678 # if ip4 config wasn't merge with an existing object
679 # we need to insert it in our list
680 user_config_list.append({
681 "ifname": macvlan_ip4_ifname,
682 "hwaddress": macvlan_ip4_mac,
683 "hwaddress_int": macvlan_ip4_mac_int,
684 "mode": "bridge",
685 "ips": ip4,
686 "id": vrrp_id
687 })
4a973d40 688 elif not ip4 and not ifquery and self.cache.link_exists(macvlan_ip4_ifname):
bd451a48
JF
689 # special check to see if all ipv4 were removed from the vrrp
690 # configuration, if so we need to remove the associated macvlan
4a973d40 691 self.netlink.link_del(macvlan_ip4_ifname)
5bc963f0
JF
692
693 if ip6 or ifquery:
b994bd39 694 merged_with_existing_obj = False
5bc963f0 695 macvlan_ip6_mac = "00:00:5e:00:02:%s" % hex_id
223ba5af 696 macvlan_ip6_mac_int = utils.mac_str_to_int(macvlan_ip6_mac)
b994bd39
JF
697 # if the vrr config is defined in different lines for the same ID
698 # we need to save the ip4 and ip6 in the objects we previously
699 # created, example:
700 # vrrp 255 10.0.0.15/24 10.0.0.2/15
701 # vrrp 255 fe80::a00:27ff:fe04:42/64
702
703 for obj in user_config_list:
704 if obj.get("hwaddress_int") == macvlan_ip6_mac_int:
705 obj["ips"] += ip6
706 merged_with_existing_obj = True
707
708 if not merged_with_existing_obj:
709 # if ip6 config wasn't merge with an existing object
710 # we need to insert it in our list
711 user_config_list.append({
712 "ifname": macvlan_ip6_ifname,
713 "hwaddress": macvlan_ip6_mac,
714 "hwaddress_int": macvlan_ip6_mac_int,
715 "mode": "bridge",
716 "ips": ip6,
717 "id": vrrp_id
718 })
4a973d40 719 elif not ip6 and not ifquery and self.cache.link_exists(macvlan_ip6_ifname):
bd451a48
JF
720 # special check to see if all ipv6 were removed from the vrrp
721 # configuration, if so we need to remove the associated macvlan
4a973d40 722 self.netlink.link_del(macvlan_ip6_ifname)
5bc963f0 723
c02de75e
JF
724 if not ifquery:
725 # check if vrrp attribute was removed/re-assigned
726 old_vrr_ids = set()
727
728 try:
729 for old_ifaceobj in statemanager.statemanager_api.get_ifaceobjs(ifname) or []:
730 for vrr_config in old_ifaceobj.get_attr_value("vrrp") or []:
731 try:
732 old_vrr_ids.add(vrr_config.split()[0])
3218f49d 733 except Exception:
c02de75e
JF
734 continue
735
736 if old_vrr_ids:
737
738 for config in user_config_list:
739 try:
740 old_vrr_ids.remove(config["id"])
741 except KeyError:
742 pass
743
744 for id_to_remove in old_vrr_ids:
745 macvlan_ip4_ifname = "%s%s" % (self.get_vrrp_prefix(ifname, "4"), id_to_remove)
746 macvlan_ip6_ifname = "%s%s" % (self.get_vrrp_prefix(ifname, "6"), id_to_remove)
747
223ba5af
JF
748 if self.cache.link_exists(macvlan_ip4_ifname):
749 self.netlink.link_del(macvlan_ip4_ifname)
c02de75e 750
223ba5af
JF
751 if self.cache.link_exists(macvlan_ip6_ifname):
752 self.netlink.link_del(macvlan_ip6_ifname)
c02de75e
JF
753
754 except Exception as e:
17485c78 755 self.logger.debug("%s: vrrp: failure while removing unused macvlan(s): %s" % (ifname, e))
c02de75e 756
5bc963f0
JF
757 return user_config_list
758
759 def translate_addrvirtual_user_config_to_list(self, ifaceobj, address_virtual_list):
760 """
761 # Translate:
762 # address-virtual 00:11:22:33:44:01 2001:0db8::0370:7334/64 11.0.1.1/24 11.0.1.2/24
763 # To:
764 # [
765 # {
766 # "ifname": "macvlan_ifname",
767 # "hwaddress": "macvlan_hwaddress",
768 # "ips": [str(IPNetwork), ]
769 # },
770 # ]
771 """
772 user_config_list = []
773
774 if not address_virtual_list:
775 return user_config_list
776
777 macvlan_prefix = self._get_macvlan_prefix(ifaceobj)
778
779 for index, addr_virtual in enumerate(address_virtual_list):
780 av_attrs = addr_virtual.split()
5bc963f0
JF
781 mac = av_attrs[0]
782 if mac:
783 mac = mac.lower()
784
785 if not self.check_mac_address(ifaceobj, mac):
786 continue
787
e588acb7
JF
788 config = {
789 "ifname": "%s%d" % (macvlan_prefix, index),
790 "mode": "private"
791 }
5bc963f0
JF
792
793 if mac != "none":
794 config["hwaddress"] = mac
223ba5af 795 config["hwaddress_int"] = utils.mac_str_to_int(mac)
5bc963f0
JF
796
797 ip_network_obj_list = []
798 for ip in av_attrs[1:]:
0e936c3f 799 ip_network_obj_list.append(ipnetwork.IPNetwork(ip))
5bc963f0
JF
800
801 config["ips"] = ip_network_obj_list
802 user_config_list.append(config)
803
804 return user_config_list
805
42e85fc8 806 def _down(self, ifaceobj, ifaceobj_getfunc=None):
15ef32ea 807 try:
cb46a208
RP
808 self._remove_address_config(ifaceobj,
809 ifaceobj.get_attr_value('address-virtual'))
5bc963f0
JF
810
811 #### VRR
812 hwaddress = []
68c8d699 813 for vrr_prefix in [self.get_vrrp_prefix(ifaceobj.name, "4"), self.get_vrrp_prefix(ifaceobj.name, "6")]:
5bc963f0
JF
814 for macvlan_ifacename in glob.glob("/sys/class/net/%s*" % vrr_prefix):
815 macvlan_ifacename = os.path.basename(macvlan_ifacename)
223ba5af 816 if not self.cache.link_exists(macvlan_ifacename):
5bc963f0 817 continue
223ba5af
JF
818 hwaddress.append(self.cache.get_link_address(macvlan_ifacename))
819 self.netlink.link_del(macvlan_ifacename)
5bc963f0
JF
820 # XXX: Also delete any fdb addresses. This requires, checking mac address
821 # on individual macvlan interfaces and deleting the vlan from that.
5bc963f0
JF
822 if any(hwaddress):
823 self._remove_addresses_from_bridge(ifaceobj, hwaddress)
3b01ed76 824 except Exception as e:
5bc963f0
JF
825 import traceback
826 traceback.print_exc()
15ef32ea
RP
827 self.log_warn(str(e))
828
829 def _query_check(self, ifaceobj, ifaceobjcurr):
5bc963f0 830
223ba5af 831 if not self.cache.link_exists(ifaceobj.name):
cb46a208 832 return
007cae35
JF
833
834 user_config_address_virtual_ipv6_addr = ifaceobj.get_attr_value_first('address-virtual-ipv6-addrgen')
835 if user_config_address_virtual_ipv6_addr and user_config_address_virtual_ipv6_addr not in utils._string_values:
836 ifaceobjcurr.update_config_with_status('address-virtual-ipv6-addrgen', user_config_address_virtual_ipv6_addr, 1)
837 user_config_address_virtual_ipv6_addr = None
5bc963f0
JF
838
839 address_virtual_list = ifaceobj.get_attr_value('address-virtual')
840
841 macvlans_running_ipv6_addr_virtual = self.query_check_macvlan_config(
842 ifaceobj,
843 ifaceobjcurr,
844 "address-virtual",
845 user_config_address_virtual_ipv6_addr,
846 virtual_addr_list_raw=address_virtual_list,
847 macvlan_config_list=self.translate_addrvirtual_user_config_to_list(
848 ifaceobj,
849 address_virtual_list
850 )
851 )
852
853 vrr_config_list = ifaceobj.get_attr_value("vrrp")
854
855 macvlans_running_ipv6_addr_vrr = self.query_check_macvlan_config(
856 ifaceobj,
857 ifaceobjcurr,
858 "vrrp",
859 user_config_address_virtual_ipv6_addr,
860 virtual_addr_list_raw=vrr_config_list,
861 macvlan_config_list=self.translate_vrr_user_config_to_list(
862 ifaceobj,
863 vrr_config_list,
864 ifquery=True
865 )
866 )
867
868 macvlans_running_ipv6_addr = macvlans_running_ipv6_addr_virtual + macvlans_running_ipv6_addr_vrr
869 if user_config_address_virtual_ipv6_addr:
870 bool_user_ipv6_addrgen = utils.get_boolean_from_string(user_config_address_virtual_ipv6_addr)
871 for running_ipv6_addrgen in macvlans_running_ipv6_addr:
872 if (not bool_user_ipv6_addrgen) != running_ipv6_addrgen:
873 ifaceobjcurr.update_config_with_status('address-virtual-ipv6-addrgen', user_config_address_virtual_ipv6_addr, 1)
874 return
875 ifaceobjcurr.update_config_with_status('address-virtual-ipv6-addrgen', user_config_address_virtual_ipv6_addr, 0)
876
223ba5af
JF
877 @staticmethod
878 def compare_user_config_vs_running_state(running_addrs, user_addrs):
879 ip4 = []
880 ip6 = []
881
882 for ip in user_addrs or []:
0e936c3f
JF
883 if ip.version == 6:
884 ip6.append(ip)
223ba5af 885 else:
0e936c3f 886 ip4.append(ip)
223ba5af
JF
887
888 running_ipobj = []
889 for ip in running_addrs or []:
0e936c3f 890 running_ipobj.append(ip)
223ba5af
JF
891
892 return running_ipobj == (ip4 + ip6)
893
5bc963f0
JF
894 def query_check_macvlan_config(self, ifaceobj, ifaceobjcurr, attr_name, user_config_address_virtual_ipv6_addr, virtual_addr_list_raw, macvlan_config_list):
895 """
896 macvlan_config_list = [
897 {
898 "ifname": "macvlan_ifname",
899 "hwaddress": "macvlan_hwaddress",
900 "ips": [str(IPNetwork), ]
901 },
902 ]
903 """
904 is_vrr = attr_name == "vrrp"
007cae35
JF
905 macvlans_running_ipv6_addr = []
906
5bc963f0
JF
907 if not virtual_addr_list_raw:
908 return macvlans_running_ipv6_addr
909
910 macvlan_config_queue = deque(macvlan_config_list)
911
912 while macvlan_config_queue:
913
914 ip4_config = None
915 ip6_config = None
916
917 config = macvlan_config_queue.popleft()
918
919 if is_vrr:
920 ip4_config = config
921 ip6_config = macvlan_config_queue.popleft()
922
923 macvlan_ifacename = config.get("ifname")
15ef32ea 924
223ba5af 925 if not self.cache.link_exists(macvlan_ifacename):
5bc963f0 926 ifaceobjcurr.update_config_with_status(attr_name, "", 1)
cb46a208 927 continue
007cae35 928
5bc963f0
JF
929 macvlan_hwaddress = config.get("hwaddress")
930 macvlan_hwaddress_int = config.get("hwaddress_int")
931
007cae35 932 if user_config_address_virtual_ipv6_addr:
223ba5af 933 macvlans_running_ipv6_addr.append(self.cache.get_link_ipv6_addrgen_mode(macvlan_ifacename))
007cae35 934
cb46a208 935 # Check mac and ip address
223ba5af 936 rhwaddress = ip4_macvlan_hwaddress = self.cache.get_link_address(macvlan_ifacename)
0e936c3f 937 raddrs = ip4_running_addrs = self.cache.get_managed_ip_addresses(
d486dd0d 938 ifname=macvlan_ifacename,
223ba5af
JF
939 ifaceobj_list=[ifaceobj],
940 with_address_virtual=True
0e936c3f 941 )
007cae35 942
5bc963f0
JF
943 if not is_vrr:
944 ips = config.get("ips")
945
223ba5af 946 if not rhwaddress:
5bc963f0
JF
947 ifaceobjcurr.update_config_with_status(attr_name, "", 1)
948 continue
949
950 try:
223ba5af
JF
951 if utils.mac_str_to_int(rhwaddress) == macvlan_hwaddress_int \
952 and self.compare_user_config_vs_running_state(raddrs, ips) \
5bc963f0
JF
953 and self._check_addresses_in_bridge(ifaceobj, macvlan_hwaddress):
954 ifaceobjcurr.update_config_with_status(
955 attr_name,
956 " ".join(virtual_addr_list_raw),
957 0
958 )
959 else:
c3231ed0
JF
960 if raddrs:
961 address_virtual_value = "%s %s" % (rhwaddress, " ".join(raddrs))
962 else:
963 address_virtual_value = rhwaddress
c3231ed0 964 ifaceobjcurr.update_config_with_status(attr_name, address_virtual_value, 1)
0e936c3f
JF
965 except Exception as e:
966 self.logger.debug("addressvirtual: %s" % str(e))
c3231ed0
JF
967 if raddrs:
968 address_virtual_value = "%s %s" % (rhwaddress, " ".join(raddrs))
969 else:
970 address_virtual_value = rhwaddress
971
972 ifaceobjcurr.update_config_with_status(attr_name, address_virtual_value, 1)
5bc963f0
JF
973 else:
974 # VRRP
975
976 ok = False
977 # check macvlan ip4 hwaddress (only if ip4 were provided by the user)
978 if not ip4_config.get("ips") or ip4_macvlan_hwaddress == ip4_config.get("hwaddress"):
979 ip6_macvlan_ifname = ip6_config.get("ifname")
980 ip6_macvlan_hwaddress = ip6_config.get("hwaddress")
981
982 # check macvlan ip6 hwaddress (only if ip6 were provided by the user)
223ba5af 983 if not ip6_config.get("ips") or self.cache.get_link_address_raw(ip6_macvlan_ifname) == ip6_config.get("hwaddress_int"):
5bc963f0
JF
984
985 # check all ip4
223ba5af 986 if self.compare_user_config_vs_running_state(
5bc963f0
JF
987 ip4_running_addrs,
988 ip4_config.get("ips")
989 ) and self._check_addresses_in_bridge(ifaceobj, ip4_macvlan_hwaddress):
0e936c3f 990 ip6_running_addrs = self.cache.get_managed_ip_addresses(
5bc963f0 991 ifname=ip6_macvlan_ifname,
223ba5af
JF
992 ifaceobj_list=[ifaceobj],
993 with_address_virtual=True
0e936c3f 994 )
5bc963f0
JF
995
996 # check all ip6
223ba5af 997 if self.compare_user_config_vs_running_state(
5bc963f0
JF
998 ip6_running_addrs,
999 ip6_config.get("ips")
223ba5af 1000 ) and self._check_addresses_in_bridge(ifaceobj, ip6_macvlan_hwaddress):
5bc963f0
JF
1001 ifaceobjcurr.update_config_with_status(
1002 attr_name,
1003 "%s %s" % (ip4_config.get("id"), " ".join(ip4_config.get("ips") + ip6_config.get("ips"))),
1004 0
1005 )
1006 ok = True
1007
1008 if not ok:
1009 ifaceobjcurr.update_config_with_status(
1010 attr_name,
1011 "%s %s" % (ip4_config.get("id"), " ".join(ip4_config.get("ips") + ip6_config.get("ips"))),
1012 1
1013 )
1014
1015 return macvlans_running_ipv6_addr
15ef32ea 1016
42e85fc8 1017 def _query_running(self, ifaceobjrunning, ifaceobj_getfunc=None):
aaef0a79 1018 macvlan_prefix = self._get_macvlan_prefix(ifaceobjrunning)
223ba5af 1019 address_virtuals = glob.glob("/sys/class/net/%s*" %macvlan_prefix)
007cae35 1020 macvlans_ipv6_addrgen_list = []
8e113d63
RP
1021 for av in address_virtuals:
1022 macvlan_ifacename = os.path.basename(av)
223ba5af 1023 rhwaddress = self.cache.get_link_address(macvlan_ifacename)
0e936c3f 1024 raddress = self.cache.get_managed_ip_addresses(
223ba5af 1025 ifname=ifaceobjrunning.name,
0e936c3f 1026 ifaceobj_list=ifaceobj_getfunc(ifaceobjrunning.name) or [],
223ba5af 1027 with_address_virtual=True
0e936c3f 1028 )
c3175b31
JF
1029
1030 raddress = list(set(raddress))
1031
8e113d63 1032 if not raddress:
c46af1c9 1033 self.logger.warning('%s: no running addresses'
8e113d63
RP
1034 %ifaceobjrunning.name)
1035 raddress = []
580a567b
JF
1036
1037 ifaceobjrunning.update_config('address-virtual', '%s %s' %(rhwaddress, ' '.join([str(a) for a in raddress])))
007cae35 1038
223ba5af 1039 macvlans_ipv6_addrgen_list.append((macvlan_ifacename, self.cache.get_link_ipv6_addrgen_mode(macvlan_ifacename)))
007cae35
JF
1040
1041 macvlan_count = len(address_virtuals)
1042 if not macvlan_count:
1043 return
1044 ipv6_addrgen = macvlans_ipv6_addrgen_list[0][1]
1045
1046 for macvlan_ifname, macvlan_ipv6_addrgen in macvlans_ipv6_addrgen_list:
1047 if macvlan_ipv6_addrgen != ipv6_addrgen:
1048 # one macvlan has a different ipv6-addrgen configuration
1049 # we simply return, ifquery-running will print the macvlan
1050 # stanzas with the ipv6-addrgen on/off attribute
1051 return
1052 ifaceobjrunning.update_config('address-virtual-ipv6-addrgen', 'off' if ipv6_addrgen else 'on')
1053
223ba5af
JF
1054 _run_ops = {
1055 'up': _up,
1056 'down': _down,
1057 'query-checkcurr': _query_check,
1058 'query-running': _query_running
1059 }
15ef32ea
RP
1060
1061 def get_ops(self):
1062 """ returns list of ops supported by this module """
3b01ed76 1063 return list(self._run_ops.keys())
15ef32ea 1064
15ef32ea 1065
42e85fc8
RP
1066 def run(self, ifaceobj, operation, query_ifaceobj=None,
1067 ifaceobj_getfunc=None, **extra_args):
15ef32ea
RP
1068 """ run vlan configuration on the interface object passed as argument
1069
1070 Args:
1071 **ifaceobj** (object): iface object
1072
1073 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
1074 'query-running'
1075 Kwargs:
1076 **query_ifaceobj** (object): query check ifaceobject. This is only
1077 valid when op is 'query-checkcurr'. It is an object same as
1078 ifaceobj, but contains running attribute values and its config
1079 status. The modules can use it to return queried running state
1080 of interfaces. status is success if the running state is same
1081 as user required state in ifaceobj. error otherwise.
1082 """
84ca006f
RP
1083 if ifaceobj.type == ifaceType.BRIDGE_VLAN:
1084 return
15ef32ea
RP
1085 op_handler = self._run_ops.get(operation)
1086 if not op_handler:
1087 return
223ba5af 1088
15ef32ea
RP
1089 if operation == 'query-checkcurr':
1090 op_handler(self, ifaceobj, query_ifaceobj)
1091 else:
42e85fc8 1092 op_handler(self, ifaceobj, ifaceobj_getfunc=ifaceobj_getfunc)