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