3 # Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
4 # Author: Roopa Prabhu, roopa@cumulusnetworks.com
10 from string
import maketrans
11 from collections
import deque
12 from ipaddr
import IPNetwork
, IPv6Network
15 from ifupdown2
.ifupdown
.iface
import *
16 from ifupdown2
.ifupdown
.utils
import utils
17 from ifupdown2
.ifupdown
.netlink
import netlink
19 from ifupdown2
.ifupdownaddons
.LinkUtils
import LinkUtils
20 from ifupdown2
.ifupdownaddons
.modulebase
import moduleBase
22 import ifupdown2
.ifupdown
.statemanager
as statemanager
23 import ifupdown2
.ifupdown
.policymanager
as policymanager
24 import ifupdown2
.ifupdown
.ifupdownflags
as ifupdownflags
25 import ifupdown2
.ifupdown
.ifupdownconfig
as ifupdownconfig
27 from ifupdown
.iface
import *
28 from ifupdown
.utils
import utils
29 from ifupdown
.netlink
import netlink
31 from ifupdownaddons
.LinkUtils
import LinkUtils
32 from ifupdownaddons
.modulebase
import moduleBase
34 import ifupdown
.statemanager
as statemanager
35 import ifupdown
.policymanager
as policymanager
36 import ifupdown
.ifupdownflags
as ifupdownflags
37 import ifupdown
.ifupdownconfig
as ifupdownconfig
40 class addressvirtual(moduleBase
):
41 """ ifupdown2 addon module to configure virtual addresses """
43 _modinfo
= {'mhelp' : 'address module configures virtual addresses for ' +
44 'interfaces. It creates a macvlan interface for ' +
45 'every mac ip address-virtual line',
48 { 'help' : 'bridge router virtual mac and ips',
50 'validvals' : ['<mac-ip/prefixlen-list>',],
51 'example': ['address-virtual 00:11:22:33:44:01 11.0.1.1/24 11.0.1.2/24']
53 'address-virtual-ipv6-addrgen': {
54 'help': 'enable disable ipv6 link addrgenmode',
55 'validvals': ['on', 'off'],
58 'address-virtual-ipv6-addrgen on',
59 'address-virtual-ipv6-addrgen off'
63 "help": "VRRP support",
66 "vrrp 1 10.0.0.15/24 2001:0db8::0370:7334/64",
67 "vrrp 42 10.0.0.42/24"
73 def __init__(self
, *args
, **kargs
):
74 moduleBase
.__init
__(self
, *args
, **kargs
)
76 self
._bridge
_fdb
_query
_cache
= {}
77 self
.addressvirtual_with_route_metric
= utils
.get_boolean_from_string(
78 policymanager
.policymanager_api
.get_module_globals(
79 module_name
=self
.__class
__.__name
__,
80 attr
='addressvirtual_with_route_metric'
85 self
.address_virtual_ipv6_addrgen_value_dict
= {'on': 0, 'yes': 0, '0': 0, 'off': 1, 'no': 1, '1': 1}
86 self
.mac_translate_tab
= maketrans(":.-,", " ")
88 def get_dependent_ifacenames(self
, ifaceobj
, ifacenames_all
=None):
89 if ifaceobj
.get_attr_value('address-virtual') or ifaceobj
.get_attr_value("vrrp"):
90 ifaceobj
.link_privflags |
= ifaceLinkPrivFlags
.ADDRESS_VIRTUAL_SLAVE
92 def _get_macvlan_prefix(self
, ifaceobj
):
93 return '%s-v' %ifaceobj
.name
[0:13].replace('.', '-')
96 def get_vrrp_prefix(ifname
, family
):
97 return "vrrp%s-%s-" % (family
, netlink
.get_iface_index(ifname
))
99 def _add_addresses_to_bridge(self
, ifaceobj
, hwaddress
):
100 # XXX: batch the addresses
101 if ifaceobj
.link_kind
& ifaceLinkKind
.VLAN
:
102 bridgename
= ifaceobj
.lowerifaces
[0]
103 vlan
= self
._get
_vlan
_id
(ifaceobj
)
104 if self
.ipcmd
.bridge_is_vlan_aware(bridgename
):
105 [self
.ipcmd
.bridge_fdb_add(bridgename
, addr
,
106 vlan
) for addr
in hwaddress
]
107 elif self
.ipcmd
.is_bridge(ifaceobj
.name
):
108 [self
.ipcmd
.bridge_fdb_add(ifaceobj
.name
, addr
)
109 for addr
in hwaddress
]
111 def _remove_addresses_from_bridge(self
, ifaceobj
, hwaddress
):
112 # XXX: batch the addresses
113 if ifaceobj
.link_kind
& ifaceLinkKind
.VLAN
:
114 bridgename
= ifaceobj
.lowerifaces
[0]
115 vlan
= self
._get
_vlan
_id
(ifaceobj
)
116 if self
.ipcmd
.bridge_is_vlan_aware(bridgename
):
117 for addr
in hwaddress
:
119 self
.ipcmd
.bridge_fdb_del(bridgename
, addr
, vlan
)
121 self
.logger
.debug("%s: %s" %(ifaceobj
.name
, str(e
)))
123 elif self
.ipcmd
.is_bridge(ifaceobj
.name
):
124 for addr
in hwaddress
:
126 self
.ipcmd
.bridge_fdb_del(ifaceobj
.name
, addr
)
128 self
.logger
.debug("%s: %s" %(ifaceobj
.name
, str(e
)))
131 def _get_bridge_fdbs(self
, bridgename
, vlan
):
132 fdbs
= self
._bridge
_fdb
_query
_cache
.get(bridgename
)
134 fdbs
= self
.ipcmd
.bridge_fdb_show_dev(bridgename
)
137 self
._bridge
_fdb
_query
_cache
[bridgename
] = fdbs
138 return fdbs
.get(vlan
)
140 def _check_addresses_in_bridge(self
, ifaceobj
, hwaddress
):
141 """ If the device is a bridge, make sure the addresses
142 are in the bridge """
143 if ifaceobj
.link_kind
& ifaceLinkKind
.VLAN
:
144 bridgename
= ifaceobj
.lowerifaces
[0]
145 vlan
= self
._get
_vlan
_id
(ifaceobj
)
146 if self
.ipcmd
.bridge_is_vlan_aware(bridgename
):
147 fdb_addrs
= self
._get
_bridge
_fdbs
(bridgename
, str(vlan
))
150 hwaddress_int
= self
.mac_str_to_int(hwaddress
)
151 for mac
in fdb_addrs
:
152 if self
.mac_str_to_int(mac
) == hwaddress_int
:
157 def _fix_connected_route(self
, ifaceobj
, vifacename
, addr
):
159 # XXX: Hack to make sure the primary address
160 # is the first in the routing table.
162 # We use `ip route get` on the vrr network to see which
163 # device the kernel returns. if it is the mac vlan device,
164 # flap the macvlan device to adjust the routing table entry.
166 # flapping the macvlan device makes sure the macvlan
167 # connected route goes through delete + add, hence adjusting
168 # the order in the routing table.
171 self
.logger
.info('%s: checking route entry ...' %ifaceobj
.name
)
174 # we don't support ip6 route fix yet
175 if type(ip
) == IPv6Network
:
178 route_prefix
= '%s/%d' %(ip
.network
, ip
.prefixlen
)
180 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.VRF_SLAVE
:
181 vrf_master
= self
.ipcmd
.link_get_master(ifaceobj
.name
)
185 dev
= self
.ipcmd
.ip_route_get_dev(route_prefix
, vrf_master
=vrf_master
)
187 if dev
and dev
!= ifaceobj
.name
:
188 self
.logger
.info('%s: preferred routing entry ' %ifaceobj
.name
+
189 'seems to be of the macvlan dev %s'
191 ' .. flapping macvlan dev to fix entry.')
192 self
.ipcmd
.link_down(vifacename
)
193 self
.ipcmd
.link_up(vifacename
)
195 self
.logger
.debug('%s: fixing route entry failed (%s)'
196 % (ifaceobj
.name
, str(e
)))
199 def _handle_vrf_slaves(self
, macvlan_ifacename
, ifaceobj
):
200 vrfname
= self
.ipcmd
.link_get_master(ifaceobj
.name
)
202 self
.ipcmd
.link_set(macvlan_ifacename
, 'master', vrfname
)
204 def _get_macs_from_old_config(self
, ifaceobj
=None):
205 """ This method returns a list of the mac addresses
206 in the address-virtual attribute for the bridge. """
208 saved_ifaceobjs
= statemanager
.statemanager_api
.get_ifaceobjs(ifaceobj
.name
)
209 if not saved_ifaceobjs
:
211 # we need the old saved configs from the statemanager
212 for oldifaceobj
in saved_ifaceobjs
:
213 if not oldifaceobj
.get_attr_value('address-virtual'):
215 for av
in oldifaceobj
.get_attr_value('address-virtual'):
218 self
.logger
.debug("%s: incorrect old address-virtual attrs '%s'"
219 %(oldifaceobj
.name
, av
))
221 maclist
.append(macip
[0])
224 def get_addressvirtual_ipv6_addrgen_user_conf(self
, ifaceobj
):
225 ipv6_addrgen
= ifaceobj
.get_attr_value_first('address-virtual-ipv6-addrgen')
228 # IFLA_INET6_ADDR_GEN_MODE values:
231 ipv6_addrgen_nl
= self
.address_virtual_ipv6_addrgen_value_dict
.get(ipv6_addrgen
.lower(), None)
233 if ipv6_addrgen_nl
is None:
234 self
.logger
.warning('%s: invalid value "%s" for attribute address-virtual-ipv6-addrgen' % (ifaceobj
.name
, ipv6_addrgen
))
236 return True, ipv6_addrgen_nl
239 # if user didn't configure ipv6-addrgen, should we reset to default?
240 ipv6_addrgen_nl
= self
.address_virtual_ipv6_addrgen_value_dict
.get(
241 self
.get_attr_default_value('address-virtual-ipv6-addrgen'),
244 if ipv6_addrgen_nl
is not None:
245 return True, ipv6_addrgen_nl
249 def _remove_running_address_config(self
, ifaceobj
):
250 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
253 self
.ipcmd
.batch_start()
254 for macvlan_prefix
in [
255 self
._get
_macvlan
_prefix
(ifaceobj
),
256 self
.get_vrrp_prefix(ifaceobj
.name
, "4"),
257 self
.get_vrrp_prefix(ifaceobj
.name
, "6")
259 for macvlan_ifacename
in glob
.glob("/sys/class/net/%s*" % macvlan_prefix
):
260 macvlan_ifacename
= os
.path
.basename(macvlan_ifacename
)
261 if not self
.ipcmd
.link_exists(macvlan_ifacename
):
263 hwaddress
.append(self
.ipcmd
.link_get_hwaddress(macvlan_ifacename
))
264 self
.ipcmd
.link_delete(os
.path
.basename(macvlan_ifacename
))
265 # XXX: Also delete any fdb addresses. This requires, checking mac address
266 # on individual macvlan interfaces and deleting the vlan from that.
267 self
.ipcmd
.batch_commit()
269 self
._remove
_addresses
_from
_bridge
(ifaceobj
, hwaddress
)
271 def _remove_address_config(self
, ifaceobj
, address_virtual_list
=None):
272 if not address_virtual_list
:
273 self
._remove
_running
_address
_config
(ifaceobj
)
276 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
279 self
.ipcmd
.batch_start()
281 macvlan_prefix
= self
._get
_macvlan
_prefix
(ifaceobj
)
282 for av
in address_virtual_list
:
283 av_attrs
= av
.split()
284 if len(av_attrs
) < 2:
285 self
.log_error("%s: incorrect address-virtual attrs '%s'"
286 %(ifaceobj
.name
, av
), ifaceobj
,
291 # Delete the macvlan device on this device
292 macvlan_ifacename
= '%s%d' %(macvlan_prefix
, av_idx
)
293 self
.ipcmd
.link_delete(os
.path
.basename(macvlan_ifacename
))
294 if av_attrs
[0] != 'None':
295 hwaddress
.append(av_attrs
[0])
297 self
.ipcmd
.batch_commit()
298 self
._remove
_addresses
_from
_bridge
(ifaceobj
, hwaddress
)
300 def check_mac_address(self
, ifaceobj
, mac
):
304 if int(mac
.split(":")[0], 16) & 1 :
305 self
.log_error("%s: Multicast bit is set in the virtual mac address '%s'"
306 % (ifaceobj
.name
, mac
), ifaceobj
=ifaceobj
)
312 def _fixup_vrf_enslavements(self
, ifaceobj
, ifaceobj_getfunc
=None):
313 """ This function fixes up address virtual interfaces
314 (macvlans) on vrf slaves. Since this fixup is an overhead,
315 this must be called only in cases when ifupdown2 is
316 called on the vrf device or its slave and not when
317 ifupdown2 is called for all devices. When all
318 interfaces are brought up, the expectation is that
319 the normal path will fix up a vrf device or its slaves"""
321 if not ifaceobj_getfunc
:
323 if ((ifaceobj
.link_kind
& ifaceLinkKind
.VRF
) and
324 self
.ipcmd
.link_exists(ifaceobj
.name
)):
325 # if I am a vrf device and I have slaves
326 # that have address virtual config,
327 # enslave the slaves 'address virtual
328 # interfaces (macvlans)' to myself:
329 running_slaves
= self
.ipcmd
.link_get_lowers(ifaceobj
.name
)
331 # pick up any existing slaves of a vrf device and
332 # look for their upperdevices and enslave them to the
334 for s
in running_slaves
:
335 sobjs
= ifaceobj_getfunc(s
)
337 (sobjs
[0].link_privflags
& ifaceLinkPrivFlags
.ADDRESS_VIRTUAL_SLAVE
)):
338 # enslave all its upper devices to
340 upperdevs
= self
.ipcmd
.link_get_uppers(sobjs
[0].name
)
344 # skip vrf device which
345 # will also show up in the
347 if u
== ifaceobj
.name
:
349 self
.ipcmd
.link_set(u
, 'master', ifaceobj
.name
,
351 elif ((ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.ADDRESS_VIRTUAL_SLAVE
) and
352 (ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.VRF_SLAVE
) and
353 self
.ipcmd
.link_exists(ifaceobj
.name
)):
354 # If I am a vrf slave and I have 'address virtual'
355 # config, make sure my addrress virtual interfaces
356 # (macvlans) are also enslaved to the vrf device
357 vrfname
= ifaceobj
.get_attr_value_first('vrf')
358 if not vrfname
or not self
.ipcmd
.link_exists(vrfname
):
360 running_uppers
= self
.ipcmd
.link_get_uppers(ifaceobj
.name
)
361 if not running_uppers
:
363 macvlan_prefix
= self
._get
_macvlan
_prefix
(ifaceobj
)
364 if not macvlan_prefix
:
366 for u
in running_uppers
:
369 if u
.startswith(macvlan_prefix
):
370 self
.ipcmd
.link_set(u
, 'master', vrfname
,
373 def mac_str_to_int(self
, mac
):
375 for n
in mac
.translate(self
.mac_translate_tab
).split():
376 mac_int
+= int(n
, 16)
379 def create_macvlan_and_apply_config(self
, ifaceobj
, intf_config_list
):
383 "ifname": "macvlan_ifname",
384 "hwaddress": "macvlan_hwaddress",
385 "ips": [str(IPNetwork), ]
389 user_configured_ipv6_addrgenmode
, ipv6_addrgen_user_value
= self
.get_addressvirtual_ipv6_addrgen_user_conf(ifaceobj
)
390 purge_existing
= False if ifupdownflags
.flags
.PERFMODE
else True
392 ifname
= ifaceobj
.name
394 lower_iface_mtu
= update_mtu
= None
395 if ifupdownconfig
.config
.get("adjust_logical_dev_mtu", "1") != "0":
396 if ifaceobj
.lowerifaces
and intf_config_list
:
399 self
.ipcmd
.batch_start()
401 for intf_config_dict
in intf_config_list
:
403 macvlan_ifname
= intf_config_dict
.get("ifname")
404 macvlan_hwaddr
= intf_config_dict
.get("hwaddress")
405 macvlan_mode
= intf_config_dict
.get("mode")
406 ips
= intf_config_dict
.get("ips")
408 if not self
.ipcmd
.link_exists(macvlan_ifname
):
409 self
.ipcmd
.link_add_macvlan(ifname
, macvlan_ifname
, macvlan_mode
)
412 # first thing we need to handle vrf enslavement
413 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.VRF_SLAVE
:
414 self
._handle
_vrf
_slaves
(macvlan_ifname
, ifaceobj
)
416 if user_configured_ipv6_addrgenmode
:
417 self
.ipcmd
.ipv6_addrgen(macvlan_ifname
, ipv6_addrgen_user_value
, link_created
)
420 self
.ipcmd
.link_set_hwaddress(macvlan_ifname
, macvlan_hwaddr
)
421 hw_address_list
.append(macvlan_hwaddr
)
423 if self
.addressvirtual_with_route_metric
and self
.ipcmd
.addr_metric_support():
424 metric
= self
.ipcmd
.get_default_ip_metric()
428 self
.ipcmd
.addr_add_multiple(
436 # If link existed before, flap the link
439 if not self
.addressvirtual_with_route_metric
or not self
.ipcmd
.addr_metric_support():
440 # if the system doesn't support ip addr set METRIC
441 # we need to do manually check the ordering of the ip4 routes
442 self
._fix
_connected
_route
(ifaceobj
, macvlan_ifname
, ips
[0])
445 lower_iface_mtu
= self
.ipcmd
.link_get_mtu(ifname
, refresh
=True)
448 if lower_iface_mtu
and lower_iface_mtu
!= self
.ipcmd
.link_get_mtu(macvlan_ifname
, refresh
=True):
450 self
.ipcmd
.link_set_mtu(macvlan_ifname
,
452 except Exception as e
:
453 self
.logger
.info('%s: failed to set mtu %s: %s' %
454 (macvlan_ifname
, lower_iface_mtu
, e
))
456 # set macvlan device to up in anycase.
457 # since we auto create them here..we are responsible
458 # to bring them up here in the case they were brought down
459 # by some other entity in the system.
460 netlink
.link_set_updown(macvlan_ifname
, "up")
463 if not self
.addressvirtual_with_route_metric
or not self
.ipcmd
.addr_metric_support():
464 # if the system doesn't support ip addr set METRIC
465 # we need to do manually check the ordering of the ip6 routes
466 self
.ipcmd
.fix_ipv6_route_metric(ifaceobj
, macvlan_ifname
, ips
)
467 except Exception as e
:
468 self
.logger
.debug('fix_vrf_slave_ipv6_route_metric: failed: %s' % e
)
470 # Disable IPv6 duplicate address detection on VRR interfaces
475 syskey
= "net.ipv6.conf.%s.%s" % (macvlan_ifname
, key
)
476 if self
.sysctl_get(syskey
) != sysval
:
477 self
.sysctl_set(syskey
, sysval
)
479 self
.ipcmd
.batch_commit()
480 return hw_address_list
482 def _up(self
, ifaceobj
, ifaceobj_getfunc
=None):
483 if not ifupdownflags
.flags
.ALL
:
484 self
._fixup
_vrf
_enslavements
(ifaceobj
, ifaceobj_getfunc
)
486 address_virtual_list
= ifaceobj
.get_attr_value('address-virtual')
487 vrr_config_list
= ifaceobj
.get_attr_value("vrrp")
489 if not address_virtual_list
and not vrr_config_list
:
490 # XXX: address virtual is not present. In which case,
491 # delete stale macvlan devices.
492 self
._remove
_running
_address
_config
(ifaceobj
)
495 if ifaceobj
.upperifaces
and not ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.VRF_SLAVE
:
496 self
.log_error("%s: invalid placement of address-virtual/vrrp lines "
497 "(must be configured under an interface "
498 "with no upper interfaces or parent interfaces)"
499 % ifaceobj
.name
, ifaceobj
)
501 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
504 addr_virtual_macs
= self
.create_macvlan_and_apply_config(
506 self
.translate_addrvirtual_user_config_to_list(
512 vrr_macs
= self
.create_macvlan_and_apply_config(
514 self
.translate_vrr_user_config_to_list(
520 hw_address_list
= addr_virtual_macs
+ vrr_macs
522 # check the statemanager for old configs.
523 # We need to remove only the previously configured FDB entries
524 oldmacs
= self
._get
_macs
_from
_old
_config
(ifaceobj
)
525 # get a list of fdbs in old that are not in new config meaning they should
526 # be removed since they are gone from the config
527 removed_macs
= [mac
for mac
in oldmacs
if mac
.lower() not in hw_address_list
]
528 self
._remove
_addresses
_from
_bridge
(ifaceobj
, removed_macs
)
529 # if ifaceobj is a bridge and bridge is a vlan aware bridge
530 # add the vid to the bridge
531 self
._add
_addresses
_to
_bridge
(ifaceobj
, hw_address_list
)
533 def translate_vrr_user_config_to_list(self
, ifaceobj
, vrr_config_list
, ifquery
=False):
535 If (IPv4 addresses provided):
537 else if (IPv6 addresses provided):
541 vrrp 1 2001:0db8::0370:7334/64
544 # vrrp 255 10.0.0.15/24 10.0.0.2/1
548 # "ifname": "macvlan_ifname",
549 # "hwaddress": "macvlan_hwaddress",
550 # "mode": "macvlan_mode",
551 # "ips": [str(IPNetwork), ]
555 ifname
= ifaceobj
.name
556 user_config_list
= []
558 for index
, config
in enumerate(vrr_config_list
or []):
559 vrrp_id
, ip_addrs
= config
.split(" ", 1)
560 hex_id
= '%02x' % int(vrrp_id
)
564 for ip_addr
in ip_addrs
.split():
565 ip_network_obj
= IPNetwork(ip_addr
)
566 is_ip6
= isinstance(ip_network_obj
, IPv6Network
)
573 macvlan_ip4_ifname
= "%s%s" % (self
.get_vrrp_prefix(ifname
, "4"), vrrp_id
)
574 macvlan_ip6_ifname
= "%s%s" % (self
.get_vrrp_prefix(ifname
, "6"), vrrp_id
)
576 merged_with_existing_obj
= False
577 # if the vrr config is defined in different lines for the same ID
578 # we need to save the ip4 and ip6 in the objects we previously
580 # vrrp 255 10.0.0.15/24 10.0.0.2/15
581 # vrrp 255 fe80::a00:27ff:fe04:42/64
582 for obj
in user_config_list
:
583 if obj
.get("ifname") == macvlan_ip4_ifname
:
585 merged_with_existing_obj
= True
586 elif obj
.get("ifname") == macvlan_ip6_ifname
:
588 merged_with_existing_obj
= True
590 if merged_with_existing_obj
:
595 macvlan_ip4_mac
= "00:00:5e:00:01:%s" % hex_id
596 user_config_list
.append({
597 "ifname": macvlan_ip4_ifname
,
598 "hwaddress": macvlan_ip4_mac
,
599 "hwaddress_int": self
.mac_str_to_int(macvlan_ip4_mac
),
604 elif not ip4
and not ifquery
:
605 # special check to see if all ipv4 were removed from the vrrp
606 # configuration, if so we need to remove the associated macvlan
607 if self
.ipcmd
.link_exists(macvlan_ip4_ifname
):
608 netlink
.link_del(macvlan_ip4_ifname
)
612 macvlan_ip6_mac
= "00:00:5e:00:02:%s" % hex_id
613 user_config_list
.append({
614 "ifname": macvlan_ip6_ifname
,
615 "hwaddress": macvlan_ip6_mac
,
616 "hwaddress_int": self
.mac_str_to_int(macvlan_ip6_mac
),
621 elif not ip6
and not ifquery
:
622 # special check to see if all ipv6 were removed from the vrrp
623 # configuration, if so we need to remove the associated macvlan
624 if self
.ipcmd
.link_exists(macvlan_ip6_ifname
):
625 netlink
.link_del(macvlan_ip6_ifname
)
627 return user_config_list
629 def translate_addrvirtual_user_config_to_list(self
, ifaceobj
, address_virtual_list
):
632 # address-virtual 00:11:22:33:44:01 2001:0db8::0370:7334/64 11.0.1.1/24 11.0.1.2/24
636 # "ifname": "macvlan_ifname",
637 # "hwaddress": "macvlan_hwaddress",
638 # "ips": [str(IPNetwork), ]
642 user_config_list
= []
644 if not address_virtual_list
:
645 return user_config_list
647 macvlan_prefix
= self
._get
_macvlan
_prefix
(ifaceobj
)
649 for index
, addr_virtual
in enumerate(address_virtual_list
):
650 av_attrs
= addr_virtual
.split()
652 if len(av_attrs
) < 2:
653 self
.log_error("%s: incorrect address-virtual attrs '%s'"
654 % (ifaceobj
.name
, addr_virtual
), ifaceobj
,
662 if not self
.check_mac_address(ifaceobj
, mac
):
666 "ifname": "%s%d" % (macvlan_prefix
, index
),
671 config
["hwaddress"] = mac
672 config
["hwaddress_int"] = self
.mac_str_to_int(mac
)
674 ip_network_obj_list
= []
675 for ip
in av_attrs
[1:]:
676 ip_network_obj_list
.append(str(IPNetwork(ip
)))
678 config
["ips"] = ip_network_obj_list
679 user_config_list
.append(config
)
681 return user_config_list
683 def process_macvlans_config(self
, ifaceobj
, attr_name
, virtual_addr_list_raw
, macvlan_config_list
):
684 return self
.create_macvlan_and_apply_config(ifaceobj
, macvlan_config_list
)
686 def _down(self
, ifaceobj
, ifaceobj_getfunc
=None):
688 self
._remove
_address
_config
(ifaceobj
,
689 ifaceobj
.get_attr_value('address-virtual'))
693 self
.ipcmd
.batch_start()
694 for vrr_prefix
in [self
.get_vrrp_prefix(ifaceobj
.name
, "4"), self
.get_vrrp_prefix(ifaceobj
.name
, "6")]:
695 for macvlan_ifacename
in glob
.glob("/sys/class/net/%s*" % vrr_prefix
):
696 macvlan_ifacename
= os
.path
.basename(macvlan_ifacename
)
697 if not self
.ipcmd
.link_exists(macvlan_ifacename
):
699 hwaddress
.append(self
.ipcmd
.link_get_hwaddress(macvlan_ifacename
))
700 self
.ipcmd
.link_delete(os
.path
.basename(macvlan_ifacename
))
701 # XXX: Also delete any fdb addresses. This requires, checking mac address
702 # on individual macvlan interfaces and deleting the vlan from that.
703 self
.ipcmd
.batch_commit()
705 self
._remove
_addresses
_from
_bridge
(ifaceobj
, hwaddress
)
708 traceback
.print_exc()
709 self
.log_warn(str(e
))
711 def _query_check(self
, ifaceobj
, ifaceobjcurr
):
713 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
716 user_config_address_virtual_ipv6_addr
= ifaceobj
.get_attr_value_first('address-virtual-ipv6-addrgen')
717 if user_config_address_virtual_ipv6_addr
and user_config_address_virtual_ipv6_addr
not in utils
._string
_values
:
718 ifaceobjcurr
.update_config_with_status('address-virtual-ipv6-addrgen', user_config_address_virtual_ipv6_addr
, 1)
719 user_config_address_virtual_ipv6_addr
= None
721 address_virtual_list
= ifaceobj
.get_attr_value('address-virtual')
723 macvlans_running_ipv6_addr_virtual
= self
.query_check_macvlan_config(
727 user_config_address_virtual_ipv6_addr
,
728 virtual_addr_list_raw
=address_virtual_list
,
729 macvlan_config_list
=self
.translate_addrvirtual_user_config_to_list(
735 vrr_config_list
= ifaceobj
.get_attr_value("vrrp")
737 macvlans_running_ipv6_addr_vrr
= self
.query_check_macvlan_config(
741 user_config_address_virtual_ipv6_addr
,
742 virtual_addr_list_raw
=vrr_config_list
,
743 macvlan_config_list
=self
.translate_vrr_user_config_to_list(
750 macvlans_running_ipv6_addr
= macvlans_running_ipv6_addr_virtual
+ macvlans_running_ipv6_addr_vrr
751 if user_config_address_virtual_ipv6_addr
:
752 bool_user_ipv6_addrgen
= utils
.get_boolean_from_string(user_config_address_virtual_ipv6_addr
)
753 for running_ipv6_addrgen
in macvlans_running_ipv6_addr
:
754 if (not bool_user_ipv6_addrgen
) != running_ipv6_addrgen
:
755 ifaceobjcurr
.update_config_with_status('address-virtual-ipv6-addrgen', user_config_address_virtual_ipv6_addr
, 1)
757 ifaceobjcurr
.update_config_with_status('address-virtual-ipv6-addrgen', user_config_address_virtual_ipv6_addr
, 0)
759 def query_check_macvlan_config(self
, ifaceobj
, ifaceobjcurr
, attr_name
, user_config_address_virtual_ipv6_addr
, virtual_addr_list_raw
, macvlan_config_list
):
761 macvlan_config_list = [
763 "ifname": "macvlan_ifname",
764 "hwaddress": "macvlan_hwaddress",
765 "ips": [str(IPNetwork), ]
769 is_vrr
= attr_name
== "vrrp"
770 macvlans_running_ipv6_addr
= []
772 if not virtual_addr_list_raw
:
773 return macvlans_running_ipv6_addr
775 macvlan_config_queue
= deque(macvlan_config_list
)
777 while macvlan_config_queue
:
782 config
= macvlan_config_queue
.popleft()
786 ip6_config
= macvlan_config_queue
.popleft()
788 macvlan_ifacename
= config
.get("ifname")
790 if not self
.ipcmd
.link_exists(macvlan_ifacename
):
791 ifaceobjcurr
.update_config_with_status(attr_name
, "", 1)
794 macvlan_hwaddress
= config
.get("hwaddress")
795 macvlan_hwaddress_int
= config
.get("hwaddress_int")
797 if user_config_address_virtual_ipv6_addr
:
798 macvlans_running_ipv6_addr
.append(self
.ipcmd
.get_ipv6_addrgen_mode(macvlan_ifacename
))
800 # Check mac and ip address
801 rhwaddress
= ip4_macvlan_hwaddress
= self
.ipcmd
.link_get_hwaddress(macvlan_ifacename
)
802 raddrs
= ip4_running_addrs
= self
.ipcmd
.get_running_addrs(
803 ifname
=macvlan_ifacename
,
805 addr_virtual_ifaceobj
=ifaceobj
809 ips
= config
.get("ips")
811 if not raddrs
or not rhwaddress
:
812 ifaceobjcurr
.update_config_with_status(attr_name
, "", 1)
816 if self
.mac_str_to_int(rhwaddress
) == macvlan_hwaddress_int \
817 and self
.ipcmd
.compare_user_config_vs_running_state(raddrs
, ips
) \
818 and self
._check
_addresses
_in
_bridge
(ifaceobj
, macvlan_hwaddress
):
819 ifaceobjcurr
.update_config_with_status(
821 " ".join(virtual_addr_list_raw
),
825 ifaceobjcurr
.update_config_with_status(
827 '%s %s' % (rhwaddress
, ' '.join(raddrs
)),
831 ifaceobjcurr
.update_config_with_status(
833 '%s %s' % (rhwaddress
, ' '.join(raddrs
)),
840 # check macvlan ip4 hwaddress (only if ip4 were provided by the user)
841 if not ip4_config
.get("ips") or ip4_macvlan_hwaddress
== ip4_config
.get("hwaddress"):
842 ip6_macvlan_ifname
= ip6_config
.get("ifname")
843 ip6_macvlan_hwaddress
= ip6_config
.get("hwaddress")
845 # check macvlan ip6 hwaddress (only if ip6 were provided by the user)
846 if not ip6_config
.get("ips") or self
.ipcmd
.link_get_hwaddress(ip6_macvlan_ifname
) == ip6_macvlan_hwaddress
:
849 if self
.ipcmd
.compare_user_config_vs_running_state(
851 ip4_config
.get("ips")
852 ) and self
._check
_addresses
_in
_bridge
(ifaceobj
, ip4_macvlan_hwaddress
):
853 ip6_running_addrs
= self
.ipcmd
.get_running_addrs(
854 ifname
=ip6_macvlan_ifname
,
856 addr_virtual_ifaceobj
=ifaceobj
860 if self
.ipcmd
.compare_user_config_vs_running_state(
862 ip6_config
.get("ips")
863 ) and self
._check
_addresses
_in
_bridge
(ifaceobj
, ip4_macvlan_hwaddress
):
864 ifaceobjcurr
.update_config_with_status(
866 "%s %s" % (ip4_config
.get("id"), " ".join(ip4_config
.get("ips") + ip6_config
.get("ips"))),
872 ifaceobjcurr
.update_config_with_status(
874 "%s %s" % (ip4_config
.get("id"), " ".join(ip4_config
.get("ips") + ip6_config
.get("ips"))),
878 return macvlans_running_ipv6_addr
880 def _query_running(self
, ifaceobjrunning
, ifaceobj_getfunc
=None):
881 macvlan_prefix
= self
._get
_macvlan
_prefix
(ifaceobjrunning
)
882 address_virtuals
= glob
.glob("/sys/class/net/%s*" %macvlan_prefix
)
883 macvlans_ipv6_addrgen_list
= []
884 for av
in address_virtuals
:
885 macvlan_ifacename
= os
.path
.basename(av
)
886 rhwaddress
= self
.ipcmd
.link_get_hwaddress(macvlan_ifacename
)
889 for obj
in ifaceobj_getfunc(ifaceobjrunning
.name
) or []:
890 raddress
.extend(self
.ipcmd
.get_running_addrs(None, macvlan_ifacename
, addr_virtual_ifaceobj
=obj
) or [])
892 raddress
= list(set(raddress
))
895 self
.logger
.warn('%s: no running addresses'
896 %ifaceobjrunning
.name
)
898 ifaceobjrunning
.update_config('address-virtual',
899 '%s %s' %(rhwaddress
, ' '.join(raddress
)))
901 macvlans_ipv6_addrgen_list
.append((macvlan_ifacename
, self
.ipcmd
.get_ipv6_addrgen_mode(macvlan_ifacename
)))
903 macvlan_count
= len(address_virtuals
)
904 if not macvlan_count
:
906 ipv6_addrgen
= macvlans_ipv6_addrgen_list
[0][1]
908 for macvlan_ifname
, macvlan_ipv6_addrgen
in macvlans_ipv6_addrgen_list
:
909 if macvlan_ipv6_addrgen
!= ipv6_addrgen
:
910 # one macvlan has a different ipv6-addrgen configuration
911 # we simply return, ifquery-running will print the macvlan
912 # stanzas with the ipv6-addrgen on/off attribute
914 ifaceobjrunning
.update_config('address-virtual-ipv6-addrgen', 'off' if ipv6_addrgen
else 'on')
917 _run_ops
= {'up' : _up
,
919 'query-checkcurr' : _query_check
,
920 'query-running' : _query_running
}
923 """ returns list of ops supported by this module """
924 return self
._run
_ops
.keys()
926 def _init_command_handlers(self
):
928 self
.ipcmd
= LinkUtils()
930 def run(self
, ifaceobj
, operation
, query_ifaceobj
=None,
931 ifaceobj_getfunc
=None, **extra_args
):
932 """ run vlan configuration on the interface object passed as argument
935 **ifaceobj** (object): iface object
937 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
940 **query_ifaceobj** (object): query check ifaceobject. This is only
941 valid when op is 'query-checkcurr'. It is an object same as
942 ifaceobj, but contains running attribute values and its config
943 status. The modules can use it to return queried running state
944 of interfaces. status is success if the running state is same
945 as user required state in ifaceobj. error otherwise.
947 if ifaceobj
.type == ifaceType
.BRIDGE_VLAN
:
949 op_handler
= self
._run
_ops
.get(operation
)
952 self
._init
_command
_handlers
()
953 if operation
== 'query-checkcurr':
954 op_handler(self
, ifaceobj
, query_ifaceobj
)
956 op_handler(self
, ifaceobj
, ifaceobj_getfunc
=ifaceobj_getfunc
)