]>
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) | |
229 | try: | |
230 | vxlanid = int(vxlanid) | |
231 | except: | |
232 | self.log_error('%s: invalid vxlan-id \'%s\'' % (ifname, vxlanid), ifaceobj) | |
233 | ||
234 | if not group: | |
235 | group = policymanager.policymanager_api.get_attr_default( | |
236 | module_name=self.__class__.__name__, | |
237 | attr='vxlan-svcnodeip' | |
238 | ) | |
239 | ||
240 | if group: | |
241 | try: | |
242 | group = IPv4Address(group) | |
243 | except AddressValueError: | |
244 | try: | |
245 | group_ip = IPv4Network(group).ip | |
246 | self.logger.warning('%s: vxlan-svcnodeip %s: netmask ignored' % (ifname, group)) | |
247 | group = group_ip | |
248 | except: | |
249 | raise Exception('%s: invalid vxlan-svcnodeip %s: must be in ipv4 format' % (ifname, group)) | |
250 | ||
251 | if not local: | |
252 | local = policymanager.policymanager_api.get_attr_default( | |
253 | module_name=self.__class__.__name__, | |
254 | attr='vxlan-local-tunnelip' | |
255 | ) | |
256 | ||
257 | if local: | |
258 | try: | |
259 | local = IPv4Address(local) | |
260 | except AddressValueError: | |
261 | try: | |
262 | local_ip = IPv4Network(local).ip | |
263 | self.logger.warning('%s: vxlan-local-tunnelip %s: netmask ignored' % (ifname, local)) | |
264 | local = local_ip | |
265 | except: | |
266 | raise Exception('%s: invalid vxlan-local-tunnelip %s: must be in ipv4 format' % (ifname, local)) | |
267 | ||
268 | if not ageing: | |
269 | ageing = policymanager.policymanager_api.get_attr_default( | |
270 | module_name=self.__class__.__name__, | |
271 | attr='vxlan-ageing' | |
272 | ) | |
273 | ||
274 | if not ageing and link_exists: | |
275 | # if link doesn't exist we let the kernel define ageing | |
276 | ageing = self.get_attr_default_value('vxlan-ageing') | |
277 | ||
278 | if not vxlan_port: | |
279 | vxlan_port = policymanager.policymanager_api.get_attr_default( | |
280 | module_name=self.__class__.__name__, | |
281 | attr='vxlan-port' | |
282 | ) | |
283 | ||
284 | try: | |
285 | vxlan_port = int(vxlan_port) | |
286 | except TypeError: | |
287 | # TypeError means vxlan_port was None | |
288 | # ie: not provided by the user or the policy | |
289 | vxlan_port = netlink.VXLAN_UDP_PORT | |
290 | except ValueError as e: | |
291 | self.logger.warning('%s: vxlan-port: using default %s: invalid configured value %s' % (ifname, netlink.VXLAN_UDP_PORT, str(e))) | |
292 | vxlan_port = netlink.VXLAN_UDP_PORT | |
293 | ||
3fb83a7a | 294 | if link_exists and not ifupdownflags.flags.DRYRUN: |
d486dd0d JF |
295 | cache_port = vxlanattrs.get(Link.IFLA_VXLAN_PORT) |
296 | if vxlan_port != cache_port: | |
297 | self.logger.warning('%s: vxlan-port (%s) cannot be changed - to apply the desired change please run: ifdown %s && ifup %s' | |
298 | % (ifname, cache_port, ifname, ifname)) | |
299 | vxlan_port = cache_port | |
300 | ||
301 | if self.should_create_set_vxlan(link_exists, ifname, vxlanid, local, learning, ageing, group): | |
302 | try: | |
303 | netlink.link_add_vxlan(ifname, vxlanid, | |
304 | local=local, | |
305 | learning=learning, | |
306 | ageing=ageing, | |
307 | group=group, | |
a382b488 JF |
308 | dstport=vxlan_port, |
309 | physdev=physdev) | |
d486dd0d JF |
310 | except Exception as e_netlink: |
311 | self.logger.debug('%s: vxlan netlink: %s' % (ifname, str(e_netlink))) | |
312 | try: | |
313 | self.ipcmd.link_create_vxlan(ifname, vxlanid, | |
314 | localtunnelip=local, | |
315 | svcnodeip=group, | |
316 | remoteips=ifaceobj.get_attr_value('vxlan-remoteip'), | |
317 | learning='on' if learning else 'off', | |
318 | ageing=ageing) | |
319 | except Exception as e_iproute2: | |
320 | self.logger.warning('%s: vxlan add/set failed: %s' % (ifname, str(e_iproute2))) | |
321 | return | |
322 | ||
323 | try: | |
324 | # manually adding an entry to the caching after creating/updating the vxlan | |
325 | if not ifname in linkCache.links: | |
326 | linkCache.links[ifname] = {'linkinfo': {}} | |
327 | linkCache.links[ifname]['linkinfo'].update({ | |
328 | 'learning': learning, | |
329 | Link.IFLA_VXLAN_LEARNING: learning, | |
330 | 'vxlanid': str(vxlanid), | |
331 | Link.IFLA_VXLAN_ID: vxlanid | |
332 | }) | |
333 | if ageing: | |
334 | linkCache.links[ifname]['linkinfo'].update({ | |
335 | 'ageing': ageing, | |
336 | Link.IFLA_VXLAN_AGEING: int(ageing) | |
337 | }) | |
338 | except: | |
339 | pass | |
340 | else: | |
341 | self.logger.info('%s: vxlan already exists' % ifname) | |
342 | # if the vxlan already exists it's already cached | |
343 | ||
344 | remoteips = ifaceobj.get_attr_value('vxlan-remoteip') | |
345 | if remoteips: | |
346 | try: | |
347 | for remoteip in remoteips: | |
348 | IPv4Address(remoteip) | |
349 | except Exception as e: | |
350 | self.log_error('%s: vxlan-remoteip: %s' %(ifaceobj.name, str(e))) | |
351 | ||
352 | if purge_remotes or remoteips: | |
353 | # figure out the diff for remotes and do the bridge fdb updates | |
354 | # only if provisioned by user and not by an vxlan external | |
355 | # controller. | |
356 | peers = self.ipcmd.get_vxlan_peers(ifaceobj.name, group) | |
357 | if local and remoteips and local in remoteips: | |
358 | remoteips.remove(local) | |
359 | cur_peers = set(peers) | |
360 | if remoteips: | |
361 | new_peers = set(remoteips) | |
362 | del_list = cur_peers.difference(new_peers) | |
363 | add_list = new_peers.difference(cur_peers) | |
364 | else: | |
365 | del_list = cur_peers | |
366 | add_list = [] | |
367 | ||
368 | for addr in del_list: | |
369 | try: | |
370 | self.ipcmd.bridge_fdb_del(ifaceobj.name, | |
371 | '00:00:00:00:00:00', | |
372 | None, True, addr) | |
373 | except: | |
374 | pass | |
375 | ||
376 | for addr in add_list: | |
377 | try: | |
378 | self.ipcmd.bridge_fdb_append(ifaceobj.name, | |
379 | '00:00:00:00:00:00', | |
380 | None, True, addr) | |
381 | except: | |
382 | pass | |
383 | ||
384 | def _up(self, ifaceobj): | |
385 | self._vxlan_create(ifaceobj) | |
386 | ||
387 | def _down(self, ifaceobj): | |
388 | try: | |
389 | self.ipcmd.link_delete(ifaceobj.name) | |
390 | except Exception, e: | |
391 | self.log_warn(str(e)) | |
392 | ||
393 | def _query_check_n_update(self, ifaceobj, ifaceobjcurr, attrname, attrval, | |
394 | running_attrval): | |
395 | if not ifaceobj.get_attr_value_first(attrname): | |
396 | return | |
397 | if running_attrval and attrval == running_attrval: | |
398 | ifaceobjcurr.update_config_with_status(attrname, attrval, 0) | |
399 | else: | |
400 | ifaceobjcurr.update_config_with_status(attrname, running_attrval, 1) | |
401 | ||
402 | def _query_check_n_update_addresses(self, ifaceobjcurr, attrname, | |
403 | addresses, running_addresses): | |
404 | if addresses: | |
405 | for a in addresses: | |
406 | if a in running_addresses: | |
407 | ifaceobjcurr.update_config_with_status(attrname, a, 0) | |
408 | else: | |
409 | ifaceobjcurr.update_config_with_status(attrname, a, 1) | |
410 | running_addresses = Set(running_addresses).difference( | |
411 | Set(addresses)) | |
412 | [ifaceobjcurr.update_config_with_status(attrname, a, 1) | |
413 | for a in running_addresses] | |
414 | ||
415 | def _query_check(self, ifaceobj, ifaceobjcurr): | |
416 | if not self.ipcmd.link_exists(ifaceobj.name): | |
417 | return | |
418 | # Update vxlan object | |
419 | vxlanattrs = self.ipcmd.get_vxlandev_attrs(ifaceobj.name) | |
420 | if not vxlanattrs: | |
421 | ifaceobjcurr.check_n_update_config_with_status_many(ifaceobj, | |
422 | self.get_mod_attrs(), -1) | |
423 | return | |
424 | self._query_check_n_update(ifaceobj, ifaceobjcurr, 'vxlan-id', | |
425 | ifaceobj.get_attr_value_first('vxlan-id'), | |
426 | vxlanattrs.get('vxlanid')) | |
427 | ||
428 | self._query_check_n_update( | |
429 | ifaceobj, | |
430 | ifaceobjcurr, | |
431 | 'vxlan-port', | |
432 | ifaceobj.get_attr_value_first('vxlan-port'), | |
433 | str(vxlanattrs.get(Link.IFLA_VXLAN_PORT)) | |
434 | ) | |
435 | ||
436 | running_attrval = vxlanattrs.get('local') | |
437 | attrval = ifaceobj.get_attr_value_first('vxlan-local-tunnelip') | |
438 | if not attrval: | |
439 | attrval = vxlan._vxlan_local_tunnelip | |
440 | ifaceobj.update_config('vxlan-local-tunnelip', attrval) | |
441 | ||
442 | if running_attrval == self._clagd_vxlan_anycast_ip: | |
443 | # if local ip is anycast_ip, then let query_check to go through | |
444 | attrval = self._clagd_vxlan_anycast_ip | |
445 | self._query_check_n_update(ifaceobj, ifaceobjcurr, 'vxlan-local-tunnelip', | |
446 | attrval, running_attrval) | |
447 | ||
448 | self._query_check_n_update(ifaceobj, ifaceobjcurr, 'vxlan-svcnodeip', | |
449 | ifaceobj.get_attr_value_first('vxlan-svcnodeip'), | |
450 | vxlanattrs.get('svcnode')) | |
451 | ||
452 | purge_remotes = self._get_purge_remotes(ifaceobj) | |
453 | if purge_remotes or ifaceobj.get_attr_value('vxlan-remoteip'): | |
454 | # If purge remotes or if vxlan-remoteip's are set | |
455 | # in the config file, we are owners of the installed | |
456 | # remote-ip's, lets check and report any remote ips we don't | |
457 | # understand | |
458 | self._query_check_n_update_addresses(ifaceobjcurr, 'vxlan-remoteip', | |
459 | ifaceobj.get_attr_value('vxlan-remoteip'), | |
460 | self.ipcmd.get_vxlan_peers(ifaceobj.name, vxlanattrs.get('svcnode'))) | |
461 | ||
462 | learning = ifaceobj.get_attr_value_first('vxlan-learning') | |
463 | if learning: | |
464 | running_learning = vxlanattrs.get('learning') | |
465 | if learning == 'yes' and running_learning == 'on': | |
466 | running_learning = 'yes' | |
467 | elif learning == 'no' and running_learning == 'off': | |
468 | running_learning = 'no' | |
469 | if learning == running_learning: | |
470 | ifaceobjcurr.update_config_with_status('vxlan-learning', | |
471 | running_learning, 0) | |
472 | else: | |
473 | ifaceobjcurr.update_config_with_status('vxlan-learning', | |
474 | running_learning, 1) | |
475 | ageing = ifaceobj.get_attr_value_first('vxlan-ageing') | |
476 | if not ageing: | |
477 | ageing = self.get_mod_subattr('vxlan-ageing', 'default') | |
478 | self._query_check_n_update(ifaceobj, ifaceobjcurr, 'vxlan-ageing', | |
479 | ageing, vxlanattrs.get('ageing')) | |
480 | ||
a382b488 JF |
481 | physdev = ifaceobj.get_attr_value_first('vxlan-physdev') |
482 | ||
483 | if physdev: | |
484 | ifla_vxlan_link = vxlanattrs.get(Link.IFLA_VXLAN_LINK) | |
485 | ||
486 | if ifla_vxlan_link: | |
487 | self._query_check_n_update( | |
488 | ifaceobj, | |
489 | ifaceobjcurr, | |
490 | 'vxlan-physdev', | |
491 | physdev, | |
492 | netlink.get_iface_name(ifla_vxlan_link) | |
493 | ) | |
494 | else: | |
495 | ifaceobjcurr.update_config_with_status('vxlan-physdev', physdev, 1) | |
496 | ||
497 | ||
d486dd0d JF |
498 | def _query_running(self, ifaceobjrunning): |
499 | vxlanattrs = self.ipcmd.get_vxlandev_attrs(ifaceobjrunning.name) | |
500 | if not vxlanattrs: | |
501 | return | |
502 | attrval = vxlanattrs.get('vxlanid') | |
503 | if attrval: | |
504 | ifaceobjrunning.update_config('vxlan-id', vxlanattrs.get('vxlanid')) | |
505 | else: | |
506 | # if there is no vxlan id, this is not a vxlan port | |
507 | return | |
508 | ||
509 | ifaceobjrunning.update_config('vxlan-port', vxlanattrs.get(Link.IFLA_VXLAN_PORT)) | |
510 | ||
511 | attrval = vxlanattrs.get('local') | |
512 | if attrval: | |
513 | ifaceobjrunning.update_config('vxlan-local-tunnelip', attrval) | |
514 | attrval = vxlanattrs.get('svcnode') | |
515 | if attrval: | |
516 | ifaceobjrunning.update_config('vxlan-svcnode', attrval) | |
517 | purge_remotes = self._get_purge_remotes(None) | |
518 | if purge_remotes: | |
519 | # if purge_remotes is on, it means we own the | |
520 | # remote ips. Query them and add it to the running config | |
521 | attrval = self.ipcmd.get_vxlan_peers(ifaceobjrunning.name, vxlanattrs.get('svcnode')) | |
522 | if attrval: | |
523 | [ifaceobjrunning.update_config('vxlan-remoteip', a) | |
524 | for a in attrval] | |
525 | attrval = vxlanattrs.get('learning') | |
526 | if attrval and attrval == 'on': | |
527 | ifaceobjrunning.update_config('vxlan-learning', 'on') | |
528 | attrval = vxlanattrs.get('ageing') | |
529 | if attrval: | |
530 | ifaceobjrunning.update_config('vxlan-ageing', vxlanattrs.get('ageing')) | |
531 | ||
a382b488 JF |
532 | ifla_vxlan_link = vxlanattrs.get(Link.IFLA_VXLAN_LINK) |
533 | if ifla_vxlan_link: | |
534 | ifaceobjrunning.update_config( | |
535 | 'vxlan-physdev', | |
536 | netlink.get_iface_name(ifla_vxlan_link) | |
537 | ) | |
538 | ||
d486dd0d JF |
539 | _run_ops = {'pre-up' : _up, |
540 | 'post-down' : _down, | |
541 | 'query-checkcurr' : _query_check, | |
542 | 'query-running' : _query_running} | |
543 | ||
544 | def get_ops(self): | |
545 | return self._run_ops.keys() | |
546 | ||
547 | def _init_command_handlers(self): | |
548 | if not self.ipcmd: | |
549 | self.ipcmd = LinkUtils() | |
550 | ||
551 | def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args): | |
552 | op_handler = self._run_ops.get(operation) | |
553 | if not op_handler: | |
554 | return | |
555 | if (operation != 'query-running' and | |
556 | not self._is_vxlan_device(ifaceobj)): | |
557 | return | |
558 | self._init_command_handlers() | |
559 | if operation == 'query-checkcurr': | |
560 | op_handler(self, ifaceobj, query_ifaceobj) | |
561 | else: | |
562 | op_handler(self, ifaceobj) |