]>
Commit | Line | Data |
---|---|---|
15ef32ea RP |
1 | #!/usr/bin/python |
2 | # | |
3 | # Copyright 2014 Cumulus Networks, Inc. All rights reserved. | |
4 | # Author: Roopa Prabhu, roopa@cumulusnetworks.com | |
5 | # | |
6 | ||
9087e727 JF |
7 | import os |
8 | ||
15ef32ea RP |
9 | try: |
10 | from ipaddr import IPNetwork | |
11 | from sets import Set | |
12 | from ifupdown.iface import * | |
13 | from ifupdownaddons.modulebase import moduleBase | |
14 | from ifupdownaddons.iproute2 import iproute2 | |
15 | from ifupdownaddons.dhclient import dhclient | |
84f33af6 | 16 | import ifupdown.policymanager as policymanager |
264dcaa0 | 17 | import ifupdown.rtnetlink_api as rtnetlink_api |
0582f185 | 18 | import ifupdown.ifupdownconfig as ifupdownConfig |
fc5e1735 | 19 | import ifupdown.ifupdownflags as ifupdownflags |
15ef32ea RP |
20 | except ImportError, e: |
21 | raise ImportError (str(e) + "- required module not found") | |
22 | ||
23 | class address(moduleBase): | |
24 | """ ifupdown2 addon module to configure address, mtu, hwaddress, alias | |
25 | (description) on an interface """ | |
26 | ||
27 | _modinfo = {'mhelp' : 'address configuration module for interfaces', | |
28 | 'attrs': { | |
29 | 'address' : | |
30 | {'help' : 'ipv4 or ipv6 addresses', | |
31 | 'example' : ['address 10.0.12.3/24', | |
32 | 'address 2000:1000:1000:1000:3::5/128']}, | |
33 | 'netmask' : | |
34 | {'help': 'netmask', | |
35 | 'example' : ['netmask 255.255.255.0'], | |
36 | 'compat' : True}, | |
37 | 'broadcast' : | |
38 | {'help': 'broadcast address', | |
39 | 'example' : ['broadcast 10.0.1.255']}, | |
40 | 'scope' : | |
41 | {'help': 'scope', | |
42 | 'example' : ['scope host']}, | |
43 | 'preferred-lifetime' : | |
44 | {'help': 'preferred lifetime', | |
45 | 'example' : ['preferred-lifetime forever', | |
46 | 'preferred-lifetime 10']}, | |
47 | 'gateway' : | |
48 | {'help': 'default gateway', | |
49 | 'example' : ['gateway 255.255.255.0']}, | |
50 | 'mtu' : | |
51 | { 'help': 'interface mtu', | |
52 | 'example' : ['mtu 1600'], | |
53 | 'default' : '1500'}, | |
54 | 'hwaddress' : | |
55 | {'help' : 'hw address', | |
56 | 'example': ['hwaddress 44:38:39:00:27:b8']}, | |
57 | 'alias' : | |
58 | { 'help': 'description/alias', | |
394e68b5 RP |
59 | 'example' : ['alias testnetwork']}, |
60 | 'address-purge' : | |
61 | { 'help': 'purge existing addresses. By default ' + | |
62 | 'any existing ip addresses on an interface are ' + | |
63 | 'purged to match persistant addresses in the ' + | |
64 | 'interfaces file. Set this attribute to \'no\'' + | |
65 | 'if you want to preserve existing addresses', | |
66 | 'default' : 'yes', | |
a794fb31 BR |
67 | 'example' : ['address-purge yes/no']}, |
68 | 'clagd-vxlan-anycast-ip' : | |
69 | { 'help' : 'Anycast local IP address for ' + | |
70 | 'dual connected VxLANs', | |
71 | 'example' : ['clagd-vxlan-anycast-ip 36.0.0.11']}}} | |
15ef32ea RP |
72 | |
73 | def __init__(self, *args, **kargs): | |
74 | moduleBase.__init__(self, *args, **kargs) | |
75 | self.ipcmd = None | |
8e113d63 | 76 | self._bridge_fdb_query_cache = {} |
84f33af6 | 77 | self.default_mtu = policymanager.policymanager_api.get_attr_default(module_name=self.__class__.__name__, attr='mtu') |
15ef32ea | 78 | |
75afe2a7 RP |
79 | def _address_valid(self, addrs): |
80 | if not addrs: | |
81 | return False | |
82 | if any(map(lambda a: True if a[:7] != '0.0.0.0' | |
83 | else False, addrs)): | |
84 | return True | |
85 | return False | |
86 | ||
428206bf | 87 | def _get_hwaddress(self, ifaceobj): |
2876ca35 | 88 | hwaddress = ifaceobj.get_attr_value_first('hwaddress') |
428206bf JF |
89 | if hwaddress and hwaddress.startswith("ether"): |
90 | hwaddress = hwaddress[5:].strip() | |
91 | return hwaddress | |
92 | ||
93 | def _process_bridge(self, ifaceobj, up): | |
94 | hwaddress = self._get_hwaddress(ifaceobj) | |
75afe2a7 RP |
95 | addrs = ifaceobj.get_attr_value_first('address') |
96 | is_vlan_dev_on_vlan_aware_bridge = False | |
97 | is_bridge = self.ipcmd.is_bridge(ifaceobj.name) | |
98 | if not is_bridge: | |
99 | if '.' in ifaceobj.name: | |
100 | (bridgename, vlan) = ifaceobj.name.split('.') | |
101 | is_vlan_dev_on_vlan_aware_bridge = self.ipcmd.bridge_is_vlan_aware(bridgename) | |
8c2c9f26 RP |
102 | if ((is_bridge and not self.ipcmd.bridge_is_vlan_aware(ifaceobj.name)) |
103 | or is_vlan_dev_on_vlan_aware_bridge): | |
75afe2a7 RP |
104 | if self._address_valid(addrs): |
105 | if up: | |
106 | self.write_file('/proc/sys/net/ipv4/conf/%s' %ifaceobj.name + | |
107 | '/arp_accept', '1') | |
108 | else: | |
109 | self.write_file('/proc/sys/net/ipv4/conf/%s' %ifaceobj.name + | |
110 | '/arp_accept', '0') | |
111 | if hwaddress and is_vlan_dev_on_vlan_aware_bridge: | |
112 | if up: | |
113 | self.ipcmd.bridge_fdb_add(bridgename, hwaddress, vlan) | |
114 | else: | |
115 | self.ipcmd.bridge_fdb_del(bridgename, hwaddress, vlan) | |
cb46a208 | 116 | |
0582f185 RP |
117 | def _get_anycast_addr(self, ifaceobjlist): |
118 | for ifaceobj in ifaceobjlist: | |
119 | anycast_addr = ifaceobj.get_attr_value_first('clagd-vxlan-anycast-ip') | |
120 | if anycast_addr: | |
121 | anycast_addr = anycast_addr+'/32' | |
122 | return anycast_addr | |
123 | return None | |
124 | ||
125 | def _inet_address_convert_to_cidr(self, ifaceobjlist): | |
15ef32ea | 126 | newaddrs = [] |
0582f185 RP |
127 | newaddr_attrs = {} |
128 | ||
129 | for ifaceobj in ifaceobjlist: | |
130 | addrs = ifaceobj.get_attr_value('address') | |
131 | if not addrs: | |
132 | continue | |
133 | ||
858a230f RP |
134 | if (((ifaceobj.role & ifaceRole.SLAVE) and |
135 | not (ifaceobj.link_privflags & ifaceLinkPrivFlags.VRF_SLAVE)) or | |
136 | ((ifaceobj.link_kind & ifaceLinkKind.BRIDGE) and | |
137 | (ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VLAN_AWARE))): | |
e6a66e79 RP |
138 | # we must not configure an IP address if the interface is |
139 | # enslaved or is a VLAN AWARE BRIDGE | |
140 | self.logger.info('%s: ignoring ip address. Interface is ' | |
141 | 'enslaved or a vlan aware bridge and cannot' | |
142 | ' have an IP Address' %(ifaceobj.name)) | |
0582f185 | 143 | return (False, newaddrs, newaddr_attrs) |
15ef32ea RP |
144 | # If user address is not in CIDR notation, convert them to CIDR |
145 | for addr_index in range(0, len(addrs)): | |
146 | addr = addrs[addr_index] | |
147 | if '/' in addr: | |
148 | newaddrs.append(addr) | |
149 | continue | |
494d31d2 | 150 | newaddr = addr |
15ef32ea RP |
151 | netmask = ifaceobj.get_attr_value_n('netmask', addr_index) |
152 | if netmask: | |
153 | prefixlen = IPNetwork('%s' %addr + | |
154 | '/%s' %netmask).prefixlen | |
0582f185 RP |
155 | newaddr = addr + '/%s' %prefixlen |
156 | newaddrs.append(newaddr) | |
15ef32ea | 157 | |
0582f185 RP |
158 | attrs = {} |
159 | for a in ['broadcast', 'pointopoint', 'scope', | |
160 | 'preferred-lifetime']: | |
161 | aval = ifaceobj.get_attr_value_n(a, addr_index) | |
162 | if aval: | |
72c964c2 | 163 | attrs[a] = aval |
0582f185 RP |
164 | |
165 | if attrs: | |
166 | newaddr_attrs[newaddr]= attrs | |
167 | return (True, newaddrs, newaddr_attrs) | |
168 | ||
77021aa1 RP |
169 | def _inet_address_list_config(self, ifaceobj, newaddrs, newaddr_attrs): |
170 | for addr_index in range(0, len(newaddrs)): | |
171 | try: | |
172 | if newaddr_attrs: | |
173 | self.ipcmd.addr_add(ifaceobj.name, newaddrs[addr_index], | |
174 | newaddr_attrs.get(newaddrs[addr_index], | |
175 | {}).get('broadcast'), | |
176 | newaddr_attrs.get(newaddrs[addr_index], | |
177 | {}).get('pointopoint'), | |
178 | newaddr_attrs.get(newaddrs[addr_index], | |
179 | {}).get('scope'), | |
180 | newaddr_attrs.get(newaddrs[addr_index], | |
181 | {}).get('preferred-lifetime')) | |
182 | else: | |
183 | self.ipcmd.addr_add(ifaceobj.name, newaddrs[addr_index]) | |
184 | except Exception, e: | |
bf3eda91 | 185 | self.log_error(str(e), ifaceobj) |
77021aa1 RP |
186 | |
187 | def _inet_address_config(self, ifaceobj, ifaceobj_getfunc=None, | |
188 | force_reapply=False): | |
0582f185 RP |
189 | squash_addr_config = (True if \ |
190 | ifupdownConfig.config.get('addr_config_squash', \ | |
191 | '0') == '1' else False) | |
192 | ||
193 | if (squash_addr_config and | |
194 | not (ifaceobj.flags & ifaceobj.YOUNGEST_SIBLING)): | |
195 | return | |
196 | ||
197 | purge_addresses = ifaceobj.get_attr_value_first('address-purge') | |
198 | if not purge_addresses: | |
199 | purge_addresses = 'yes' | |
200 | ||
201 | if squash_addr_config and ifaceobj.flags & iface.HAS_SIBLINGS: | |
202 | ifaceobjlist = ifaceobj_getfunc(ifaceobj.name) | |
203 | else: | |
204 | ifaceobjlist = [ifaceobj] | |
205 | ||
206 | (addr_supported, newaddrs, newaddr_attrs) = self._inet_address_convert_to_cidr(ifaceobjlist) | |
207 | if not addr_supported: | |
208 | return | |
209 | if (not squash_addr_config and (ifaceobj.flags & iface.HAS_SIBLINGS)): | |
210 | # if youngest sibling and squash addr is not set | |
211 | # print a warning that addresses will not be purged | |
212 | if (ifaceobj.flags & iface.YOUNGEST_SIBLING): | |
213 | self.logger.warn('%s: interface has multiple ' %ifaceobj.name + | |
214 | 'iface stanzas, skip purging existing addresses') | |
215 | purge_addresses = 'no' | |
216 | ||
fc5e1735 | 217 | if not ifupdownflags.flags.PERFMODE and purge_addresses == 'yes': |
0582f185 RP |
218 | # if perfmode is not set and purge addresses is not set to 'no' |
219 | # lets purge addresses not in the config | |
15ef32ea | 220 | runningaddrs = self.ipcmd.addr_get(ifaceobj.name, details=False) |
0582f185 | 221 | |
a794fb31 BR |
222 | # if anycast address is configured on 'lo' and is in running config |
223 | # add it to newaddrs so that ifreload doesn't wipe it out | |
0582f185 RP |
224 | anycast_addr = self._get_anycast_addr(ifaceobjlist) |
225 | ||
a794fb31 BR |
226 | if runningaddrs and anycast_addr and anycast_addr in runningaddrs: |
227 | newaddrs.append(anycast_addr) | |
15ef32ea | 228 | if newaddrs == runningaddrs: |
77021aa1 RP |
229 | if force_reapply: |
230 | self._inet_address_list_config(ifaceobj, newaddrs, newaddr_attrs) | |
15ef32ea RP |
231 | return |
232 | try: | |
233 | # if primary address is not same, there is no need to keep any. | |
234 | # reset all addresses | |
235 | if (newaddrs and runningaddrs and | |
236 | (newaddrs[0] != runningaddrs[0])): | |
237 | self.ipcmd.del_addr_all(ifaceobj.name) | |
238 | else: | |
239 | self.ipcmd.del_addr_all(ifaceobj.name, newaddrs) | |
240 | except Exception, e: | |
241 | self.log_warn(str(e)) | |
242 | if not newaddrs: | |
243 | return | |
77021aa1 | 244 | self._inet_address_list_config(ifaceobj, newaddrs, newaddr_attrs) |
15ef32ea | 245 | |
0582f185 | 246 | def _up(self, ifaceobj, ifaceobj_getfunc=None): |
15ef32ea RP |
247 | if not self.ipcmd.link_exists(ifaceobj.name): |
248 | return | |
68d9fee0 | 249 | addr_method = ifaceobj.addr_method |
77021aa1 | 250 | force_reapply = False |
15ef32ea RP |
251 | try: |
252 | # release any stale dhcp addresses if present | |
fc5e1735 | 253 | if (addr_method != "dhcp" and not ifupdownflags.flags.PERFMODE and |
15ef32ea RP |
254 | not (ifaceobj.flags & iface.HAS_SIBLINGS)): |
255 | # if not running in perf mode and ifaceobj does not have | |
256 | # any sibling iface objects, kill any stale dhclient | |
257 | # processes | |
75afe2a7 | 258 | dhclientcmd = dhclient() |
7c1135ea | 259 | if dhclientcmd.is_running(ifaceobj.name): |
15ef32ea RP |
260 | # release any dhcp leases |
261 | dhclientcmd.release(ifaceobj.name) | |
77021aa1 | 262 | force_reapply = True |
7c1135ea | 263 | elif dhclientcmd.is_running6(ifaceobj.name): |
15ef32ea | 264 | dhclientcmd.release6(ifaceobj.name) |
77021aa1 | 265 | force_reapply = True |
15ef32ea RP |
266 | except: |
267 | pass | |
8e113d63 | 268 | |
15ef32ea | 269 | self.ipcmd.batch_start() |
68d9fee0 | 270 | if addr_method != "dhcp": |
77021aa1 RP |
271 | self._inet_address_config(ifaceobj, ifaceobj_getfunc, |
272 | force_reapply) | |
15ef32ea RP |
273 | mtu = ifaceobj.get_attr_value_first('mtu') |
274 | if mtu: | |
8e113d63 | 275 | self.ipcmd.link_set(ifaceobj.name, 'mtu', mtu) |
00c12960 RP |
276 | elif (not ifaceobj.link_kind and |
277 | not (ifaceobj.link_privflags & ifaceLinkPrivFlags.BOND_SLAVE) and | |
278 | self.default_mtu): | |
279 | # logical devices like bridges and vlan devices rely on mtu | |
280 | # from their lower devices. ie mtu travels from | |
281 | # lower devices to upper devices. For bonds mtu travels from | |
282 | # upper to lower devices. running mtu depends on upper and | |
283 | # lower device mtu. With all this implicit mtu | |
284 | # config by the kernel in play, we try to be cautious here | |
285 | # on which devices we want to reset mtu to default. | |
286 | # essentially only physical interfaces which are not bond slaves | |
287 | running_mtu = self.ipcmd.link_get_mtu(ifaceobj.name) | |
288 | if running_mtu != self.default_mtu: | |
289 | self.ipcmd.link_set(ifaceobj.name, 'mtu', self.default_mtu) | |
13e22530 | 290 | |
15ef32ea RP |
291 | alias = ifaceobj.get_attr_value_first('alias') |
292 | if alias: | |
8e113d63 | 293 | self.ipcmd.link_set_alias(ifaceobj.name, alias) |
264dcaa0 RP |
294 | self.ipcmd.batch_commit() |
295 | ||
428206bf | 296 | hwaddress = self._get_hwaddress(ifaceobj) |
cb46a208 | 297 | if hwaddress: |
264dcaa0 | 298 | running_hwaddress = None |
fc5e1735 | 299 | if not ifupdownflags.flags.PERFMODE: # system is clean |
2876ca35 | 300 | running_hwaddress = self.ipcmd.link_get_hwaddress(ifaceobj.name) |
264dcaa0 RP |
301 | if hwaddress != running_hwaddress: |
302 | slave_down = False | |
303 | rtnetlink_api.rtnl_api.link_set(ifaceobj.name, "down") | |
304 | if ifaceobj.link_kind & ifaceLinkKind.BOND: | |
305 | # if bond, down all the slaves | |
306 | if ifaceobj.lowerifaces: | |
307 | for l in ifaceobj.lowerifaces: | |
308 | rtnetlink_api.rtnl_api.link_set(l, "down") | |
309 | slave_down = True | |
310 | try: | |
311 | self.ipcmd.link_set(ifaceobj.name, 'address', hwaddress) | |
312 | finally: | |
313 | rtnetlink_api.rtnl_api.link_set(ifaceobj.name, "up") | |
314 | if slave_down: | |
315 | for l in ifaceobj.lowerifaces: | |
316 | rtnetlink_api.rtnl_api.link_set(l, "up") | |
cb46a208 | 317 | |
68d9fee0 RP |
318 | try: |
319 | # Handle special things on a bridge | |
320 | self._process_bridge(ifaceobj, True) | |
321 | except Exception, e: | |
bf3eda91 | 322 | self.log_error('%s: %s' %(ifaceobj.name, str(e)), ifaceobj) |
68d9fee0 | 323 | pass |
cb46a208 | 324 | |
68d9fee0 RP |
325 | if addr_method != "dhcp": |
326 | self.ipcmd.route_add_gateway(ifaceobj.name, | |
016e9325 N |
327 | ifaceobj.get_attr_value_first('gateway'), |
328 | ifaceobj.get_attr_value_first('vrf')) | |
15ef32ea | 329 | |
0582f185 | 330 | def _down(self, ifaceobj, ifaceobj_getfunc=None): |
15ef32ea RP |
331 | try: |
332 | if not self.ipcmd.link_exists(ifaceobj.name): | |
333 | return | |
68d9fee0 RP |
334 | addr_method = ifaceobj.addr_method |
335 | if addr_method != "dhcp": | |
336 | self.ipcmd.route_del_gateway(ifaceobj.name, | |
15ef32ea | 337 | ifaceobj.get_attr_value_first('gateway'), |
016e9325 | 338 | ifaceobj.get_attr_value_first('vrf'), |
15ef32ea | 339 | ifaceobj.get_attr_value_first('metric')) |
aa052170 N |
340 | if ifaceobj.get_attr_value_first('address-purge')=='no': |
341 | addrlist = ifaceobj.get_attr_value('address') | |
342 | for addr in addrlist: | |
343 | self.ipcmd.addr_del(ifaceobj.name, addr) | |
344 | #self.ipcmd.addr_del(ifaceobj.name, ifaceobj.get_attr_value('address')[0]) | |
345 | else: | |
346 | self.ipcmd.del_addr_all(ifaceobj.name) | |
84f33af6 | 347 | mtu = ifaceobj.get_attr_value_first('mtu') |
00c12960 RP |
348 | if (not ifaceobj.link_kind and mtu and |
349 | self.default_mtu and (mtu != self.default_mtu)): | |
84f33af6 | 350 | self.ipcmd.link_set(ifaceobj.name, 'mtu', self.default_mtu) |
15ef32ea RP |
351 | alias = ifaceobj.get_attr_value_first('alias') |
352 | if alias: | |
9087e727 | 353 | filename = '/sys/class/net/%s/ifalias' %ifaceobj.name |
a4a53f4b | 354 | self.logger.info('executing echo "" > %s' %filename) |
9087e727 | 355 | os.system('echo "" > %s' %filename) |
75afe2a7 RP |
356 | # XXX hwaddress reset cannot happen because we dont know last |
357 | # address. | |
358 | ||
359 | # Handle special things on a bridge | |
360 | self._process_bridge(ifaceobj, False) | |
15ef32ea | 361 | except Exception, e: |
bcf11b14 RP |
362 | self.logger.debug('%s : %s' %(ifaceobj.name, str(e))) |
363 | pass | |
15ef32ea RP |
364 | |
365 | def _get_iface_addresses(self, ifaceobj): | |
366 | addrlist = ifaceobj.get_attr_value('address') | |
367 | outaddrlist = [] | |
368 | ||
369 | if not addrlist: return None | |
370 | for addrindex in range(0, len(addrlist)): | |
371 | addr = addrlist[addrindex] | |
372 | netmask = ifaceobj.get_attr_value_n('netmask', addrindex) | |
373 | if netmask: | |
374 | prefixlen = IPNetwork('%s' %addr + | |
375 | '/%s' %netmask).prefixlen | |
376 | addr = addr + '/%s' %prefixlen | |
377 | outaddrlist.append(addr) | |
378 | return outaddrlist | |
379 | ||
8e113d63 RP |
380 | def _get_bridge_fdbs(self, bridgename, vlan): |
381 | fdbs = self._bridge_fdb_query_cache.get(bridgename) | |
382 | if not fdbs: | |
383 | fdbs = self.ipcmd.bridge_fdb_show_dev(bridgename) | |
384 | if not fdbs: | |
385 | return | |
386 | self._bridge_fdb_query_cache[bridgename] = fdbs | |
387 | return fdbs.get(vlan) | |
388 | ||
389 | def _check_addresses_in_bridge(self, ifaceobj, hwaddress): | |
390 | """ If the device is a bridge, make sure the addresses | |
391 | are in the bridge """ | |
392 | if '.' in ifaceobj.name: | |
393 | (bridgename, vlan) = ifaceobj.name.split('.') | |
394 | if self.ipcmd.bridge_is_vlan_aware(bridgename): | |
395 | fdb_addrs = self._get_bridge_fdbs(bridgename, vlan) | |
396 | if not fdb_addrs or hwaddress not in fdb_addrs: | |
397 | return False | |
398 | return True | |
399 | ||
0582f185 | 400 | def _query_check(self, ifaceobj, ifaceobjcurr, ifaceobj_getfunc=None): |
15ef32ea RP |
401 | runningaddrsdict = None |
402 | if not self.ipcmd.link_exists(ifaceobj.name): | |
403 | self.logger.debug('iface %s not found' %ifaceobj.name) | |
404 | return | |
16d854b4 | 405 | addr_method = ifaceobj.addr_method |
15ef32ea RP |
406 | self.query_n_update_ifaceobjcurr_attr(ifaceobj, ifaceobjcurr, |
407 | 'mtu', self.ipcmd.link_get_mtu) | |
428206bf | 408 | hwaddress = self._get_hwaddress(ifaceobj) |
8e113d63 | 409 | if hwaddress: |
2876ca35 | 410 | rhwaddress = self.ipcmd.link_get_hwaddress(ifaceobj.name) |
8e113d63 RP |
411 | if not rhwaddress or rhwaddress != hwaddress: |
412 | ifaceobjcurr.update_config_with_status('hwaddress', rhwaddress, | |
413 | 1) | |
414 | elif not self._check_addresses_in_bridge(ifaceobj, hwaddress): | |
415 | # XXX: hw address is not in bridge | |
416 | ifaceobjcurr.update_config_with_status('hwaddress', rhwaddress, | |
417 | 1) | |
418 | ifaceobjcurr.status_str = 'bridge fdb error' | |
419 | else: | |
420 | ifaceobjcurr.update_config_with_status('hwaddress', rhwaddress, | |
421 | 0) | |
15ef32ea RP |
422 | self.query_n_update_ifaceobjcurr_attr(ifaceobj, ifaceobjcurr, |
423 | 'alias', self.ipcmd.link_get_alias) | |
424 | # compare addresses | |
16d854b4 RP |
425 | if addr_method == 'dhcp': |
426 | return | |
15ef32ea RP |
427 | addrs = self._get_iface_addresses(ifaceobj) |
428 | runningaddrsdict = self.ipcmd.addr_get(ifaceobj.name) | |
a794fb31 BR |
429 | # if anycast address is configured on 'lo' and is in running config |
430 | # add it to addrs so that query_check doesn't fail | |
431 | anycast_addr = ifaceobj.get_attr_value_first('clagd-vxlan-anycast-ip') | |
432 | if anycast_addr: | |
433 | anycast_addr = anycast_addr+'/32' | |
434 | if runningaddrsdict and anycast_addr and runningaddrsdict.get(anycast_addr): | |
435 | addrs.append(anycast_addr) | |
15ef32ea RP |
436 | |
437 | # Set ifaceobjcurr method and family | |
438 | ifaceobjcurr.addr_method = ifaceobj.addr_method | |
439 | ifaceobjcurr.addr_family = ifaceobj.addr_family | |
440 | if not runningaddrsdict and not addrs: | |
441 | return | |
442 | runningaddrs = runningaddrsdict.keys() if runningaddrsdict else [] | |
443 | if runningaddrs != addrs: | |
444 | runningaddrsset = set(runningaddrs) if runningaddrs else set([]) | |
445 | addrsset = set(addrs) if addrs else set([]) | |
446 | if (ifaceobj.flags & iface.HAS_SIBLINGS): | |
447 | if not addrsset: | |
448 | return | |
449 | # only check for addresses present in running config | |
450 | addrsdiff = addrsset.difference(runningaddrsset) | |
451 | for addr in addrs: | |
452 | if addr in addrsdiff: | |
453 | ifaceobjcurr.update_config_with_status('address', | |
454 | addr, 1) | |
455 | else: | |
456 | ifaceobjcurr.update_config_with_status('address', | |
457 | addr, 0) | |
458 | else: | |
459 | addrsdiff = addrsset.symmetric_difference(runningaddrsset) | |
460 | for addr in addrsset.union(runningaddrsset): | |
461 | if addr in addrsdiff: | |
462 | ifaceobjcurr.update_config_with_status('address', | |
463 | addr, 1) | |
464 | else: | |
465 | ifaceobjcurr.update_config_with_status('address', | |
466 | addr, 0) | |
467 | elif addrs: | |
468 | [ifaceobjcurr.update_config_with_status('address', | |
469 | addr, 0) for addr in addrs] | |
470 | #XXXX Check broadcast address, scope, etc | |
471 | return | |
472 | ||
0582f185 | 473 | def _query_running(self, ifaceobjrunning, ifaceobj_getfunc=None): |
15ef32ea RP |
474 | if not self.ipcmd.link_exists(ifaceobjrunning.name): |
475 | self.logger.debug('iface %s not found' %ifaceobjrunning.name) | |
15ef32ea RP |
476 | return |
477 | dhclientcmd = dhclient() | |
478 | if (dhclientcmd.is_running(ifaceobjrunning.name) or | |
479 | dhclientcmd.is_running6(ifaceobjrunning.name)): | |
480 | # If dhcp is configured on the interface, we skip it | |
84f33af6 | 481 | return |
15ef32ea RP |
482 | isloopback = self.ipcmd.link_isloopback(ifaceobjrunning.name) |
483 | if isloopback: | |
484 | default_addrs = ['127.0.0.1/8', '::1/128'] | |
485 | ifaceobjrunning.addr_family = 'inet' | |
486 | ifaceobjrunning.addr_method = 'loopback' | |
487 | else: | |
488 | default_addrs = [] | |
489 | runningaddrsdict = self.ipcmd.addr_get(ifaceobjrunning.name) | |
490 | if runningaddrsdict: | |
491 | [ifaceobjrunning.update_config('address', addr) | |
492 | for addr, addrattrs in runningaddrsdict.items() | |
493 | if addr not in default_addrs] | |
494 | mtu = self.ipcmd.link_get_mtu(ifaceobjrunning.name) | |
495 | if (mtu and | |
496 | (ifaceobjrunning.name == 'lo' and mtu != '16436') or | |
497 | (ifaceobjrunning.name != 'lo' and | |
498 | mtu != self.get_mod_subattr('mtu', 'default'))): | |
499 | ifaceobjrunning.update_config('mtu', mtu) | |
500 | alias = self.ipcmd.link_get_alias(ifaceobjrunning.name) | |
84f33af6 | 501 | if alias: |
15ef32ea RP |
502 | ifaceobjrunning.update_config('alias', alias) |
503 | ||
504 | _run_ops = {'up' : _up, | |
505 | 'down' : _down, | |
506 | 'query-checkcurr' : _query_check, | |
507 | 'query-running' : _query_running } | |
508 | ||
509 | def get_ops(self): | |
510 | """ returns list of ops supported by this module """ | |
511 | return self._run_ops.keys() | |
512 | ||
513 | def _init_command_handlers(self): | |
514 | if not self.ipcmd: | |
fc5e1735 | 515 | self.ipcmd = iproute2() |
15ef32ea | 516 | |
6e16e5ae | 517 | def run(self, ifaceobj, operation, query_ifaceobj=None, ifaceobj_getfunc=None): |
15ef32ea RP |
518 | """ run address configuration on the interface object passed as argument |
519 | ||
520 | Args: | |
521 | **ifaceobj** (object): iface object | |
522 | ||
523 | **operation** (str): any of 'up', 'down', 'query-checkcurr', | |
524 | 'query-running' | |
525 | Kwargs: | |
526 | query_ifaceobj (object): query check ifaceobject. This is only | |
527 | valid when op is 'query-checkcurr'. It is an object same as | |
528 | ifaceobj, but contains running attribute values and its config | |
529 | status. The modules can use it to return queried running state | |
530 | of interfaces. status is success if the running state is same | |
531 | as user required state in ifaceobj. error otherwise. | |
532 | """ | |
8e113d63 RP |
533 | if ifaceobj.type == ifaceType.BRIDGE_VLAN: |
534 | return | |
15ef32ea RP |
535 | op_handler = self._run_ops.get(operation) |
536 | if not op_handler: | |
537 | return | |
15ef32ea RP |
538 | self._init_command_handlers() |
539 | if operation == 'query-checkcurr': | |
0582f185 RP |
540 | op_handler(self, ifaceobj, query_ifaceobj, |
541 | ifaceobj_getfunc=ifaceobj_getfunc) | |
15ef32ea | 542 | else: |
0582f185 RP |
543 | op_handler(self, ifaceobj, |
544 | ifaceobj_getfunc=ifaceobj_getfunc) |