]> git.proxmox.com Git - mirror_ifupdown2.git/blame - ifupdown2/addons/addressvirtual.py
add support for new address policy: 'ip_blacklist'
[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
d486dd0d 16 from ifupdown2.ifupdown.iface import *
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
d486dd0d 31 from ifupdown.iface import *
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
110 def addr_metric_support(cls):
111 return cls.ADDR_METRIC_SUPPORT
112
113 @classmethod
114 def get_default_ip_metric(cls):
115 return cls.DEFAULT_IP_METRIC
116
42e85fc8 117 def get_dependent_ifacenames(self, ifaceobj, ifacenames_all=None):
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)
c3a22da6 289 if not self.cache.link_exists(macvlan_ifacename) or not 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:
400 self.logger.info("%s: syncing macvlan forwarding with lower device forwarding state failed: %s" % str(e))
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
5bc963f0
JF
423 if ifupdownconfig.config.get("adjust_logical_dev_mtu", "1") != "0":
424 if ifaceobj.lowerifaces and intf_config_list:
425 update_mtu = True
426
223ba5af
JF
427 if update_mtu:
428 lower_iface_mtu = self.cache.get_link_mtu(ifaceobj.name)
429 lower_iface_mtu_str = str(lower_iface_mtu)
430
431 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
432
433 for intf_config_dict in intf_config_list:
434 link_created = False
435 macvlan_ifname = intf_config_dict.get("ifname")
436 macvlan_hwaddr = intf_config_dict.get("hwaddress")
e588acb7 437 macvlan_mode = intf_config_dict.get("mode")
5bc963f0 438 ips = intf_config_dict.get("ips")
3eb08b79
JF
439
440 for ip in ips:
441 self.ip_blacklist_check(ifname, ip)
5bc963f0 442
223ba5af
JF
443 if not self.cache.link_exists(macvlan_ifname):
444 # When creating VRRP macvlan with bridge mode, the kernel
445 # return an error: 'Invalid argument' (22)
446 # so for now we should only use the iproute2 API.
447 # try:
448 # self.netlink.link_add_macvlan(ifname, macvlan_ifname)
3218f49d 449 # except Exception:
223ba5af 450 self.iproute2.link_add_macvlan(ifname, macvlan_ifname, macvlan_mode)
a6353bfb 451 self.sync_macvlan_forwarding_state(ifname, macvlan_ifname)
5bc963f0
JF
452 link_created = True
453
454 # first thing we need to handle vrf enslavement
455 if ifaceobj.link_privflags & ifaceLinkPrivFlags.VRF_SLAVE:
223ba5af
JF
456 vrf_ifname = self.cache.get_master(ifaceobj.name)
457 if vrf_ifname:
458 self.iproute2.link_set_master(macvlan_ifname, vrf_ifname)
5bc963f0 459
92c2d4a9
QY
460 # if we are dealing with a VRRP macvlan we need to set addrgenmode
461 # to RANDOM, and protodown on
32d448a8
JF
462 if vrrp:
463 try:
223ba5af 464 self.iproute2.link_set_ipv6_addrgen(
32d448a8
JF
465 macvlan_ifname,
466 Link.IN6_ADDR_GEN_MODE_RANDOM,
467 link_created
468 )
469 except Exception as e:
470 self.logger.warning("%s: %s: ip link set dev %s addrgenmode random: "
471 "operation not supported: %s" % (ifname, macvlan_ifname, macvlan_ifname, str(e)))
92c2d4a9 472 try:
61e63e79 473 if link_created:
223ba5af 474 self.netlink.link_set_protodown_on(macvlan_ifname)
92c2d4a9
QY
475 except Exception as e:
476 self.logger.warning("%s: %s: ip link set dev %s protodown on: operation not supported: %s" % (ifname, macvlan_ifname, macvlan_ifname, str(e)))
32d448a8 477 elif user_configured_ipv6_addrgenmode:
223ba5af 478 self.iproute2.link_set_ipv6_addrgen(macvlan_ifname, ipv6_addrgen_user_value, link_created)
5bc963f0
JF
479
480 if macvlan_hwaddr:
223ba5af
JF
481 self.iproute2.link_set_address_and_keep_down(
482 macvlan_ifname,
483 macvlan_hwaddr,
484 keep_down=ifaceobj.link_privflags & ifaceLinkPrivFlags.KEEP_LINK_DOWN
485 )
5bc963f0
JF
486 hw_address_list.append(macvlan_hwaddr)
487
223ba5af
JF
488 if self.addressvirtual_with_route_metric and self.addr_metric_support():
489 metric = self.get_default_ip_metric()
5bc963f0
JF
490 else:
491 metric = None
492
223ba5af 493 self.iproute2.add_addresses(
5bc963f0
JF
494 ifaceobj,
495 macvlan_ifname,
496 ips,
497 purge_existing,
498 metric=metric
499 )
500
ee007539
JF
501 if ifaceobj.link_privflags & ifaceLinkPrivFlags.KEEP_LINK_DOWN:
502 self.logger.info("%s: keeping macvlan down - link-down yes on lower device %s" % (macvlan_ifname, ifname))
223ba5af 503 self.netlink.link_down(macvlan_ifname)
ee007539 504
5bc963f0
JF
505 # If link existed before, flap the link
506 if not link_created:
507
223ba5af 508 if not self.addressvirtual_with_route_metric or not self.addr_metric_support():
5bc963f0
JF
509 # if the system doesn't support ip addr set METRIC
510 # we need to do manually check the ordering of the ip4 routes
511 self._fix_connected_route(ifaceobj, macvlan_ifname, ips[0])
512
513 if update_mtu:
5bc963f0
JF
514 update_mtu = False
515
5bc963f0 516 try:
223ba5af 517 self.sysfs.link_set_mtu(macvlan_ifname, mtu_str=lower_iface_mtu_str, mtu_int=lower_iface_mtu)
5bc963f0 518 except Exception as e:
223ba5af 519 self.logger.info('%s: failed to set mtu %s: %s' % (macvlan_ifname, lower_iface_mtu, e))
5bc963f0
JF
520
521 # set macvlan device to up in anycase.
522 # since we auto create them here..we are responsible
523 # to bring them up here in the case they were brought down
524 # by some other entity in the system.
ee007539 525 if not ifaceobj.link_privflags & ifaceLinkPrivFlags.KEEP_LINK_DOWN:
223ba5af 526 self.netlink.link_up(macvlan_ifname)
5bc963f0
JF
527 else:
528 try:
223ba5af 529 if not self.addressvirtual_with_route_metric or not self.addr_metric_support():
5bc963f0
JF
530 # if the system doesn't support ip addr set METRIC
531 # we need to do manually check the ordering of the ip6 routes
223ba5af 532 self.iproute2.fix_ipv6_route_metric(ifaceobj, macvlan_ifname, ips)
5bc963f0
JF
533 except Exception as e:
534 self.logger.debug('fix_vrf_slave_ipv6_route_metric: failed: %s' % e)
535
536 # Disable IPv6 duplicate address detection on VRR interfaces
223ba5af
JF
537 sysctl_prefix = "net.ipv6.conf.%s" % macvlan_ifname
538
539 try:
540 syskey = "%s.%s" % (sysctl_prefix, "enhanced_dad")
541 if self.sysctl_get(syskey) != "0":
542 self.sysctl_set(syskey, "0")
543 except Exception as e:
544 self.logger.info("sysctl failure: operation not supported: %s" % str(e))
545
5bc963f0
JF
546 for key, sysval in {
547 "accept_dad": "0",
548 "dad_transmits": "0"
3b01ed76 549 }.items():
223ba5af 550 syskey = "%s.%s" % (sysctl_prefix, key)
5bc963f0
JF
551 if self.sysctl_get(syskey) != sysval:
552 self.sysctl_set(syskey, sysval)
553
223ba5af 554 self.iproute2.batch_commit()
5bc963f0
JF
555 return hw_address_list
556
42e85fc8
RP
557 def _up(self, ifaceobj, ifaceobj_getfunc=None):
558 if not ifupdownflags.flags.ALL:
559 self._fixup_vrf_enslavements(ifaceobj, ifaceobj_getfunc)
5bc963f0 560
15ef32ea 561 address_virtual_list = ifaceobj.get_attr_value('address-virtual')
5bc963f0
JF
562 vrr_config_list = ifaceobj.get_attr_value("vrrp")
563
564 if not address_virtual_list and not vrr_config_list:
15ef32ea 565 # XXX: address virtual is not present. In which case,
00f6105d 566 # delete stale macvlan devices.
5bc963f0 567 self._remove_running_address_config(ifaceobj)
15ef32ea
RP
568 return
569
5bc963f0
JF
570 if ifaceobj.upperifaces and not ifaceobj.link_privflags & ifaceLinkPrivFlags.VRF_SLAVE:
571 self.log_error("%s: invalid placement of address-virtual/vrrp lines "
572 "(must be configured under an interface "
573 "with no upper interfaces or parent interfaces)"
574 % ifaceobj.name, ifaceobj)
f466af7a 575
223ba5af 576 if not self.cache.link_exists(ifaceobj.name):
15ef32ea 577 return
5bc963f0
JF
578
579 addr_virtual_macs = self.create_macvlan_and_apply_config(
580 ifaceobj,
581 self.translate_addrvirtual_user_config_to_list(
582 ifaceobj,
583 address_virtual_list
584 )
585 )
586
587 vrr_macs = self.create_macvlan_and_apply_config(
588 ifaceobj,
589 self.translate_vrr_user_config_to_list(
590 ifaceobj,
591 vrr_config_list
32d448a8
JF
592 ),
593 vrrp=True
5bc963f0
JF
594 )
595
596 hw_address_list = addr_virtual_macs + vrr_macs
597
598 # check the statemanager for old configs.
599 # We need to remove only the previously configured FDB entries
600 oldmacs = self._get_macs_from_old_config(ifaceobj)
601 # get a list of fdbs in old that are not in new config meaning they should
602 # be removed since they are gone from the config
603 removed_macs = [mac for mac in oldmacs if mac.lower() not in hw_address_list]
604 self._remove_addresses_from_bridge(ifaceobj, removed_macs)
605 # if ifaceobj is a bridge and bridge is a vlan aware bridge
606 # add the vid to the bridge
607 self._add_addresses_to_bridge(ifaceobj, hw_address_list)
608
5bc963f0
JF
609 def translate_vrr_user_config_to_list(self, ifaceobj, vrr_config_list, ifquery=False):
610 """
611 If (IPv4 addresses provided):
612 00:00:5e:00:01:<V>
613 else if (IPv6 addresses provided):
614 00:00:5e:00:02:<V>
615
616 vrrp 1 10.0.0.15/24
617 vrrp 1 2001:0db8::0370:7334/64
618
619 # Translate:
620 # vrrp 255 10.0.0.15/24 10.0.0.2/1
621 # To:
622 # [
623 # {
624 # "ifname": "macvlan_ifname",
625 # "hwaddress": "macvlan_hwaddress",
e588acb7 626 # "mode": "macvlan_mode",
5bc963f0
JF
627 # "ips": [str(IPNetwork), ]
628 # },
629 # ]
630 """
631 ifname = ifaceobj.name
632 user_config_list = []
633
8fb6dd67 634 for index, config in enumerate(vrr_config_list or []):
5bc963f0
JF
635 vrrp_id, ip_addrs = config.split(" ", 1)
636 hex_id = '%02x' % int(vrrp_id)
637 ip4 = []
638 ip6 = []
639
640 for ip_addr in ip_addrs.split():
0e936c3f
JF
641 ip_network_obj = ipnetwork.IPNetwork(ip_addr)
642 is_ip6 = ip_network_obj.version == 6
5bc963f0
JF
643
644 if is_ip6:
7a6d8252 645 ip6.append(ip_network_obj)
5bc963f0 646 else:
7a6d8252 647 ip4.append(ip_network_obj)
5bc963f0 648
3e112a1c
JF
649 macvlan_ip4_ifname = "%s%s" % (self.get_vrrp_prefix(ifname, "4"), vrrp_id)
650 macvlan_ip6_ifname = "%s%s" % (self.get_vrrp_prefix(ifname, "6"), vrrp_id)
5bc963f0 651
5bc963f0 652 if ip4 or ifquery:
b994bd39 653 merged_with_existing_obj = False
5bc963f0 654 macvlan_ip4_mac = "00:00:5e:00:01:%s" % hex_id
223ba5af 655 macvlan_ip4_mac_int = utils.mac_str_to_int(macvlan_ip4_mac)
b994bd39
JF
656 # if the vrr config is defined in different lines for the same ID
657 # we need to save the ip4 and ip6 in the objects we previously
658 # created, example:
659 # vrrp 255 10.0.0.15/24 10.0.0.2/15
660 # vrrp 255 fe80::a00:27ff:fe04:42/64
661 for obj in user_config_list:
662 if obj.get("hwaddress_int") == macvlan_ip4_mac_int:
663 obj["ips"] += ip4
664 merged_with_existing_obj = True
665
666 if not merged_with_existing_obj:
667 # if ip4 config wasn't merge with an existing object
668 # we need to insert it in our list
669 user_config_list.append({
670 "ifname": macvlan_ip4_ifname,
671 "hwaddress": macvlan_ip4_mac,
672 "hwaddress_int": macvlan_ip4_mac_int,
673 "mode": "bridge",
674 "ips": ip4,
675 "id": vrrp_id
676 })
bd451a48
JF
677 elif not ip4 and not ifquery:
678 # special check to see if all ipv4 were removed from the vrrp
679 # configuration, if so we need to remove the associated macvlan
223ba5af
JF
680 if self.cache.link_exists(macvlan_ip4_ifname):
681 self.netlink.link_del(macvlan_ip4_ifname)
5bc963f0
JF
682
683 if ip6 or ifquery:
b994bd39 684 merged_with_existing_obj = False
5bc963f0 685 macvlan_ip6_mac = "00:00:5e:00:02:%s" % hex_id
223ba5af 686 macvlan_ip6_mac_int = utils.mac_str_to_int(macvlan_ip6_mac)
b994bd39
JF
687 # if the vrr config is defined in different lines for the same ID
688 # we need to save the ip4 and ip6 in the objects we previously
689 # created, example:
690 # vrrp 255 10.0.0.15/24 10.0.0.2/15
691 # vrrp 255 fe80::a00:27ff:fe04:42/64
692
693 for obj in user_config_list:
694 if obj.get("hwaddress_int") == macvlan_ip6_mac_int:
695 obj["ips"] += ip6
696 merged_with_existing_obj = True
697
698 if not merged_with_existing_obj:
699 # if ip6 config wasn't merge with an existing object
700 # we need to insert it in our list
701 user_config_list.append({
702 "ifname": macvlan_ip6_ifname,
703 "hwaddress": macvlan_ip6_mac,
704 "hwaddress_int": macvlan_ip6_mac_int,
705 "mode": "bridge",
706 "ips": ip6,
707 "id": vrrp_id
708 })
bd451a48
JF
709 elif not ip6 and not ifquery:
710 # special check to see if all ipv6 were removed from the vrrp
711 # configuration, if so we need to remove the associated macvlan
223ba5af
JF
712 if self.cache.link_exists(macvlan_ip6_ifname):
713 self.netlink.link_del(macvlan_ip6_ifname)
5bc963f0 714
c02de75e
JF
715 if not ifquery:
716 # check if vrrp attribute was removed/re-assigned
717 old_vrr_ids = set()
718
719 try:
720 for old_ifaceobj in statemanager.statemanager_api.get_ifaceobjs(ifname) or []:
721 for vrr_config in old_ifaceobj.get_attr_value("vrrp") or []:
722 try:
723 old_vrr_ids.add(vrr_config.split()[0])
3218f49d 724 except Exception:
c02de75e
JF
725 continue
726
727 if old_vrr_ids:
728
729 for config in user_config_list:
730 try:
731 old_vrr_ids.remove(config["id"])
732 except KeyError:
733 pass
734
735 for id_to_remove in old_vrr_ids:
736 macvlan_ip4_ifname = "%s%s" % (self.get_vrrp_prefix(ifname, "4"), id_to_remove)
737 macvlan_ip6_ifname = "%s%s" % (self.get_vrrp_prefix(ifname, "6"), id_to_remove)
738
223ba5af
JF
739 if self.cache.link_exists(macvlan_ip4_ifname):
740 self.netlink.link_del(macvlan_ip4_ifname)
c02de75e 741
223ba5af
JF
742 if self.cache.link_exists(macvlan_ip6_ifname):
743 self.netlink.link_del(macvlan_ip6_ifname)
c02de75e
JF
744
745 except Exception as e:
746 self.logger.debug("%s: vrrp: failure while removing unused macvlan(s)" % ifname)
747
5bc963f0
JF
748 return user_config_list
749
750 def translate_addrvirtual_user_config_to_list(self, ifaceobj, address_virtual_list):
751 """
752 # Translate:
753 # address-virtual 00:11:22:33:44:01 2001:0db8::0370:7334/64 11.0.1.1/24 11.0.1.2/24
754 # To:
755 # [
756 # {
757 # "ifname": "macvlan_ifname",
758 # "hwaddress": "macvlan_hwaddress",
759 # "ips": [str(IPNetwork), ]
760 # },
761 # ]
762 """
763 user_config_list = []
764
765 if not address_virtual_list:
766 return user_config_list
767
768 macvlan_prefix = self._get_macvlan_prefix(ifaceobj)
769
770 for index, addr_virtual in enumerate(address_virtual_list):
771 av_attrs = addr_virtual.split()
5bc963f0
JF
772 mac = av_attrs[0]
773 if mac:
774 mac = mac.lower()
775
776 if not self.check_mac_address(ifaceobj, mac):
777 continue
778
e588acb7
JF
779 config = {
780 "ifname": "%s%d" % (macvlan_prefix, index),
781 "mode": "private"
782 }
5bc963f0
JF
783
784 if mac != "none":
785 config["hwaddress"] = mac
223ba5af 786 config["hwaddress_int"] = utils.mac_str_to_int(mac)
5bc963f0
JF
787
788 ip_network_obj_list = []
789 for ip in av_attrs[1:]:
0e936c3f 790 ip_network_obj_list.append(ipnetwork.IPNetwork(ip))
5bc963f0
JF
791
792 config["ips"] = ip_network_obj_list
793 user_config_list.append(config)
794
795 return user_config_list
796
42e85fc8 797 def _down(self, ifaceobj, ifaceobj_getfunc=None):
15ef32ea 798 try:
cb46a208
RP
799 self._remove_address_config(ifaceobj,
800 ifaceobj.get_attr_value('address-virtual'))
5bc963f0
JF
801
802 #### VRR
803 hwaddress = []
68c8d699 804 for vrr_prefix in [self.get_vrrp_prefix(ifaceobj.name, "4"), self.get_vrrp_prefix(ifaceobj.name, "6")]:
5bc963f0
JF
805 for macvlan_ifacename in glob.glob("/sys/class/net/%s*" % vrr_prefix):
806 macvlan_ifacename = os.path.basename(macvlan_ifacename)
223ba5af 807 if not self.cache.link_exists(macvlan_ifacename):
5bc963f0 808 continue
223ba5af
JF
809 hwaddress.append(self.cache.get_link_address(macvlan_ifacename))
810 self.netlink.link_del(macvlan_ifacename)
5bc963f0
JF
811 # XXX: Also delete any fdb addresses. This requires, checking mac address
812 # on individual macvlan interfaces and deleting the vlan from that.
5bc963f0
JF
813 if any(hwaddress):
814 self._remove_addresses_from_bridge(ifaceobj, hwaddress)
3b01ed76 815 except Exception as e:
5bc963f0
JF
816 import traceback
817 traceback.print_exc()
15ef32ea
RP
818 self.log_warn(str(e))
819
820 def _query_check(self, ifaceobj, ifaceobjcurr):
5bc963f0 821
223ba5af 822 if not self.cache.link_exists(ifaceobj.name):
cb46a208 823 return
007cae35
JF
824
825 user_config_address_virtual_ipv6_addr = ifaceobj.get_attr_value_first('address-virtual-ipv6-addrgen')
826 if user_config_address_virtual_ipv6_addr and user_config_address_virtual_ipv6_addr not in utils._string_values:
827 ifaceobjcurr.update_config_with_status('address-virtual-ipv6-addrgen', user_config_address_virtual_ipv6_addr, 1)
828 user_config_address_virtual_ipv6_addr = None
5bc963f0
JF
829
830 address_virtual_list = ifaceobj.get_attr_value('address-virtual')
831
832 macvlans_running_ipv6_addr_virtual = self.query_check_macvlan_config(
833 ifaceobj,
834 ifaceobjcurr,
835 "address-virtual",
836 user_config_address_virtual_ipv6_addr,
837 virtual_addr_list_raw=address_virtual_list,
838 macvlan_config_list=self.translate_addrvirtual_user_config_to_list(
839 ifaceobj,
840 address_virtual_list
841 )
842 )
843
844 vrr_config_list = ifaceobj.get_attr_value("vrrp")
845
846 macvlans_running_ipv6_addr_vrr = self.query_check_macvlan_config(
847 ifaceobj,
848 ifaceobjcurr,
849 "vrrp",
850 user_config_address_virtual_ipv6_addr,
851 virtual_addr_list_raw=vrr_config_list,
852 macvlan_config_list=self.translate_vrr_user_config_to_list(
853 ifaceobj,
854 vrr_config_list,
855 ifquery=True
856 )
857 )
858
859 macvlans_running_ipv6_addr = macvlans_running_ipv6_addr_virtual + macvlans_running_ipv6_addr_vrr
860 if user_config_address_virtual_ipv6_addr:
861 bool_user_ipv6_addrgen = utils.get_boolean_from_string(user_config_address_virtual_ipv6_addr)
862 for running_ipv6_addrgen in macvlans_running_ipv6_addr:
863 if (not bool_user_ipv6_addrgen) != running_ipv6_addrgen:
864 ifaceobjcurr.update_config_with_status('address-virtual-ipv6-addrgen', user_config_address_virtual_ipv6_addr, 1)
865 return
866 ifaceobjcurr.update_config_with_status('address-virtual-ipv6-addrgen', user_config_address_virtual_ipv6_addr, 0)
867
223ba5af
JF
868 @staticmethod
869 def compare_user_config_vs_running_state(running_addrs, user_addrs):
870 ip4 = []
871 ip6 = []
872
873 for ip in user_addrs or []:
0e936c3f
JF
874 if ip.version == 6:
875 ip6.append(ip)
223ba5af 876 else:
0e936c3f 877 ip4.append(ip)
223ba5af
JF
878
879 running_ipobj = []
880 for ip in running_addrs or []:
0e936c3f 881 running_ipobj.append(ip)
223ba5af
JF
882
883 return running_ipobj == (ip4 + ip6)
884
5bc963f0
JF
885 def query_check_macvlan_config(self, ifaceobj, ifaceobjcurr, attr_name, user_config_address_virtual_ipv6_addr, virtual_addr_list_raw, macvlan_config_list):
886 """
887 macvlan_config_list = [
888 {
889 "ifname": "macvlan_ifname",
890 "hwaddress": "macvlan_hwaddress",
891 "ips": [str(IPNetwork), ]
892 },
893 ]
894 """
895 is_vrr = attr_name == "vrrp"
007cae35
JF
896 macvlans_running_ipv6_addr = []
897
5bc963f0
JF
898 if not virtual_addr_list_raw:
899 return macvlans_running_ipv6_addr
900
901 macvlan_config_queue = deque(macvlan_config_list)
902
903 while macvlan_config_queue:
904
905 ip4_config = None
906 ip6_config = None
907
908 config = macvlan_config_queue.popleft()
909
910 if is_vrr:
911 ip4_config = config
912 ip6_config = macvlan_config_queue.popleft()
913
914 macvlan_ifacename = config.get("ifname")
15ef32ea 915
223ba5af 916 if not self.cache.link_exists(macvlan_ifacename):
5bc963f0 917 ifaceobjcurr.update_config_with_status(attr_name, "", 1)
cb46a208 918 continue
007cae35 919
5bc963f0
JF
920 macvlan_hwaddress = config.get("hwaddress")
921 macvlan_hwaddress_int = config.get("hwaddress_int")
922
007cae35 923 if user_config_address_virtual_ipv6_addr:
223ba5af 924 macvlans_running_ipv6_addr.append(self.cache.get_link_ipv6_addrgen_mode(macvlan_ifacename))
007cae35 925
cb46a208 926 # Check mac and ip address
223ba5af 927 rhwaddress = ip4_macvlan_hwaddress = self.cache.get_link_address(macvlan_ifacename)
0e936c3f 928 raddrs = ip4_running_addrs = self.cache.get_managed_ip_addresses(
d486dd0d 929 ifname=macvlan_ifacename,
223ba5af
JF
930 ifaceobj_list=[ifaceobj],
931 with_address_virtual=True
0e936c3f 932 )
007cae35 933
5bc963f0
JF
934 if not is_vrr:
935 ips = config.get("ips")
936
223ba5af 937 if not rhwaddress:
5bc963f0
JF
938 ifaceobjcurr.update_config_with_status(attr_name, "", 1)
939 continue
940
941 try:
223ba5af
JF
942 if utils.mac_str_to_int(rhwaddress) == macvlan_hwaddress_int \
943 and self.compare_user_config_vs_running_state(raddrs, ips) \
5bc963f0
JF
944 and self._check_addresses_in_bridge(ifaceobj, macvlan_hwaddress):
945 ifaceobjcurr.update_config_with_status(
946 attr_name,
947 " ".join(virtual_addr_list_raw),
948 0
949 )
950 else:
c3231ed0
JF
951 if raddrs:
952 address_virtual_value = "%s %s" % (rhwaddress, " ".join(raddrs))
953 else:
954 address_virtual_value = rhwaddress
c3231ed0 955 ifaceobjcurr.update_config_with_status(attr_name, address_virtual_value, 1)
0e936c3f
JF
956 except Exception as e:
957 self.logger.debug("addressvirtual: %s" % str(e))
c3231ed0
JF
958 if raddrs:
959 address_virtual_value = "%s %s" % (rhwaddress, " ".join(raddrs))
960 else:
961 address_virtual_value = rhwaddress
962
963 ifaceobjcurr.update_config_with_status(attr_name, address_virtual_value, 1)
5bc963f0
JF
964 else:
965 # VRRP
966
967 ok = False
968 # check macvlan ip4 hwaddress (only if ip4 were provided by the user)
969 if not ip4_config.get("ips") or ip4_macvlan_hwaddress == ip4_config.get("hwaddress"):
970 ip6_macvlan_ifname = ip6_config.get("ifname")
971 ip6_macvlan_hwaddress = ip6_config.get("hwaddress")
972
973 # check macvlan ip6 hwaddress (only if ip6 were provided by the user)
223ba5af 974 if not ip6_config.get("ips") or self.cache.get_link_address_raw(ip6_macvlan_ifname) == ip6_config.get("hwaddress_int"):
5bc963f0
JF
975
976 # check all ip4
223ba5af 977 if self.compare_user_config_vs_running_state(
5bc963f0
JF
978 ip4_running_addrs,
979 ip4_config.get("ips")
980 ) and self._check_addresses_in_bridge(ifaceobj, ip4_macvlan_hwaddress):
0e936c3f 981 ip6_running_addrs = self.cache.get_managed_ip_addresses(
5bc963f0 982 ifname=ip6_macvlan_ifname,
223ba5af
JF
983 ifaceobj_list=[ifaceobj],
984 with_address_virtual=True
0e936c3f 985 )
5bc963f0
JF
986
987 # check all ip6
223ba5af 988 if self.compare_user_config_vs_running_state(
5bc963f0
JF
989 ip6_running_addrs,
990 ip6_config.get("ips")
223ba5af 991 ) and self._check_addresses_in_bridge(ifaceobj, ip6_macvlan_hwaddress):
5bc963f0
JF
992 ifaceobjcurr.update_config_with_status(
993 attr_name,
994 "%s %s" % (ip4_config.get("id"), " ".join(ip4_config.get("ips") + ip6_config.get("ips"))),
995 0
996 )
997 ok = True
998
999 if not ok:
1000 ifaceobjcurr.update_config_with_status(
1001 attr_name,
1002 "%s %s" % (ip4_config.get("id"), " ".join(ip4_config.get("ips") + ip6_config.get("ips"))),
1003 1
1004 )
1005
1006 return macvlans_running_ipv6_addr
15ef32ea 1007
42e85fc8 1008 def _query_running(self, ifaceobjrunning, ifaceobj_getfunc=None):
aaef0a79 1009 macvlan_prefix = self._get_macvlan_prefix(ifaceobjrunning)
223ba5af 1010 address_virtuals = glob.glob("/sys/class/net/%s*" %macvlan_prefix)
007cae35 1011 macvlans_ipv6_addrgen_list = []
8e113d63
RP
1012 for av in address_virtuals:
1013 macvlan_ifacename = os.path.basename(av)
223ba5af 1014 rhwaddress = self.cache.get_link_address(macvlan_ifacename)
0e936c3f 1015 raddress = self.cache.get_managed_ip_addresses(
223ba5af 1016 ifname=ifaceobjrunning.name,
0e936c3f 1017 ifaceobj_list=ifaceobj_getfunc(ifaceobjrunning.name) or [],
223ba5af 1018 with_address_virtual=True
0e936c3f 1019 )
c3175b31
JF
1020
1021 raddress = list(set(raddress))
1022
8e113d63 1023 if not raddress:
c46af1c9 1024 self.logger.warning('%s: no running addresses'
8e113d63
RP
1025 %ifaceobjrunning.name)
1026 raddress = []
580a567b
JF
1027
1028 ifaceobjrunning.update_config('address-virtual', '%s %s' %(rhwaddress, ' '.join([str(a) for a in raddress])))
007cae35 1029
223ba5af 1030 macvlans_ipv6_addrgen_list.append((macvlan_ifacename, self.cache.get_link_ipv6_addrgen_mode(macvlan_ifacename)))
007cae35
JF
1031
1032 macvlan_count = len(address_virtuals)
1033 if not macvlan_count:
1034 return
1035 ipv6_addrgen = macvlans_ipv6_addrgen_list[0][1]
1036
1037 for macvlan_ifname, macvlan_ipv6_addrgen in macvlans_ipv6_addrgen_list:
1038 if macvlan_ipv6_addrgen != ipv6_addrgen:
1039 # one macvlan has a different ipv6-addrgen configuration
1040 # we simply return, ifquery-running will print the macvlan
1041 # stanzas with the ipv6-addrgen on/off attribute
1042 return
1043 ifaceobjrunning.update_config('address-virtual-ipv6-addrgen', 'off' if ipv6_addrgen else 'on')
1044
223ba5af
JF
1045 _run_ops = {
1046 'up': _up,
1047 'down': _down,
1048 'query-checkcurr': _query_check,
1049 'query-running': _query_running
1050 }
15ef32ea
RP
1051
1052 def get_ops(self):
1053 """ returns list of ops supported by this module """
3b01ed76 1054 return list(self._run_ops.keys())
15ef32ea 1055
15ef32ea 1056
42e85fc8
RP
1057 def run(self, ifaceobj, operation, query_ifaceobj=None,
1058 ifaceobj_getfunc=None, **extra_args):
15ef32ea
RP
1059 """ run vlan configuration on the interface object passed as argument
1060
1061 Args:
1062 **ifaceobj** (object): iface object
1063
1064 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
1065 'query-running'
1066 Kwargs:
1067 **query_ifaceobj** (object): query check ifaceobject. This is only
1068 valid when op is 'query-checkcurr'. It is an object same as
1069 ifaceobj, but contains running attribute values and its config
1070 status. The modules can use it to return queried running state
1071 of interfaces. status is success if the running state is same
1072 as user required state in ifaceobj. error otherwise.
1073 """
84ca006f
RP
1074 if ifaceobj.type == ifaceType.BRIDGE_VLAN:
1075 return
15ef32ea
RP
1076 op_handler = self._run_ops.get(operation)
1077 if not op_handler:
1078 return
223ba5af 1079
15ef32ea
RP
1080 if operation == 'query-checkcurr':
1081 op_handler(self, ifaceobj, query_ifaceobj)
1082 else:
42e85fc8 1083 op_handler(self, ifaceobj, ifaceobj_getfunc=ifaceobj_getfunc)