]>
Commit | Line | Data |
---|---|---|
d486dd0d JF |
1 | #!/usr/bin/python |
2 | # | |
3 | # Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved. | |
4 | # Author: Roopa Prabhu, roopa@cumulusnetworks.com | |
5 | # | |
6 | ||
7 | ||
8 | from sets import Set | |
9 | from ipaddr import IPNetwork, IPv4Address, IPv4Network, AddressValueError | |
10 | ||
11 | try: | |
12 | import ifupdown2.ifupdown.policymanager as policymanager | |
3fb83a7a | 13 | import ifupdown2.ifupdown.ifupdownflags as ifupdownflags |
d486dd0d JF |
14 | |
15 | from ifupdown2.nlmanager.nlmanager import Link | |
16 | ||
17 | from ifupdown2.ifupdown.iface import * | |
18 | from ifupdown2.ifupdown.utils import utils | |
19 | from ifupdown2.ifupdown.netlink import netlink | |
20 | from ifupdown2.ifupdownaddons.cache import * | |
21 | from ifupdown2.ifupdownaddons.LinkUtils import LinkUtils | |
22 | from ifupdown2.ifupdownaddons.modulebase import moduleBase | |
23 | except ImportError: | |
24 | import ifupdown.policymanager as policymanager | |
3fb83a7a | 25 | import ifupdown.ifupdownflags as ifupdownflags |
d486dd0d JF |
26 | |
27 | from nlmanager.nlmanager import Link | |
28 | ||
29 | from ifupdown.iface import * | |
30 | from ifupdown.utils import utils | |
31 | from ifupdown.netlink import netlink | |
32 | ||
33 | from ifupdownaddons.cache import * | |
34 | from ifupdownaddons.LinkUtils import LinkUtils | |
35 | from ifupdownaddons.modulebase import moduleBase | |
36 | ||
37 | ||
38 | class vxlan(moduleBase): | |
39 | _modinfo = {'mhelp' : 'vxlan module configures vxlan interfaces.', | |
40 | 'attrs' : { | |
41 | 'vxlan-id' : | |
42 | {'help' : 'vxlan id', | |
43 | 'validrange' : ['1', '16777214'], | |
44 | 'required' : True, | |
45 | 'example': ['vxlan-id 100']}, | |
46 | 'vxlan-local-tunnelip' : | |
47 | {'help' : 'vxlan local tunnel ip', | |
48 | 'validvals' : ['<ipv4>'], | |
49 | 'example': ['vxlan-local-tunnelip 172.16.20.103']}, | |
50 | 'vxlan-svcnodeip' : | |
51 | {'help' : 'vxlan id', | |
52 | 'validvals' : ['<ipv4>'], | |
53 | 'example': ['vxlan-svcnodeip 172.16.22.125']}, | |
54 | 'vxlan-remoteip' : | |
55 | {'help' : 'vxlan remote ip', | |
56 | 'validvals' : ['<ipv4>'], | |
57 | 'example': ['vxlan-remoteip 172.16.22.127'], | |
58 | 'multiline': True}, | |
59 | 'vxlan-learning' : | |
60 | {'help' : 'vxlan learning yes/no', | |
61 | 'validvals' : ['yes', 'no', 'on', 'off'], | |
62 | 'example': ['vxlan-learning no'], | |
63 | 'default': 'yes'}, | |
64 | 'vxlan-ageing' : | |
65 | {'help' : 'vxlan aging timer', | |
66 | 'validrange' : ['0', '4096'], | |
67 | 'example': ['vxlan-ageing 300'], | |
68 | 'default': '300'}, | |
69 | 'vxlan-purge-remotes' : | |
70 | {'help' : 'vxlan purge existing remote entries', | |
71 | 'validvals' : ['yes', 'no'], | |
72 | 'example': ['vxlan-purge-remotes yes'],}, | |
73 | 'vxlan-port': { | |
74 | 'help': 'vxlan UDP port (transmitted to vxlan driver)', | |
0d6edae7 | 75 | 'example': ['vxlan-port 4789'], |
d486dd0d JF |
76 | 'validrange': ['1', '65536'], |
77 | 'default': '4789', | |
a382b488 JF |
78 | }, |
79 | 'vxlan-physdev': | |
80 | {'help': 'vxlan physical device', | |
81 | 'example': ['vxlan-physdev eth1']}, | |
82 | ||
d486dd0d JF |
83 | }} |
84 | _clagd_vxlan_anycast_ip = "" | |
85 | _vxlan_local_tunnelip = None | |
86 | ||
87 | def __init__(self, *args, **kargs): | |
88 | moduleBase.__init__(self, *args, **kargs) | |
89 | self.ipcmd = None | |
90 | purge_remotes = policymanager.policymanager_api.get_module_globals(module_name=self.__class__.__name__, attr='vxlan-purge-remotes') | |
91 | if purge_remotes: | |
92 | self._purge_remotes = utils.get_boolean_from_string(purge_remotes) | |
93 | else: | |
94 | self._purge_remotes = False | |
95 | ||
96 | def syntax_check(self, ifaceobj, ifaceobj_getfunc): | |
97 | if self._is_vxlan_device(ifaceobj): | |
98 | if not ifaceobj.get_attr_value_first('vxlan-local-tunnelip') and not vxlan._vxlan_local_tunnelip: | |
99 | self.logger.warning('%s: missing vxlan-local-tunnelip' % ifaceobj.name) | |
100 | return False | |
101 | return self.syntax_check_localip_anycastip_equal( | |
102 | ifaceobj.name, | |
103 | ifaceobj.get_attr_value_first('vxlan-local-tunnelip') or vxlan._vxlan_local_tunnelip, | |
104 | vxlan._clagd_vxlan_anycast_ip | |
105 | ) | |
106 | return True | |
107 | ||
108 | def syntax_check_localip_anycastip_equal(self, ifname, local_ip, anycast_ip): | |
109 | try: | |
110 | if IPNetwork(local_ip) == IPNetwork(anycast_ip): | |
111 | self.logger.warning('%s: vxlan-local-tunnelip and clagd-vxlan-anycast-ip are identical (%s)' | |
112 | % (ifname, local_ip)) | |
113 | return False | |
114 | except: | |
115 | pass | |
116 | return True | |
117 | ||
118 | def get_dependent_ifacenames(self, ifaceobj, ifaceobjs_all=None): | |
119 | if self._is_vxlan_device(ifaceobj): | |
120 | ifaceobj.link_kind |= ifaceLinkKind.VXLAN | |
121 | self._set_global_local_ip(ifaceobj) | |
122 | elif ifaceobj.name == 'lo': | |
123 | clagd_vxlan_list = ifaceobj.get_attr_value('clagd-vxlan-anycast-ip') | |
124 | if clagd_vxlan_list: | |
125 | if len(clagd_vxlan_list) != 1: | |
126 | self.log_warn('%s: multiple clagd-vxlan-anycast-ip lines, using first one' | |
127 | % (ifaceobj.name,)) | |
128 | vxlan._clagd_vxlan_anycast_ip = clagd_vxlan_list[0] | |
129 | ||
130 | self._set_global_local_ip(ifaceobj) | |
a382b488 JF |
131 | |
132 | # If we should use a specific underlay device for the VXLAN | |
133 | # tunnel make sure this device is set up before the VXLAN iface. | |
134 | physdev = ifaceobj.get_attr_value_first('vxlan-physdev') | |
135 | ||
136 | if physdev: | |
137 | return [physdev] | |
138 | ||
d486dd0d JF |
139 | return None |
140 | ||
141 | def _set_global_local_ip(self, ifaceobj): | |
142 | vxlan_local_tunnel_ip = ifaceobj.get_attr_value_first('vxlan-local-tunnelip') | |
143 | if vxlan_local_tunnel_ip and not vxlan._vxlan_local_tunnelip: | |
144 | vxlan._vxlan_local_tunnelip = vxlan_local_tunnel_ip | |
145 | ||
146 | def _is_vxlan_device(self, ifaceobj): | |
147 | if ifaceobj.get_attr_value_first('vxlan-id'): | |
148 | return True | |
149 | return False | |
150 | ||
151 | def _get_purge_remotes(self, ifaceobj): | |
152 | if not ifaceobj: | |
153 | return self._purge_remotes | |
154 | purge_remotes = ifaceobj.get_attr_value_first('vxlan-purge-remotes') | |
155 | if purge_remotes: | |
156 | purge_remotes = utils.get_boolean_from_string(purge_remotes) | |
157 | else: | |
158 | purge_remotes = self._purge_remotes | |
159 | return purge_remotes | |
160 | ||
161 | def should_create_set_vxlan(self, link_exists, ifname, vxlan_id, local, learning, ageing, group): | |
162 | """ | |
163 | should we issue a netlink: ip link add dev %ifname type vxlan ...? | |
164 | checking each attribute against the cache | |
165 | """ | |
166 | if not link_exists: | |
167 | return True | |
168 | ||
169 | try: | |
170 | if ageing: | |
171 | ageing = int(ageing) | |
172 | except: | |
173 | pass | |
174 | ||
175 | for attr_list, value in ( | |
176 | ((ifname, 'linkinfo', Link.IFLA_VXLAN_ID), vxlan_id), | |
177 | ((ifname, 'linkinfo', Link.IFLA_VXLAN_AGEING), ageing), | |
178 | ((ifname, 'linkinfo', Link.IFLA_VXLAN_LOCAL), local), | |
179 | ((ifname, 'linkinfo', Link.IFLA_VXLAN_LEARNING), learning), | |
180 | ((ifname, 'linkinfo', Link.IFLA_VXLAN_GROUP), group), | |
181 | ): | |
182 | if value and not self.ipcmd.cache_check(attr_list, value): | |
183 | return True | |
184 | return False | |
185 | ||
186 | def _vxlan_create(self, ifaceobj): | |
187 | vxlanid = ifaceobj.get_attr_value_first('vxlan-id') | |
188 | if vxlanid: | |
189 | ifname = ifaceobj.name | |
190 | anycastip = self._clagd_vxlan_anycast_ip | |
191 | group = ifaceobj.get_attr_value_first('vxlan-svcnodeip') | |
192 | ||
193 | local = ifaceobj.get_attr_value_first('vxlan-local-tunnelip') | |
194 | if not local and vxlan._vxlan_local_tunnelip: | |
195 | local = vxlan._vxlan_local_tunnelip | |
196 | ||
197 | self.syntax_check_localip_anycastip_equal(ifname, local, anycastip) | |
198 | # if both local-ip and anycast-ip are identical the function prints a warning | |
199 | ||
200 | ageing = ifaceobj.get_attr_value_first('vxlan-ageing') | |
201 | vxlan_port = ifaceobj.get_attr_value_first('vxlan-port') | |
a382b488 | 202 | physdev = ifaceobj.get_attr_value_first('vxlan-physdev') |
d486dd0d JF |
203 | purge_remotes = self._get_purge_remotes(ifaceobj) |
204 | ||
205 | link_exists = self.ipcmd.link_exists(ifname) | |
206 | ||
207 | if (not link_exists or | |
208 | not ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT): | |
209 | vxlan_learning = ifaceobj.get_attr_value_first('vxlan-learning') | |
210 | if not vxlan_learning: | |
211 | vxlan_learning = self.get_attr_default_value('vxlan-learning') | |
212 | learning = utils.get_boolean_from_string(vxlan_learning) | |
213 | else: | |
214 | learning = utils.get_boolean_from_string( | |
215 | self.ipcmd.get_vxlandev_learning(ifname)) | |
216 | ||
217 | if link_exists: | |
218 | vxlanattrs = self.ipcmd.get_vxlandev_attrs(ifname) | |
219 | # on ifreload do not overwrite anycast_ip to individual ip | |
220 | # if clagd has modified | |
221 | if vxlanattrs: | |
222 | running_localtunnelip = vxlanattrs.get('local') | |
223 | if (anycastip and running_localtunnelip and | |
224 | anycastip == running_localtunnelip): | |
225 | local = running_localtunnelip | |
226 | if vxlanattrs.get('vxlanid') != vxlanid: | |
227 | self.log_error('%s: Cannot change running vxlan id: ' | |
228 | 'Operation not supported' % ifname, ifaceobj) | |
b067bba9 JF |
229 | else: |
230 | device_link_kind = self.ipcmd.link_get_kind(ifname) | |
231 | if not device_link_kind: | |
232 | self.logger.error("%s: device already exists and is not a vxlan" % ifname) | |
233 | ifaceobj.set_status(ifaceStatus.ERROR) | |
234 | return | |
235 | elif device_link_kind != "vxlan": | |
236 | self.logger.error("%s: device already exists and is not a vxlan (type %s)" % (ifname, device_link_kind)) | |
237 | ifaceobj.set_status(ifaceStatus.ERROR) | |
238 | return | |
239 | ||
d486dd0d JF |
240 | try: |
241 | vxlanid = int(vxlanid) | |
242 | except: | |
243 | self.log_error('%s: invalid vxlan-id \'%s\'' % (ifname, vxlanid), ifaceobj) | |
244 | ||
245 | if not group: | |
246 | group = policymanager.policymanager_api.get_attr_default( | |
247 | module_name=self.__class__.__name__, | |
248 | attr='vxlan-svcnodeip' | |
249 | ) | |
250 | ||
251 | if group: | |
252 | try: | |
253 | group = IPv4Address(group) | |
254 | except AddressValueError: | |
255 | try: | |
256 | group_ip = IPv4Network(group).ip | |
257 | self.logger.warning('%s: vxlan-svcnodeip %s: netmask ignored' % (ifname, group)) | |
258 | group = group_ip | |
259 | except: | |
260 | raise Exception('%s: invalid vxlan-svcnodeip %s: must be in ipv4 format' % (ifname, group)) | |
261 | ||
262 | if not local: | |
263 | local = policymanager.policymanager_api.get_attr_default( | |
264 | module_name=self.__class__.__name__, | |
265 | attr='vxlan-local-tunnelip' | |
266 | ) | |
267 | ||
268 | if local: | |
269 | try: | |
270 | local = IPv4Address(local) | |
271 | except AddressValueError: | |
272 | try: | |
273 | local_ip = IPv4Network(local).ip | |
274 | self.logger.warning('%s: vxlan-local-tunnelip %s: netmask ignored' % (ifname, local)) | |
275 | local = local_ip | |
276 | except: | |
277 | raise Exception('%s: invalid vxlan-local-tunnelip %s: must be in ipv4 format' % (ifname, local)) | |
278 | ||
279 | if not ageing: | |
280 | ageing = policymanager.policymanager_api.get_attr_default( | |
281 | module_name=self.__class__.__name__, | |
282 | attr='vxlan-ageing' | |
283 | ) | |
284 | ||
285 | if not ageing and link_exists: | |
286 | # if link doesn't exist we let the kernel define ageing | |
287 | ageing = self.get_attr_default_value('vxlan-ageing') | |
288 | ||
289 | if not vxlan_port: | |
290 | vxlan_port = policymanager.policymanager_api.get_attr_default( | |
291 | module_name=self.__class__.__name__, | |
292 | attr='vxlan-port' | |
293 | ) | |
294 | ||
295 | try: | |
296 | vxlan_port = int(vxlan_port) | |
297 | except TypeError: | |
298 | # TypeError means vxlan_port was None | |
299 | # ie: not provided by the user or the policy | |
300 | vxlan_port = netlink.VXLAN_UDP_PORT | |
301 | except ValueError as e: | |
302 | self.logger.warning('%s: vxlan-port: using default %s: invalid configured value %s' % (ifname, netlink.VXLAN_UDP_PORT, str(e))) | |
303 | vxlan_port = netlink.VXLAN_UDP_PORT | |
304 | ||
b067bba9 | 305 | if link_exists and vxlanattrs and not ifupdownflags.flags.DRYRUN: |
d486dd0d JF |
306 | cache_port = vxlanattrs.get(Link.IFLA_VXLAN_PORT) |
307 | if vxlan_port != cache_port: | |
308 | self.logger.warning('%s: vxlan-port (%s) cannot be changed - to apply the desired change please run: ifdown %s && ifup %s' | |
309 | % (ifname, cache_port, ifname, ifname)) | |
310 | vxlan_port = cache_port | |
311 | ||
312 | if self.should_create_set_vxlan(link_exists, ifname, vxlanid, local, learning, ageing, group): | |
313 | try: | |
314 | netlink.link_add_vxlan(ifname, vxlanid, | |
315 | local=local, | |
316 | learning=learning, | |
317 | ageing=ageing, | |
318 | group=group, | |
a382b488 JF |
319 | dstport=vxlan_port, |
320 | physdev=physdev) | |
d486dd0d JF |
321 | except Exception as e_netlink: |
322 | self.logger.debug('%s: vxlan netlink: %s' % (ifname, str(e_netlink))) | |
323 | try: | |
324 | self.ipcmd.link_create_vxlan(ifname, vxlanid, | |
325 | localtunnelip=local, | |
326 | svcnodeip=group, | |
327 | remoteips=ifaceobj.get_attr_value('vxlan-remoteip'), | |
328 | learning='on' if learning else 'off', | |
329 | ageing=ageing) | |
330 | except Exception as e_iproute2: | |
331 | self.logger.warning('%s: vxlan add/set failed: %s' % (ifname, str(e_iproute2))) | |
332 | return | |
333 | ||
334 | try: | |
335 | # manually adding an entry to the caching after creating/updating the vxlan | |
336 | if not ifname in linkCache.links: | |
337 | linkCache.links[ifname] = {'linkinfo': {}} | |
338 | linkCache.links[ifname]['linkinfo'].update({ | |
339 | 'learning': learning, | |
340 | Link.IFLA_VXLAN_LEARNING: learning, | |
341 | 'vxlanid': str(vxlanid), | |
342 | Link.IFLA_VXLAN_ID: vxlanid | |
343 | }) | |
344 | if ageing: | |
345 | linkCache.links[ifname]['linkinfo'].update({ | |
346 | 'ageing': ageing, | |
347 | Link.IFLA_VXLAN_AGEING: int(ageing) | |
348 | }) | |
349 | except: | |
350 | pass | |
351 | else: | |
352 | self.logger.info('%s: vxlan already exists' % ifname) | |
353 | # if the vxlan already exists it's already cached | |
354 | ||
355 | remoteips = ifaceobj.get_attr_value('vxlan-remoteip') | |
356 | if remoteips: | |
357 | try: | |
358 | for remoteip in remoteips: | |
359 | IPv4Address(remoteip) | |
360 | except Exception as e: | |
361 | self.log_error('%s: vxlan-remoteip: %s' %(ifaceobj.name, str(e))) | |
362 | ||
363 | if purge_remotes or remoteips: | |
364 | # figure out the diff for remotes and do the bridge fdb updates | |
365 | # only if provisioned by user and not by an vxlan external | |
366 | # controller. | |
367 | peers = self.ipcmd.get_vxlan_peers(ifaceobj.name, group) | |
368 | if local and remoteips and local in remoteips: | |
369 | remoteips.remove(local) | |
370 | cur_peers = set(peers) | |
371 | if remoteips: | |
372 | new_peers = set(remoteips) | |
373 | del_list = cur_peers.difference(new_peers) | |
374 | add_list = new_peers.difference(cur_peers) | |
375 | else: | |
376 | del_list = cur_peers | |
377 | add_list = [] | |
378 | ||
379 | for addr in del_list: | |
380 | try: | |
381 | self.ipcmd.bridge_fdb_del(ifaceobj.name, | |
382 | '00:00:00:00:00:00', | |
383 | None, True, addr) | |
384 | except: | |
385 | pass | |
386 | ||
387 | for addr in add_list: | |
388 | try: | |
389 | self.ipcmd.bridge_fdb_append(ifaceobj.name, | |
390 | '00:00:00:00:00:00', | |
391 | None, True, addr) | |
392 | except: | |
393 | pass | |
394 | ||
395 | def _up(self, ifaceobj): | |
396 | self._vxlan_create(ifaceobj) | |
397 | ||
398 | def _down(self, ifaceobj): | |
399 | try: | |
400 | self.ipcmd.link_delete(ifaceobj.name) | |
401 | except Exception, e: | |
402 | self.log_warn(str(e)) | |
403 | ||
404 | def _query_check_n_update(self, ifaceobj, ifaceobjcurr, attrname, attrval, | |
405 | running_attrval): | |
406 | if not ifaceobj.get_attr_value_first(attrname): | |
407 | return | |
408 | if running_attrval and attrval == running_attrval: | |
409 | ifaceobjcurr.update_config_with_status(attrname, attrval, 0) | |
410 | else: | |
411 | ifaceobjcurr.update_config_with_status(attrname, running_attrval, 1) | |
412 | ||
413 | def _query_check_n_update_addresses(self, ifaceobjcurr, attrname, | |
414 | addresses, running_addresses): | |
415 | if addresses: | |
416 | for a in addresses: | |
417 | if a in running_addresses: | |
418 | ifaceobjcurr.update_config_with_status(attrname, a, 0) | |
419 | else: | |
420 | ifaceobjcurr.update_config_with_status(attrname, a, 1) | |
421 | running_addresses = Set(running_addresses).difference( | |
422 | Set(addresses)) | |
423 | [ifaceobjcurr.update_config_with_status(attrname, a, 1) | |
424 | for a in running_addresses] | |
425 | ||
426 | def _query_check(self, ifaceobj, ifaceobjcurr): | |
427 | if not self.ipcmd.link_exists(ifaceobj.name): | |
428 | return | |
429 | # Update vxlan object | |
430 | vxlanattrs = self.ipcmd.get_vxlandev_attrs(ifaceobj.name) | |
431 | if not vxlanattrs: | |
432 | ifaceobjcurr.check_n_update_config_with_status_many(ifaceobj, | |
433 | self.get_mod_attrs(), -1) | |
434 | return | |
435 | self._query_check_n_update(ifaceobj, ifaceobjcurr, 'vxlan-id', | |
436 | ifaceobj.get_attr_value_first('vxlan-id'), | |
437 | vxlanattrs.get('vxlanid')) | |
438 | ||
439 | self._query_check_n_update( | |
440 | ifaceobj, | |
441 | ifaceobjcurr, | |
442 | 'vxlan-port', | |
443 | ifaceobj.get_attr_value_first('vxlan-port'), | |
444 | str(vxlanattrs.get(Link.IFLA_VXLAN_PORT)) | |
445 | ) | |
446 | ||
447 | running_attrval = vxlanattrs.get('local') | |
448 | attrval = ifaceobj.get_attr_value_first('vxlan-local-tunnelip') | |
449 | if not attrval: | |
450 | attrval = vxlan._vxlan_local_tunnelip | |
451 | ifaceobj.update_config('vxlan-local-tunnelip', attrval) | |
452 | ||
453 | if running_attrval == self._clagd_vxlan_anycast_ip: | |
454 | # if local ip is anycast_ip, then let query_check to go through | |
455 | attrval = self._clagd_vxlan_anycast_ip | |
456 | self._query_check_n_update(ifaceobj, ifaceobjcurr, 'vxlan-local-tunnelip', | |
457 | attrval, running_attrval) | |
458 | ||
459 | self._query_check_n_update(ifaceobj, ifaceobjcurr, 'vxlan-svcnodeip', | |
460 | ifaceobj.get_attr_value_first('vxlan-svcnodeip'), | |
461 | vxlanattrs.get('svcnode')) | |
462 | ||
463 | purge_remotes = self._get_purge_remotes(ifaceobj) | |
464 | if purge_remotes or ifaceobj.get_attr_value('vxlan-remoteip'): | |
465 | # If purge remotes or if vxlan-remoteip's are set | |
466 | # in the config file, we are owners of the installed | |
467 | # remote-ip's, lets check and report any remote ips we don't | |
468 | # understand | |
469 | self._query_check_n_update_addresses(ifaceobjcurr, 'vxlan-remoteip', | |
470 | ifaceobj.get_attr_value('vxlan-remoteip'), | |
471 | self.ipcmd.get_vxlan_peers(ifaceobj.name, vxlanattrs.get('svcnode'))) | |
472 | ||
473 | learning = ifaceobj.get_attr_value_first('vxlan-learning') | |
474 | if learning: | |
475 | running_learning = vxlanattrs.get('learning') | |
476 | if learning == 'yes' and running_learning == 'on': | |
477 | running_learning = 'yes' | |
478 | elif learning == 'no' and running_learning == 'off': | |
479 | running_learning = 'no' | |
480 | if learning == running_learning: | |
481 | ifaceobjcurr.update_config_with_status('vxlan-learning', | |
482 | running_learning, 0) | |
483 | else: | |
484 | ifaceobjcurr.update_config_with_status('vxlan-learning', | |
485 | running_learning, 1) | |
486 | ageing = ifaceobj.get_attr_value_first('vxlan-ageing') | |
487 | if not ageing: | |
488 | ageing = self.get_mod_subattr('vxlan-ageing', 'default') | |
489 | self._query_check_n_update(ifaceobj, ifaceobjcurr, 'vxlan-ageing', | |
490 | ageing, vxlanattrs.get('ageing')) | |
491 | ||
a382b488 JF |
492 | physdev = ifaceobj.get_attr_value_first('vxlan-physdev') |
493 | ||
494 | if physdev: | |
495 | ifla_vxlan_link = vxlanattrs.get(Link.IFLA_VXLAN_LINK) | |
496 | ||
497 | if ifla_vxlan_link: | |
498 | self._query_check_n_update( | |
499 | ifaceobj, | |
500 | ifaceobjcurr, | |
501 | 'vxlan-physdev', | |
502 | physdev, | |
503 | netlink.get_iface_name(ifla_vxlan_link) | |
504 | ) | |
505 | else: | |
506 | ifaceobjcurr.update_config_with_status('vxlan-physdev', physdev, 1) | |
507 | ||
508 | ||
d486dd0d JF |
509 | def _query_running(self, ifaceobjrunning): |
510 | vxlanattrs = self.ipcmd.get_vxlandev_attrs(ifaceobjrunning.name) | |
511 | if not vxlanattrs: | |
512 | return | |
513 | attrval = vxlanattrs.get('vxlanid') | |
514 | if attrval: | |
515 | ifaceobjrunning.update_config('vxlan-id', vxlanattrs.get('vxlanid')) | |
516 | else: | |
517 | # if there is no vxlan id, this is not a vxlan port | |
518 | return | |
519 | ||
520 | ifaceobjrunning.update_config('vxlan-port', vxlanattrs.get(Link.IFLA_VXLAN_PORT)) | |
521 | ||
522 | attrval = vxlanattrs.get('local') | |
523 | if attrval: | |
524 | ifaceobjrunning.update_config('vxlan-local-tunnelip', attrval) | |
525 | attrval = vxlanattrs.get('svcnode') | |
526 | if attrval: | |
527 | ifaceobjrunning.update_config('vxlan-svcnode', attrval) | |
528 | purge_remotes = self._get_purge_remotes(None) | |
529 | if purge_remotes: | |
530 | # if purge_remotes is on, it means we own the | |
531 | # remote ips. Query them and add it to the running config | |
532 | attrval = self.ipcmd.get_vxlan_peers(ifaceobjrunning.name, vxlanattrs.get('svcnode')) | |
533 | if attrval: | |
534 | [ifaceobjrunning.update_config('vxlan-remoteip', a) | |
535 | for a in attrval] | |
536 | attrval = vxlanattrs.get('learning') | |
537 | if attrval and attrval == 'on': | |
538 | ifaceobjrunning.update_config('vxlan-learning', 'on') | |
539 | attrval = vxlanattrs.get('ageing') | |
540 | if attrval: | |
541 | ifaceobjrunning.update_config('vxlan-ageing', vxlanattrs.get('ageing')) | |
542 | ||
a382b488 JF |
543 | ifla_vxlan_link = vxlanattrs.get(Link.IFLA_VXLAN_LINK) |
544 | if ifla_vxlan_link: | |
545 | ifaceobjrunning.update_config( | |
546 | 'vxlan-physdev', | |
547 | netlink.get_iface_name(ifla_vxlan_link) | |
548 | ) | |
549 | ||
d486dd0d JF |
550 | _run_ops = {'pre-up' : _up, |
551 | 'post-down' : _down, | |
552 | 'query-checkcurr' : _query_check, | |
553 | 'query-running' : _query_running} | |
554 | ||
555 | def get_ops(self): | |
556 | return self._run_ops.keys() | |
557 | ||
558 | def _init_command_handlers(self): | |
559 | if not self.ipcmd: | |
560 | self.ipcmd = LinkUtils() | |
561 | ||
562 | def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args): | |
563 | op_handler = self._run_ops.get(operation) | |
564 | if not op_handler: | |
565 | return | |
566 | if (operation != 'query-running' and | |
567 | not self._is_vxlan_device(ifaceobj)): | |
568 | return | |
569 | self._init_command_handlers() | |
570 | if operation == 'query-checkcurr': | |
571 | op_handler(self, ifaceobj, query_ifaceobj) | |
572 | else: | |
573 | op_handler(self, ifaceobj) |