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