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