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