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('.', '-')
95 def _add_addresses_to_bridge(self
, ifaceobj
, hwaddress
):
96 # XXX: batch the addresses
97 if ifaceobj
.link_kind
& ifaceLinkKind
.VLAN
:
98 bridgename
= ifaceobj
.lowerifaces
[0]
99 vlan
= self
._get
_vlan
_id
(ifaceobj
)
100 if self
.ipcmd
.bridge_is_vlan_aware(bridgename
):
101 [self
.ipcmd
.bridge_fdb_add(bridgename
, addr
,
102 vlan
) for addr
in hwaddress
]
103 elif self
.ipcmd
.is_bridge(ifaceobj
.name
):
104 [self
.ipcmd
.bridge_fdb_add(ifaceobj
.name
, addr
)
105 for addr
in hwaddress
]
107 def _remove_addresses_from_bridge(self
, ifaceobj
, hwaddress
):
108 # XXX: batch the addresses
109 if ifaceobj
.link_kind
& ifaceLinkKind
.VLAN
:
110 bridgename
= ifaceobj
.lowerifaces
[0]
111 vlan
= self
._get
_vlan
_id
(ifaceobj
)
112 if self
.ipcmd
.bridge_is_vlan_aware(bridgename
):
113 for addr
in hwaddress
:
115 self
.ipcmd
.bridge_fdb_del(bridgename
, addr
, vlan
)
117 self
.logger
.debug("%s: %s" %(ifaceobj
.name
, str(e
)))
119 elif self
.ipcmd
.is_bridge(ifaceobj
.name
):
120 for addr
in hwaddress
:
122 self
.ipcmd
.bridge_fdb_del(ifaceobj
.name
, addr
)
124 self
.logger
.debug("%s: %s" %(ifaceobj
.name
, str(e
)))
127 def _get_bridge_fdbs(self
, bridgename
, vlan
):
128 fdbs
= self
._bridge
_fdb
_query
_cache
.get(bridgename
)
130 fdbs
= self
.ipcmd
.bridge_fdb_show_dev(bridgename
)
133 self
._bridge
_fdb
_query
_cache
[bridgename
] = fdbs
134 return fdbs
.get(vlan
)
136 def _check_addresses_in_bridge(self
, ifaceobj
, hwaddress
):
137 """ If the device is a bridge, make sure the addresses
138 are in the bridge """
139 if ifaceobj
.link_kind
& ifaceLinkKind
.VLAN
:
140 bridgename
= ifaceobj
.lowerifaces
[0]
141 vlan
= self
._get
_vlan
_id
(ifaceobj
)
142 if self
.ipcmd
.bridge_is_vlan_aware(bridgename
):
143 fdb_addrs
= self
._get
_bridge
_fdbs
(bridgename
, str(vlan
))
146 hwaddress_int
= self
.mac_str_to_int(hwaddress
)
147 for mac
in fdb_addrs
:
148 if self
.mac_str_to_int(mac
) == hwaddress_int
:
153 def _fix_connected_route(self
, ifaceobj
, vifacename
, addr
):
155 # XXX: Hack to make sure the primary address
156 # is the first in the routing table.
158 # We use `ip route get` on the vrr network to see which
159 # device the kernel returns. if it is the mac vlan device,
160 # flap the macvlan device to adjust the routing table entry.
162 # flapping the macvlan device makes sure the macvlan
163 # connected route goes through delete + add, hence adjusting
164 # the order in the routing table.
167 self
.logger
.info('%s: checking route entry ...' %ifaceobj
.name
)
170 # we don't support ip6 route fix yet
171 if type(ip
) == IPv6Network
:
174 route_prefix
= '%s/%d' %(ip
.network
, ip
.prefixlen
)
176 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.VRF_SLAVE
:
177 vrf_master
= self
.ipcmd
.link_get_master(ifaceobj
.name
)
181 dev
= self
.ipcmd
.ip_route_get_dev(route_prefix
, vrf_master
=vrf_master
)
183 if dev
and dev
!= ifaceobj
.name
:
184 self
.logger
.info('%s: preferred routing entry ' %ifaceobj
.name
+
185 'seems to be of the macvlan dev %s'
187 ' .. flapping macvlan dev to fix entry.')
188 self
.ipcmd
.link_down(vifacename
)
189 self
.ipcmd
.link_up(vifacename
)
191 self
.logger
.debug('%s: fixing route entry failed (%s)'
192 % (ifaceobj
.name
, str(e
)))
195 def _handle_vrf_slaves(self
, macvlan_ifacename
, ifaceobj
):
196 vrfname
= self
.ipcmd
.link_get_master(ifaceobj
.name
)
198 self
.ipcmd
.link_set(macvlan_ifacename
, 'master', vrfname
)
200 def _get_macs_from_old_config(self
, ifaceobj
=None):
201 """ This method returns a list of the mac addresses
202 in the address-virtual attribute for the bridge. """
204 saved_ifaceobjs
= statemanager
.statemanager_api
.get_ifaceobjs(ifaceobj
.name
)
205 if not saved_ifaceobjs
:
207 # we need the old saved configs from the statemanager
208 for oldifaceobj
in saved_ifaceobjs
:
209 if not oldifaceobj
.get_attr_value('address-virtual'):
211 for av
in oldifaceobj
.get_attr_value('address-virtual'):
214 self
.logger
.debug("%s: incorrect old address-virtual attrs '%s'"
215 %(oldifaceobj
.name
, av
))
217 maclist
.append(macip
[0])
220 def get_addressvirtual_ipv6_addrgen_user_conf(self
, ifaceobj
):
221 ipv6_addrgen
= ifaceobj
.get_attr_value_first('address-virtual-ipv6-addrgen')
224 # IFLA_INET6_ADDR_GEN_MODE values:
227 ipv6_addrgen_nl
= self
.address_virtual_ipv6_addrgen_value_dict
.get(ipv6_addrgen
.lower(), None)
229 if ipv6_addrgen_nl
is None:
230 self
.logger
.warning('%s: invalid value "%s" for attribute address-virtual-ipv6-addrgen' % (ifaceobj
.name
, ipv6_addrgen
))
232 return True, ipv6_addrgen_nl
235 # if user didn't configure ipv6-addrgen, should we reset to default?
236 ipv6_addrgen_nl
= self
.address_virtual_ipv6_addrgen_value_dict
.get(
237 self
.get_attr_default_value('address-virtual-ipv6-addrgen'),
240 if ipv6_addrgen_nl
is not None:
241 return True, ipv6_addrgen_nl
245 def _remove_running_address_config(self
, ifaceobj
):
246 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
249 self
.ipcmd
.batch_start()
250 for macvlan_prefix
in [
251 self
._get
_macvlan
_prefix
(ifaceobj
),
252 self
.get_vrr_prefix(ifaceobj
.name
, "4"),
253 self
.get_vrr_prefix(ifaceobj
.name
, "6")
255 for macvlan_ifacename
in glob
.glob("/sys/class/net/%s*" % macvlan_prefix
):
256 macvlan_ifacename
= os
.path
.basename(macvlan_ifacename
)
257 if not self
.ipcmd
.link_exists(macvlan_ifacename
):
259 hwaddress
.append(self
.ipcmd
.link_get_hwaddress(macvlan_ifacename
))
260 self
.ipcmd
.link_delete(os
.path
.basename(macvlan_ifacename
))
261 # XXX: Also delete any fdb addresses. This requires, checking mac address
262 # on individual macvlan interfaces and deleting the vlan from that.
263 self
.ipcmd
.batch_commit()
265 self
._remove
_addresses
_from
_bridge
(ifaceobj
, hwaddress
)
267 def _remove_address_config(self
, ifaceobj
, address_virtual_list
=None):
268 if not address_virtual_list
:
269 self
._remove
_running
_address
_config
(ifaceobj
)
272 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
275 self
.ipcmd
.batch_start()
277 macvlan_prefix
= self
._get
_macvlan
_prefix
(ifaceobj
)
278 for av
in address_virtual_list
:
279 av_attrs
= av
.split()
280 if len(av_attrs
) < 2:
281 self
.log_error("%s: incorrect address-virtual attrs '%s'"
282 %(ifaceobj
.name
, av
), ifaceobj
,
287 # Delete the macvlan device on this device
288 macvlan_ifacename
= '%s%d' %(macvlan_prefix
, av_idx
)
289 self
.ipcmd
.link_delete(os
.path
.basename(macvlan_ifacename
))
290 if av_attrs
[0] != 'None':
291 hwaddress
.append(av_attrs
[0])
293 self
.ipcmd
.batch_commit()
294 self
._remove
_addresses
_from
_bridge
(ifaceobj
, hwaddress
)
296 def check_mac_address(self
, ifaceobj
, mac
):
300 if int(mac
.split(":")[0], 16) & 1 :
301 self
.log_error("%s: Multicast bit is set in the virtual mac address '%s'"
302 % (ifaceobj
.name
, mac
), ifaceobj
=ifaceobj
)
308 def _fixup_vrf_enslavements(self
, ifaceobj
, ifaceobj_getfunc
=None):
309 """ This function fixes up address virtual interfaces
310 (macvlans) on vrf slaves. Since this fixup is an overhead,
311 this must be called only in cases when ifupdown2 is
312 called on the vrf device or its slave and not when
313 ifupdown2 is called for all devices. When all
314 interfaces are brought up, the expectation is that
315 the normal path will fix up a vrf device or its slaves"""
317 if not ifaceobj_getfunc
:
319 if ((ifaceobj
.link_kind
& ifaceLinkKind
.VRF
) and
320 self
.ipcmd
.link_exists(ifaceobj
.name
)):
321 # if I am a vrf device and I have slaves
322 # that have address virtual config,
323 # enslave the slaves 'address virtual
324 # interfaces (macvlans)' to myself:
325 running_slaves
= self
.ipcmd
.link_get_lowers(ifaceobj
.name
)
327 # pick up any existing slaves of a vrf device and
328 # look for their upperdevices and enslave them to the
330 for s
in running_slaves
:
331 sobjs
= ifaceobj_getfunc(s
)
333 (sobjs
[0].link_privflags
& ifaceLinkPrivFlags
.ADDRESS_VIRTUAL_SLAVE
)):
334 # enslave all its upper devices to
336 upperdevs
= self
.ipcmd
.link_get_uppers(sobjs
[0].name
)
340 # skip vrf device which
341 # will also show up in the
343 if u
== ifaceobj
.name
:
345 self
.ipcmd
.link_set(u
, 'master', ifaceobj
.name
,
347 elif ((ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.ADDRESS_VIRTUAL_SLAVE
) and
348 (ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.VRF_SLAVE
) and
349 self
.ipcmd
.link_exists(ifaceobj
.name
)):
350 # If I am a vrf slave and I have 'address virtual'
351 # config, make sure my addrress virtual interfaces
352 # (macvlans) are also enslaved to the vrf device
353 vrfname
= ifaceobj
.get_attr_value_first('vrf')
354 if not vrfname
or not self
.ipcmd
.link_exists(vrfname
):
356 running_uppers
= self
.ipcmd
.link_get_uppers(ifaceobj
.name
)
357 if not running_uppers
:
359 macvlan_prefix
= self
._get
_macvlan
_prefix
(ifaceobj
)
360 if not macvlan_prefix
:
362 for u
in running_uppers
:
365 if u
.startswith(macvlan_prefix
):
366 self
.ipcmd
.link_set(u
, 'master', vrfname
,
369 def mac_str_to_int(self
, mac
):
371 for n
in mac
.translate(self
.mac_translate_tab
).split():
372 mac_int
+= int(n
, 16)
375 def create_macvlan_and_apply_config(self
, ifaceobj
, intf_config_list
):
379 "ifname": "macvlan_ifname",
380 "hwaddress": "macvlan_hwaddress",
381 "ips": [str(IPNetwork), ]
385 user_configured_ipv6_addrgenmode
, ipv6_addrgen_user_value
= self
.get_addressvirtual_ipv6_addrgen_user_conf(ifaceobj
)
386 purge_existing
= False if ifupdownflags
.flags
.PERFMODE
else True
388 ifname
= ifaceobj
.name
390 lower_iface_mtu
= update_mtu
= None
391 if ifupdownconfig
.config
.get("adjust_logical_dev_mtu", "1") != "0":
392 if ifaceobj
.lowerifaces
and intf_config_list
:
395 self
.ipcmd
.batch_start()
397 for intf_config_dict
in intf_config_list
:
399 macvlan_ifname
= intf_config_dict
.get("ifname")
400 macvlan_hwaddr
= intf_config_dict
.get("hwaddress")
401 ips
= intf_config_dict
.get("ips")
403 if not self
.ipcmd
.link_exists(macvlan_ifname
):
404 self
.ipcmd
.link_add_macvlan(ifname
, macvlan_ifname
)
407 # first thing we need to handle vrf enslavement
408 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.VRF_SLAVE
:
409 self
._handle
_vrf
_slaves
(macvlan_ifname
, ifaceobj
)
411 if user_configured_ipv6_addrgenmode
:
412 self
.ipcmd
.ipv6_addrgen(macvlan_ifname
, ipv6_addrgen_user_value
, link_created
)
415 self
.ipcmd
.link_set_hwaddress(macvlan_ifname
, macvlan_hwaddr
)
416 hw_address_list
.append(macvlan_hwaddr
)
418 if self
.addressvirtual_with_route_metric
and self
.ipcmd
.addr_metric_support():
419 metric
= self
.ipcmd
.get_default_ip_metric()
423 self
.ipcmd
.addr_add_multiple(
431 # If link existed before, flap the link
434 if not self
.addressvirtual_with_route_metric
or not self
.ipcmd
.addr_metric_support():
435 # if the system doesn't support ip addr set METRIC
436 # we need to do manually check the ordering of the ip4 routes
437 self
._fix
_connected
_route
(ifaceobj
, macvlan_ifname
, ips
[0])
440 lower_iface_mtu
= self
.ipcmd
.link_get_mtu(ifname
, refresh
=True)
443 if lower_iface_mtu
and lower_iface_mtu
!= self
.ipcmd
.link_get_mtu(macvlan_ifname
, refresh
=True):
445 self
.ipcmd
.link_set_mtu(macvlan_ifname
,
447 except Exception as e
:
448 self
.logger
.info('%s: failed to set mtu %s: %s' %
449 (macvlan_ifname
, lower_iface_mtu
, e
))
451 # set macvlan device to up in anycase.
452 # since we auto create them here..we are responsible
453 # to bring them up here in the case they were brought down
454 # by some other entity in the system.
455 netlink
.link_set_updown(macvlan_ifname
, "up")
458 if not self
.addressvirtual_with_route_metric
or not self
.ipcmd
.addr_metric_support():
459 # if the system doesn't support ip addr set METRIC
460 # we need to do manually check the ordering of the ip6 routes
461 self
.ipcmd
.fix_ipv6_route_metric(ifaceobj
, macvlan_ifname
, ips
)
462 except Exception as e
:
463 self
.logger
.debug('fix_vrf_slave_ipv6_route_metric: failed: %s' % e
)
465 # Disable IPv6 duplicate address detection on VRR interfaces
470 syskey
= "net.ipv6.conf.%s.%s" % (macvlan_ifname
, key
)
471 if self
.sysctl_get(syskey
) != sysval
:
472 self
.sysctl_set(syskey
, sysval
)
474 self
.ipcmd
.batch_commit()
475 return hw_address_list
477 def _up(self
, ifaceobj
, ifaceobj_getfunc
=None):
478 if not ifupdownflags
.flags
.ALL
:
479 self
._fixup
_vrf
_enslavements
(ifaceobj
, ifaceobj_getfunc
)
481 address_virtual_list
= ifaceobj
.get_attr_value('address-virtual')
482 vrr_config_list
= ifaceobj
.get_attr_value("vrrp")
484 if not address_virtual_list
and not vrr_config_list
:
485 # XXX: address virtual is not present. In which case,
486 # delete stale macvlan devices.
487 self
._remove
_running
_address
_config
(ifaceobj
)
490 if ifaceobj
.upperifaces
and not ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.VRF_SLAVE
:
491 self
.log_error("%s: invalid placement of address-virtual/vrrp lines "
492 "(must be configured under an interface "
493 "with no upper interfaces or parent interfaces)"
494 % ifaceobj
.name
, ifaceobj
)
496 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
499 addr_virtual_macs
= self
.create_macvlan_and_apply_config(
501 self
.translate_addrvirtual_user_config_to_list(
507 vrr_macs
= self
.create_macvlan_and_apply_config(
509 self
.translate_vrr_user_config_to_list(
515 hw_address_list
= addr_virtual_macs
+ vrr_macs
517 # check the statemanager for old configs.
518 # We need to remove only the previously configured FDB entries
519 oldmacs
= self
._get
_macs
_from
_old
_config
(ifaceobj
)
520 # get a list of fdbs in old that are not in new config meaning they should
521 # be removed since they are gone from the config
522 removed_macs
= [mac
for mac
in oldmacs
if mac
.lower() not in hw_address_list
]
523 self
._remove
_addresses
_from
_bridge
(ifaceobj
, removed_macs
)
524 # if ifaceobj is a bridge and bridge is a vlan aware bridge
525 # add the vid to the bridge
526 self
._add
_addresses
_to
_bridge
(ifaceobj
, hw_address_list
)
528 def get_vrr_prefix(self
, ifname
, family
):
529 return '%s-%sv' % (ifname
[0:10].replace('.', '-'), family
)
531 def translate_vrr_user_config_to_list(self
, ifaceobj
, vrr_config_list
, ifquery
=False):
533 If (IPv4 addresses provided):
535 else if (IPv6 addresses provided):
539 vrrp 1 2001:0db8::0370:7334/64
542 # vrrp 255 10.0.0.15/24 10.0.0.2/1
546 # "ifname": "macvlan_ifname",
547 # "hwaddress": "macvlan_hwaddress",
548 # "ips": [str(IPNetwork), ]
552 ifname
= ifaceobj
.name
553 user_config_list
= []
555 for config
in vrr_config_list
or []:
556 vrrp_id
, ip_addrs
= config
.split(" ", 1)
557 hex_id
= '%02x' % int(vrrp_id
)
561 for ip_addr
in ip_addrs
.split():
562 ip_network_obj
= IPNetwork(ip_addr
)
563 is_ip6
= isinstance(ip_network_obj
, IPv6Network
)
570 macvlan_ip4_ifname
= "%s%s" % (self
.get_vrr_prefix(ifname
, "4"), vrrp_id
)
571 macvlan_ip6_ifname
= "%s%s" % (self
.get_vrr_prefix(ifname
, "6"), vrrp_id
)
573 merged_with_existing_obj
= False
574 # if the vrr config is defined in different lines for the same ID
575 # we need to save the ip4 and ip6 in the objects we previously
577 # vrrp 255 10.0.0.15/24 10.0.0.2/15
578 # vrrp 255 fe80::a00:27ff:fe04:42/64
579 for obj
in user_config_list
:
580 if obj
.get("ifname") == macvlan_ip4_ifname
:
582 merged_with_existing_obj
= True
583 elif obj
.get("ifname") == macvlan_ip6_ifname
:
585 merged_with_existing_obj
= True
587 if merged_with_existing_obj
:
592 macvlan_ip4_mac
= "00:00:5e:00:01:%s" % hex_id
593 user_config_list
.append({
594 "ifname": macvlan_ip4_ifname
,
595 "hwaddress": macvlan_ip4_mac
,
596 "hwaddress_int": self
.mac_str_to_int(macvlan_ip4_mac
),
603 macvlan_ip6_mac
= "00:00:5e:00:02:%s" % hex_id
604 user_config_list
.append({
605 "ifname": macvlan_ip6_ifname
,
606 "hwaddress": macvlan_ip6_mac
,
607 "hwaddress_int": self
.mac_str_to_int(macvlan_ip6_mac
),
612 return user_config_list
614 def translate_addrvirtual_user_config_to_list(self
, ifaceobj
, address_virtual_list
):
617 # address-virtual 00:11:22:33:44:01 2001:0db8::0370:7334/64 11.0.1.1/24 11.0.1.2/24
621 # "ifname": "macvlan_ifname",
622 # "hwaddress": "macvlan_hwaddress",
623 # "ips": [str(IPNetwork), ]
627 user_config_list
= []
629 if not address_virtual_list
:
630 return user_config_list
632 macvlan_prefix
= self
._get
_macvlan
_prefix
(ifaceobj
)
634 for index
, addr_virtual
in enumerate(address_virtual_list
):
635 av_attrs
= addr_virtual
.split()
637 if len(av_attrs
) < 2:
638 self
.log_error("%s: incorrect address-virtual attrs '%s'"
639 % (ifaceobj
.name
, addr_virtual
), ifaceobj
,
647 if not self
.check_mac_address(ifaceobj
, mac
):
650 config
= {"ifname": "%s%d" % (macvlan_prefix
, index
)}
653 config
["hwaddress"] = mac
654 config
["hwaddress_int"] = self
.mac_str_to_int(mac
)
656 ip_network_obj_list
= []
657 for ip
in av_attrs
[1:]:
658 ip_network_obj_list
.append(str(IPNetwork(ip
)))
660 config
["ips"] = ip_network_obj_list
661 user_config_list
.append(config
)
663 return user_config_list
665 def process_macvlans_config(self
, ifaceobj
, attr_name
, virtual_addr_list_raw
, macvlan_config_list
):
666 return self
.create_macvlan_and_apply_config(ifaceobj
, macvlan_config_list
)
668 def _down(self
, ifaceobj
, ifaceobj_getfunc
=None):
670 self
._remove
_address
_config
(ifaceobj
,
671 ifaceobj
.get_attr_value('address-virtual'))
675 self
.ipcmd
.batch_start()
676 for vrr_prefix
in [self
.get_vrr_prefix(ifaceobj
.name
, "4"), self
.get_vrr_prefix(ifaceobj
.name
, "6")]:
677 for macvlan_ifacename
in glob
.glob("/sys/class/net/%s*" % vrr_prefix
):
678 macvlan_ifacename
= os
.path
.basename(macvlan_ifacename
)
679 if not self
.ipcmd
.link_exists(macvlan_ifacename
):
681 hwaddress
.append(self
.ipcmd
.link_get_hwaddress(macvlan_ifacename
))
682 self
.ipcmd
.link_delete(os
.path
.basename(macvlan_ifacename
))
683 # XXX: Also delete any fdb addresses. This requires, checking mac address
684 # on individual macvlan interfaces and deleting the vlan from that.
685 self
.ipcmd
.batch_commit()
687 self
._remove
_addresses
_from
_bridge
(ifaceobj
, hwaddress
)
690 traceback
.print_exc()
691 self
.log_warn(str(e
))
693 def _query_check(self
, ifaceobj
, ifaceobjcurr
):
695 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
698 user_config_address_virtual_ipv6_addr
= ifaceobj
.get_attr_value_first('address-virtual-ipv6-addrgen')
699 if user_config_address_virtual_ipv6_addr
and user_config_address_virtual_ipv6_addr
not in utils
._string
_values
:
700 ifaceobjcurr
.update_config_with_status('address-virtual-ipv6-addrgen', user_config_address_virtual_ipv6_addr
, 1)
701 user_config_address_virtual_ipv6_addr
= None
703 address_virtual_list
= ifaceobj
.get_attr_value('address-virtual')
705 macvlans_running_ipv6_addr_virtual
= self
.query_check_macvlan_config(
709 user_config_address_virtual_ipv6_addr
,
710 virtual_addr_list_raw
=address_virtual_list
,
711 macvlan_config_list
=self
.translate_addrvirtual_user_config_to_list(
717 vrr_config_list
= ifaceobj
.get_attr_value("vrrp")
719 macvlans_running_ipv6_addr_vrr
= self
.query_check_macvlan_config(
723 user_config_address_virtual_ipv6_addr
,
724 virtual_addr_list_raw
=vrr_config_list
,
725 macvlan_config_list
=self
.translate_vrr_user_config_to_list(
732 macvlans_running_ipv6_addr
= macvlans_running_ipv6_addr_virtual
+ macvlans_running_ipv6_addr_vrr
733 if user_config_address_virtual_ipv6_addr
:
734 bool_user_ipv6_addrgen
= utils
.get_boolean_from_string(user_config_address_virtual_ipv6_addr
)
735 for running_ipv6_addrgen
in macvlans_running_ipv6_addr
:
736 if (not bool_user_ipv6_addrgen
) != running_ipv6_addrgen
:
737 ifaceobjcurr
.update_config_with_status('address-virtual-ipv6-addrgen', user_config_address_virtual_ipv6_addr
, 1)
739 ifaceobjcurr
.update_config_with_status('address-virtual-ipv6-addrgen', user_config_address_virtual_ipv6_addr
, 0)
741 def query_check_macvlan_config(self
, ifaceobj
, ifaceobjcurr
, attr_name
, user_config_address_virtual_ipv6_addr
, virtual_addr_list_raw
, macvlan_config_list
):
743 macvlan_config_list = [
745 "ifname": "macvlan_ifname",
746 "hwaddress": "macvlan_hwaddress",
747 "ips": [str(IPNetwork), ]
751 is_vrr
= attr_name
== "vrrp"
752 macvlans_running_ipv6_addr
= []
754 if not virtual_addr_list_raw
:
755 return macvlans_running_ipv6_addr
757 macvlan_config_queue
= deque(macvlan_config_list
)
759 while macvlan_config_queue
:
764 config
= macvlan_config_queue
.popleft()
768 ip6_config
= macvlan_config_queue
.popleft()
770 macvlan_ifacename
= config
.get("ifname")
772 if not self
.ipcmd
.link_exists(macvlan_ifacename
):
773 ifaceobjcurr
.update_config_with_status(attr_name
, "", 1)
776 macvlan_hwaddress
= config
.get("hwaddress")
777 macvlan_hwaddress_int
= config
.get("hwaddress_int")
779 if user_config_address_virtual_ipv6_addr
:
780 macvlans_running_ipv6_addr
.append(self
.ipcmd
.get_ipv6_addrgen_mode(macvlan_ifacename
))
782 # Check mac and ip address
783 rhwaddress
= ip4_macvlan_hwaddress
= self
.ipcmd
.link_get_hwaddress(macvlan_ifacename
)
784 raddrs
= ip4_running_addrs
= self
.ipcmd
.get_running_addrs(
785 ifname
=macvlan_ifacename
,
787 addr_virtual_ifaceobj
=ifaceobj
791 ips
= config
.get("ips")
793 if not raddrs
or not rhwaddress
:
794 ifaceobjcurr
.update_config_with_status(attr_name
, "", 1)
798 if self
.mac_str_to_int(rhwaddress
) == macvlan_hwaddress_int \
799 and self
.ipcmd
.compare_user_config_vs_running_state(raddrs
, ips
) \
800 and self
._check
_addresses
_in
_bridge
(ifaceobj
, macvlan_hwaddress
):
801 ifaceobjcurr
.update_config_with_status(
803 " ".join(virtual_addr_list_raw
),
807 ifaceobjcurr
.update_config_with_status(
809 '%s %s' % (rhwaddress
, ' '.join(raddrs
)),
813 ifaceobjcurr
.update_config_with_status(
815 '%s %s' % (rhwaddress
, ' '.join(raddrs
)),
822 # check macvlan ip4 hwaddress (only if ip4 were provided by the user)
823 if not ip4_config
.get("ips") or ip4_macvlan_hwaddress
== ip4_config
.get("hwaddress"):
824 ip6_macvlan_ifname
= ip6_config
.get("ifname")
825 ip6_macvlan_hwaddress
= ip6_config
.get("hwaddress")
827 # check macvlan ip6 hwaddress (only if ip6 were provided by the user)
828 if not ip6_config
.get("ips") or self
.ipcmd
.link_get_hwaddress(ip6_macvlan_ifname
) == ip6_macvlan_hwaddress
:
831 if self
.ipcmd
.compare_user_config_vs_running_state(
833 ip4_config
.get("ips")
834 ) and self
._check
_addresses
_in
_bridge
(ifaceobj
, ip4_macvlan_hwaddress
):
835 ip6_running_addrs
= self
.ipcmd
.get_running_addrs(
836 ifname
=ip6_macvlan_ifname
,
838 addr_virtual_ifaceobj
=ifaceobj
842 if self
.ipcmd
.compare_user_config_vs_running_state(
844 ip6_config
.get("ips")
845 ) and self
._check
_addresses
_in
_bridge
(ifaceobj
, ip4_macvlan_hwaddress
):
846 ifaceobjcurr
.update_config_with_status(
848 "%s %s" % (ip4_config
.get("id"), " ".join(ip4_config
.get("ips") + ip6_config
.get("ips"))),
854 ifaceobjcurr
.update_config_with_status(
856 "%s %s" % (ip4_config
.get("id"), " ".join(ip4_config
.get("ips") + ip6_config
.get("ips"))),
860 return macvlans_running_ipv6_addr
862 def _query_running(self
, ifaceobjrunning
, ifaceobj_getfunc
=None):
863 macvlan_prefix
= self
._get
_macvlan
_prefix
(ifaceobjrunning
)
864 address_virtuals
= glob
.glob("/sys/class/net/%s*" %macvlan_prefix
)
865 macvlans_ipv6_addrgen_list
= []
866 for av
in address_virtuals
:
867 macvlan_ifacename
= os
.path
.basename(av
)
868 rhwaddress
= self
.ipcmd
.link_get_hwaddress(macvlan_ifacename
)
871 for obj
in ifaceobj_getfunc(ifaceobjrunning
.name
) or []:
872 raddress
.extend(self
.ipcmd
.get_running_addrs(None, macvlan_ifacename
, addr_virtual_ifaceobj
=obj
) or [])
874 raddress
= list(set(raddress
))
877 self
.logger
.warn('%s: no running addresses'
878 %ifaceobjrunning
.name
)
880 ifaceobjrunning
.update_config('address-virtual',
881 '%s %s' %(rhwaddress
, ' '.join(raddress
)))
883 macvlans_ipv6_addrgen_list
.append((macvlan_ifacename
, self
.ipcmd
.get_ipv6_addrgen_mode(macvlan_ifacename
)))
885 macvlan_count
= len(address_virtuals
)
886 if not macvlan_count
:
888 ipv6_addrgen
= macvlans_ipv6_addrgen_list
[0][1]
890 for macvlan_ifname
, macvlan_ipv6_addrgen
in macvlans_ipv6_addrgen_list
:
891 if macvlan_ipv6_addrgen
!= ipv6_addrgen
:
892 # one macvlan has a different ipv6-addrgen configuration
893 # we simply return, ifquery-running will print the macvlan
894 # stanzas with the ipv6-addrgen on/off attribute
896 ifaceobjrunning
.update_config('address-virtual-ipv6-addrgen', 'off' if ipv6_addrgen
else 'on')
899 _run_ops
= {'up' : _up
,
901 'query-checkcurr' : _query_check
,
902 'query-running' : _query_running
}
905 """ returns list of ops supported by this module """
906 return self
._run
_ops
.keys()
908 def _init_command_handlers(self
):
910 self
.ipcmd
= LinkUtils()
912 def run(self
, ifaceobj
, operation
, query_ifaceobj
=None,
913 ifaceobj_getfunc
=None, **extra_args
):
914 """ run vlan configuration on the interface object passed as argument
917 **ifaceobj** (object): iface object
919 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
922 **query_ifaceobj** (object): query check ifaceobject. This is only
923 valid when op is 'query-checkcurr'. It is an object same as
924 ifaceobj, but contains running attribute values and its config
925 status. The modules can use it to return queried running state
926 of interfaces. status is success if the running state is same
927 as user required state in ifaceobj. error otherwise.
929 if ifaceobj
.type == ifaceType
.BRIDGE_VLAN
:
931 op_handler
= self
._run
_ops
.get(operation
)
934 self
._init
_command
_handlers
()
935 if operation
== 'query-checkcurr':
936 op_handler(self
, ifaceobj
, query_ifaceobj
)
938 op_handler(self
, ifaceobj
, ifaceobj_getfunc
=ifaceobj_getfunc
)