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