]> git.proxmox.com Git - mirror_ifupdown2.git/blame - ifupdown2/ifupdown/netlink.py
addons: vxlan: add support for vxlan-ttl attribute
[mirror_ifupdown2.git] / ifupdown2 / ifupdown / netlink.py
CommitLineData
d486dd0d
JF
1#!/usr/bin/python
2#
3# Copyright 2016-2017 Cumulus Networks, Inc. All rights reserved.
4# Author: Julien Fortin, julien@cumulusnetworks.com
5#
6
7import sys
8import socket
9import logging
10
11from collections import OrderedDict
12
13try:
14 import ifupdown2.nlmanager.nlpacket
15 import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
16
17 from ifupdown2.ifupdownaddons.cache import *
18 from ifupdown2.ifupdownaddons.utilsbase import utilsBase
19
20 from ifupdown2.nlmanager.nlmanager import Link, Address, Route, NetlinkPacket
21except ImportError:
22 import nlmanager.nlpacket
23 import ifupdown.ifupdownflags as ifupdownflags
24
25 from ifupdownaddons.cache import *
26 from ifupdownaddons.utilsbase import utilsBase
27
28 from nlmanager.nlmanager import Link, Address, Route, NetlinkPacket
29
30
31class Netlink(utilsBase):
32 VXLAN_UDP_PORT = 4789
33
34 def __init__(self, *args, **kargs):
35 utilsBase.__init__(self, *args, **kargs)
36 try:
37 sys.path.insert(0, '/usr/share/ifupdown2/')
38 try:
39 from ifupdown2.nlmanager.nlmanager import NetlinkManager
40 # Override the nlmanager's mac_int_to_str function to print the MACs
41 # like xx:xx:xx:xx:xx:xx instead of xxxx.xxxx.xxxx
42 ifupdown2.nlmanager.nlpacket.mac_int_to_str = self.mac_int_to_str
43 except ImportError:
44 from nlmanager.nlmanager import NetlinkManager
45 # Override the nlmanager's mac_int_to_str function to print the MACs
46 # like xx:xx:xx:xx:xx:xx instead of xxxx.xxxx.xxxx
47 nlmanager.nlpacket.mac_int_to_str = self.mac_int_to_str
48
49 # this should force the use of the local nlmanager
50 self._nlmanager_api = NetlinkManager(log_level=logging.WARNING)
51
52 self.link_kind_handlers = {
53 'vlan': self._link_dump_info_data_vlan,
54 'vrf': self._link_dump_info_data_vrf,
55 'vxlan': self._link_dump_info_data_vxlan,
56 'bond': self._link_dump_info_data_bond,
5a4147c4
JF
57 'bridge': self._link_dump_info_data_bridge,
58 'gre': self._link_dump_info_data_gre_tunnel,
59 'gretap': self._link_dump_info_data_gre_tunnel,
60 "ip6gre": self._link_dump_info_data_gre_tunnel,
61 "ip6gretap": self._link_dump_info_data_gre_tunnel,
62 "ip6erspan": self._link_dump_info_data_gre_tunnel,
63 'ipip': self._link_dump_info_data_iptun_tunnel,
64 'sit': self._link_dump_info_data_iptun_tunnel,
65 'ip6tnl': self._link_dump_info_data_iptun_tunnel,
66 'vti': self._link_dump_info_data_vti_tunnel,
67 'vti6': self._link_dump_info_data_vti_tunnel
d486dd0d
JF
68 }
69
70 except Exception as e:
71 self.logger.error('cannot initialize ifupdown2\'s '
72 'netlink manager: %s' % str(e))
73 raise
74
75 @staticmethod
76 def IN_MULTICAST(a):
77 """
78 /include/uapi/linux/in.h
79
80 #define IN_CLASSD(a) ((((long int) (a)) & 0xf0000000) == 0xe0000000)
81 #define IN_MULTICAST(a) IN_CLASSD(a)
82 """
83 return (int(a) & 0xf0000000) == 0xe0000000
84
85 @staticmethod
86 def mac_int_to_str(mac_int):
87 """
88 Return an integer in MAC string format: xx:xx:xx:xx:xx:xx
89 """
90 return ':'.join(("%012x" % mac_int)[i:i + 2] for i in range(0, 12, 2))
91
92 def get_iface_index(self, ifacename):
93 if ifupdownflags.flags.DRYRUN: return
94 try:
95 return self._nlmanager_api.get_iface_index(ifacename)
96 except Exception as e:
97 raise Exception('%s: netlink: %s: cannot get ifindex: %s'
98 % (ifacename, ifacename, str(e)))
99
100 def get_iface_name(self, ifindex):
101 if ifupdownflags.flags.DRYRUN: return
102 try:
103 return self._nlmanager_api.get_iface_name(ifindex)
104 except Exception as e:
105 raise Exception('netlink: cannot get ifname for index %s: %s' % (ifindex, str(e)))
106
107 def get_bridge_vlan(self, ifname):
108 self.logger.info('%s: netlink: /sbin/bridge -d -c -json vlan show' % ifname)
109 if ifupdownflags.flags.DRYRUN: return
110 try:
111 return self._nlmanager_api.vlan_get()
112 except Exception as e:
113 raise Exception('netlink: get bridge vlan: %s' % str(e))
114
115 def bridge_set_vlan_filtering(self, ifname, vlan_filtering):
116 self.logger.info('%s: netlink: ip link set dev %s type bridge vlan_filtering %s'
117 % (ifname, ifname, vlan_filtering))
118 if ifupdownflags.flags.DRYRUN: return
119 try:
120 ifla_info_data = {Link.IFLA_BR_VLAN_FILTERING: int(vlan_filtering)}
121 return self._nlmanager_api.link_set_attrs(ifname, 'bridge', ifla_info_data=ifla_info_data)
122 except Exception as e:
123 raise Exception('%s: cannot set %s vlan_filtering %s' % (ifname, ifname, vlan_filtering))
124
125 def link_add_set(self,
126 ifname=None, ifindex=0,
127 kind=None, slave_kind=None,
128 ifla={},
129 ifla_info_data={},
130 ifla_info_slave_data={},
131 link_exists=False):
132 action = 'set' if ifindex or link_exists else 'add'
133
134 if slave_kind:
135 self.logger.info('%s: netlink: ip link set dev %s: %s slave attributes' % (ifname, ifname, slave_kind))
136 else:
137 self.logger.info('%s: netlink: ip link %s %s type %s with attributes' % (ifname, action, ifname, kind))
138 if ifla:
139 self.logger.debug('%s: ifla attributes a %s' % (ifname, ifla))
140 if ifla_info_data:
141 self.logger.debug('%s: ifla_info_data %s' % (ifname, ifla_info_data))
142 if ifla_info_slave_data:
143 self.logger.debug('%s: ifla_info_slave_data %s' % (ifname, ifla_info_slave_data))
144
145 if ifupdownflags.flags.DRYRUN: return
146 try:
147 self._nlmanager_api.link_add_set(ifname=ifname,
148 ifindex=ifindex,
149 kind=kind,
150 slave_kind=slave_kind,
151 ifla=ifla,
152 ifla_info_data=ifla_info_data,
153 ifla_info_slave_data=ifla_info_slave_data)
154 except Exception as e:
155 if kind and not slave_kind:
156 kind_str = kind
157 elif kind and slave_kind:
158 kind_str = '%s (%s slave)' % (kind, slave_kind)
159 else:
160 kind_str = '(%s slave)' % slave_kind
161
162 raise Exception('netlink: cannot %s %s %s with options: %s' % (action, kind_str, ifname, str(e)))
163
164 def link_del(self, ifname):
165 self.logger.info('%s: netlink: ip link del %s' % (ifname, ifname))
166 if ifupdownflags.flags.DRYRUN: return
167 try:
168 self._nlmanager_api.link_del(ifname=ifname)
169 except Exception as e:
170 raise Exception('netlink: cannot delete link %s: %s' % (ifname, str(e)))
171
172 def link_set_master(self, ifacename, master_dev, state=None):
173 self.logger.info('%s: netlink: ip link set dev %s master %s %s'
174 % (ifacename, ifacename, master_dev,
175 state if state else ''))
176 if ifupdownflags.flags.DRYRUN: return
177 try:
178 master = 0 if not master_dev else self.get_iface_index(master_dev)
179 return self._nlmanager_api.link_set_master(ifacename,
180 master_ifindex=master,
181 state=state)
182 except Exception as e:
183 raise Exception('netlink: %s: cannot set %s master %s: %s'
184 % (ifacename, ifacename, master_dev, str(e)))
185
186 def link_set_nomaster(self, ifacename, state=None):
187 self.logger.info('%s: netlink: ip link set dev %s nomaster %s'
188 % (ifacename, ifacename, state if state else ''))
189 if ifupdownflags.flags.DRYRUN: return
190 try:
191 return self._nlmanager_api.link_set_master(ifacename,
192 master_ifindex=0,
193 state=state)
194 except Exception as e:
195 raise Exception('netlink: %s: cannot set %s nomaster: %s'
196 % (ifacename, ifacename, str(e)))
197
198 def link_add_vlan(self, vlanrawdevice, ifacename, vlanid, vlan_protocol):
199 if vlan_protocol:
200 self.logger.info('%s: netlink: ip link add link %s name %s type vlan id %s protocol %s'
201 % (ifacename, vlanrawdevice, ifacename, vlanid, vlan_protocol))
202
203 else:
204 self.logger.info('%s: netlink: ip link add link %s name %s type vlan id %s'
205 % (ifacename, vlanrawdevice, ifacename, vlanid))
206 if ifupdownflags.flags.DRYRUN: return
207 ifindex = self.get_iface_index(vlanrawdevice)
208 try:
209 return self._nlmanager_api.link_add_vlan(ifindex, ifacename, vlanid, vlan_protocol)
210 except Exception as e:
211 raise Exception('netlink: %s: cannot create vlan %s: %s'
212 % (vlanrawdevice, vlanid, str(e)))
213
214 def link_add_macvlan(self, ifacename, macvlan_ifacename):
215 self.logger.info('%s: netlink: ip link add link %s name %s type macvlan mode private'
216 % (ifacename, ifacename, macvlan_ifacename))
217 if ifupdownflags.flags.DRYRUN: return
218 ifindex = self.get_iface_index(ifacename)
219 try:
220 return self._nlmanager_api.link_add_macvlan(ifindex, macvlan_ifacename)
221 except Exception as e:
222 raise Exception('netlink: %s: cannot create macvlan %s: %s'
223 % (ifacename, macvlan_ifacename, str(e)))
224
225 def link_set_updown(self, ifacename, state):
226 self.logger.info('%s: netlink: ip link set dev %s %s'
227 % (ifacename, ifacename, state))
228 if ifupdownflags.flags.DRYRUN: return
229 try:
230 return self._nlmanager_api.link_set_updown(ifacename, state)
231 except Exception as e:
232 raise Exception('netlink: cannot set link %s %s: %s'
233 % (ifacename, state, str(e)))
234
235 def link_set_protodown(self, ifacename, state):
236 self.logger.info('%s: netlink: set link %s protodown %s'
237 % (ifacename, ifacename, state))
238 if ifupdownflags.flags.DRYRUN: return
239 try:
240 return self._nlmanager_api.link_set_protodown(ifacename, state)
241 except Exception as e:
242 raise Exception('netlink: cannot set link %s protodown %s: %s'
243 % (ifacename, state, str(e)))
244
245 def link_add_bridge(self, ifname):
246 self.logger.info('%s: netlink: ip link add %s type bridge' % (ifname, ifname))
247 if ifupdownflags.flags.DRYRUN: return
248 try:
249 return self._nlmanager_api.link_add_bridge(ifname)
250 except Exception as e:
251 raise Exception('netlink: cannot create bridge %s: %s' % (ifname, str(e)))
252
253 def link_add_bridge_vlan(self, ifacename, vlanid):
254 self.logger.info('%s: netlink: bridge vlan add vid %s dev %s'
255 % (ifacename, vlanid, ifacename))
256 if ifupdownflags.flags.DRYRUN: return
257 ifindex = self.get_iface_index(ifacename)
258 try:
259 return self._nlmanager_api.link_add_bridge_vlan(ifindex, vlanid)
260 except Exception as e:
261 raise Exception('netlink: %s: cannot create bridge vlan %s: %s'
262 % (ifacename, vlanid, str(e)))
263
264 def link_del_bridge_vlan(self, ifacename, vlanid):
265 self.logger.info('%s: netlink: bridge vlan del vid %s dev %s'
266 % (ifacename, vlanid, ifacename))
267 if ifupdownflags.flags.DRYRUN: return
268 ifindex = self.get_iface_index(ifacename)
269 try:
270 return self._nlmanager_api.link_del_bridge_vlan(ifindex, vlanid)
271 except Exception as e:
272 raise Exception('netlink: %s: cannot remove bridge vlan %s: %s'
273 % (ifacename, vlanid, str(e)))
274
275 def link_add_vxlan(self, ifacename, vxlanid, local=None, dstport=VXLAN_UDP_PORT,
ec25a08c 276 group=None, learning=True, ageing=None, physdev=None, ttl=None):
d486dd0d
JF
277 cmd = 'ip link add %s type vxlan id %s dstport %s' % (ifacename,
278 vxlanid,
279 dstport)
280 cmd += ' local %s' % local if local else ''
281 cmd += ' ageing %s' % ageing if ageing else ''
282 cmd += ' remote %s' % group if group else ' noremote'
283 cmd += ' nolearning' if not learning else ''
a382b488 284 cmd += ' dev %s' % physdev if physdev else ''
ec25a08c
JF
285
286 if ttl is not None:
287 cmd += ' ttl %s' % ttl
288
d486dd0d
JF
289 self.logger.info('%s: netlink: %s' % (ifacename, cmd))
290 if ifupdownflags.flags.DRYRUN: return
291 try:
a382b488
JF
292 if physdev:
293 physdev = self.get_iface_index(physdev)
d486dd0d
JF
294 return self._nlmanager_api.link_add_vxlan(ifacename,
295 vxlanid,
296 dstport=dstport,
297 local=local,
298 group=group,
299 learning=learning,
a382b488 300 ageing=ageing,
ec25a08c
JF
301 physdev=physdev,
302 ttl=ttl)
d486dd0d
JF
303 except Exception as e:
304 raise Exception('netlink: %s: cannot create vxlan %s: %s'
305 % (ifacename, vxlanid, str(e)))
306
307 @staticmethod
308 def _link_dump_attr(link, ifla_attributes, dump):
309 for obj in ifla_attributes:
310 attr = link.attributes.get(obj['attr'])
311 if attr:
312 dump[obj['name']] = attr.get_pretty_value(obj=obj.get('func'))
313
314 @staticmethod
315 def _link_dump_linkdata_attr(linkdata, ifla_linkdata_attr, dump):
316 for obj in ifla_linkdata_attr:
317 attr = obj['attr']
318 if attr in linkdata:
319 func = obj.get('func')
320 value = linkdata.get(attr)
321
322 if func:
323 value = func(value)
324
325 if value or obj['accept_none']:
326 dump[obj['name']] = value
327
328 ifla_attributes = [
329 {
330 'attr': Link.IFLA_LINK,
331 'name': 'link',
332 'func': lambda x: netlink.get_iface_name(x) if x > 0 else None
333 },
334 {
335 'attr': Link.IFLA_MASTER,
336 'name': 'master',
337 'func': lambda x: netlink.get_iface_name(x) if x > 0 else None
338 },
339 {
340 'attr': Link.IFLA_IFNAME,
341 'name': 'ifname',
342 'func': str,
343 },
344 {
345 'attr': Link.IFLA_MTU,
346 'name': 'mtu',
347 'func': str
348 },
349 {
350 'attr': Link.IFLA_OPERSTATE,
351 'name': 'state',
352 'func': lambda x: '0%x' % int(x) if x > len(Link.oper_to_string) else Link.oper_to_string[x][8:]
007cae35
JF
353 },
354 {
355 'attr': Link.IFLA_AF_SPEC,
356 'name': 'af_spec',
357 'func': dict
d486dd0d
JF
358 }
359 ]
360
361 ifla_address = {'attr': Link.IFLA_ADDRESS, 'name': 'hwaddress', 'func': str}
362
363 ifla_vxlan_attributes = [
364 {
365 'attr': Link.IFLA_VXLAN_LOCAL,
366 'name': 'local',
367 'func': str,
368 'accept_none': True
369 },
370 {
371 'attr': Link.IFLA_VXLAN_LOCAL6,
372 'name': 'local',
373 'func': str,
374 'accept_none': True
375 },
376 {
377 'attr': Link.IFLA_VXLAN_GROUP,
378 'name': 'svcnode',
379 'func': lambda x: str(x) if not Netlink.IN_MULTICAST(x) else None,
380 'accept_none': False
381 },
382 {
383 'attr': Link.IFLA_VXLAN_GROUP6,
384 'name': 'svcnode',
385 'func': lambda x: str(x) if not Netlink.IN_MULTICAST(x) else None,
386 'accept_none': False
387 },
388 {
389 'attr': Link.IFLA_VXLAN_LEARNING,
390 'name': 'learning',
391 'func': lambda x: 'on' if x else 'off',
392 'accept_none': True
393 }
394 ]
395
396 def _link_dump_info_data_vlan(self, ifname, linkdata):
397 return {
398 'vlanid': str(linkdata.get(Link.IFLA_VLAN_ID, '')),
399 'vlan_protocol': linkdata.get(Link.IFLA_VLAN_PROTOCOL)
400 }
401
402 def _link_dump_info_data_vrf(self, ifname, linkdata):
403 vrf_info = {'table': str(linkdata.get(Link.IFLA_VRF_TABLE, ''))}
404
405 # to remove later when moved to a true netlink cache
406 linkCache.vrfs[ifname] = vrf_info
407 return vrf_info
408
409 def _link_dump_info_data_vxlan(self, ifname, linkdata):
410 for attr, value in (
411 ('learning', 'on'),
412 ('svcnode', None),
413 ('vxlanid', str(linkdata.get(Link.IFLA_VXLAN_ID, ''))),
414 ('ageing', str(linkdata.get(Link.IFLA_VXLAN_AGEING, ''))),
415 (Link.IFLA_VXLAN_PORT, linkdata.get(Link.IFLA_VXLAN_PORT))
416 ):
417 linkdata[attr] = value
418 self._link_dump_linkdata_attr(linkdata, self.ifla_vxlan_attributes, linkdata)
419 return linkdata
420
421 ifla_bond_attributes = (
422 Link.IFLA_BOND_MODE,
423 Link.IFLA_BOND_MIIMON,
424 Link.IFLA_BOND_USE_CARRIER,
425 Link.IFLA_BOND_AD_LACP_RATE,
426 Link.IFLA_BOND_XMIT_HASH_POLICY,
427 Link.IFLA_BOND_MIN_LINKS,
428 Link.IFLA_BOND_NUM_PEER_NOTIF,
429 Link.IFLA_BOND_AD_ACTOR_SYSTEM,
430 Link.IFLA_BOND_AD_ACTOR_SYS_PRIO,
431 Link.IFLA_BOND_AD_LACP_BYPASS,
432 Link.IFLA_BOND_UPDELAY,
433 Link.IFLA_BOND_DOWNDELAY,
434 )
435
436 def _link_dump_info_data_bond(self, ifname, linkdata):
437 linkinfo = {}
438 for nl_attr in self.ifla_bond_attributes:
439 try:
440 linkinfo[nl_attr] = linkdata.get(nl_attr)
441 except Exception as e:
442 self.logger.debug('%s: parsing bond IFLA_INFO_DATA (%s): %s'
443 % (ifname, nl_attr, str(e)))
444 return linkinfo
445
446 # this dict contains the netlink attribute, cache key,
447 # and a callable to translate the netlink value into
448 # whatever value we need to store in the old cache to
449 # make sure we don't break anything
450 ifla_bridge_attributes = (
451 (Link.IFLA_BR_UNSPEC, Link.IFLA_BR_UNSPEC, None),
452 (Link.IFLA_BR_FORWARD_DELAY, "fd", lambda x: str(x / 100)),
453 (Link.IFLA_BR_HELLO_TIME, "hello", lambda x: str(x / 100)),
454 (Link.IFLA_BR_MAX_AGE, "maxage", lambda x: str(x / 100)),
455 (Link.IFLA_BR_AGEING_TIME, "ageing", lambda x: str(x / 100)),
456 (Link.IFLA_BR_STP_STATE, "stp", lambda x: 'yes' if x else 'no'),
457 (Link.IFLA_BR_PRIORITY, "bridgeprio", str),
458 (Link.IFLA_BR_VLAN_FILTERING, 'vlan_filtering', str),
459 (Link.IFLA_BR_VLAN_PROTOCOL, "vlan-protocol", str),
460 (Link.IFLA_BR_GROUP_FWD_MASK, Link.IFLA_BR_GROUP_FWD_MASK, None),
461 (Link.IFLA_BR_ROOT_ID, Link.IFLA_BR_ROOT_ID, None),
462 (Link.IFLA_BR_BRIDGE_ID, Link.IFLA_BR_BRIDGE_ID, None),
463 (Link.IFLA_BR_ROOT_PORT, Link.IFLA_BR_ROOT_PORT, None),
464 (Link.IFLA_BR_ROOT_PATH_COST, Link.IFLA_BR_ROOT_PATH_COST, None),
465 (Link.IFLA_BR_TOPOLOGY_CHANGE, Link.IFLA_BR_TOPOLOGY_CHANGE, None),
466 (Link.IFLA_BR_TOPOLOGY_CHANGE_DETECTED, Link.IFLA_BR_TOPOLOGY_CHANGE_DETECTED, None),
467 (Link.IFLA_BR_HELLO_TIMER, Link.IFLA_BR_HELLO_TIMER, None),
468 (Link.IFLA_BR_TCN_TIMER, Link.IFLA_BR_TCN_TIMER, None),
469 (Link.IFLA_BR_TOPOLOGY_CHANGE_TIMER, Link.IFLA_BR_TOPOLOGY_CHANGE_TIMER, None),
470 (Link.IFLA_BR_GC_TIMER, Link.IFLA_BR_GC_TIMER, None),
471 (Link.IFLA_BR_GROUP_ADDR, Link.IFLA_BR_GROUP_ADDR, None),
472 (Link.IFLA_BR_FDB_FLUSH, Link.IFLA_BR_FDB_FLUSH, None),
473 (Link.IFLA_BR_MCAST_ROUTER, "mcrouter", str),
474 (Link.IFLA_BR_MCAST_SNOOPING, "mcsnoop", str),
475 (Link.IFLA_BR_MCAST_QUERY_USE_IFADDR, "mcqifaddr", str),
476 (Link.IFLA_BR_MCAST_QUERIER, "mcquerier", str),
477 (Link.IFLA_BR_MCAST_HASH_ELASTICITY, "hashel", str),
478 (Link.IFLA_BR_MCAST_HASH_MAX, "hashmax", str),
479 (Link.IFLA_BR_MCAST_LAST_MEMBER_CNT, "mclmc", str),
480 (Link.IFLA_BR_MCAST_STARTUP_QUERY_CNT, "mcsqc", str),
481 (Link.IFLA_BR_MCAST_LAST_MEMBER_INTVL, "mclmi", lambda x: str(x / 100)),
482 (Link.IFLA_BR_MCAST_MEMBERSHIP_INTVL, "mcmi", lambda x: str(x / 100)),
483 (Link.IFLA_BR_MCAST_QUERIER_INTVL, "mcqpi", lambda x: str(x / 100)),
484 (Link.IFLA_BR_MCAST_QUERY_INTVL, "mcqi", lambda x: str(x / 100)),
485 (Link.IFLA_BR_MCAST_QUERY_RESPONSE_INTVL, "mcqri", lambda x: str(x / 100)),
486 (Link.IFLA_BR_MCAST_STARTUP_QUERY_INTVL, "mcsqi", lambda x: str(x / 100)),
487 (Link.IFLA_BR_NF_CALL_IPTABLES, Link.IFLA_BR_NF_CALL_IPTABLES, None),
488 (Link.IFLA_BR_NF_CALL_IP6TABLES, Link.IFLA_BR_NF_CALL_IP6TABLES, None),
489 (Link.IFLA_BR_NF_CALL_ARPTABLES, Link.IFLA_BR_NF_CALL_ARPTABLES, None),
490 (Link.IFLA_BR_VLAN_DEFAULT_PVID, Link.IFLA_BR_VLAN_DEFAULT_PVID, None),
491 (Link.IFLA_BR_PAD, Link.IFLA_BR_PAD, None),
492 (Link.IFLA_BR_VLAN_STATS_ENABLED, "vlan-stats", str),
493 (Link.IFLA_BR_MCAST_STATS_ENABLED, "mcstats", str),
494 (Link.IFLA_BR_MCAST_IGMP_VERSION, "igmp-version", str),
495 (Link.IFLA_BR_MCAST_MLD_VERSION, "mld-version", str)
496 )
497
498 def _link_dump_info_data_bridge(self, ifname, linkdata):
499 linkinfo = {}
500 for nl_attr, cache_key, func in self.ifla_bridge_attributes:
501 try:
502 if func:
503 linkinfo[cache_key] = func(linkdata.get(nl_attr))
504 else:
505 linkinfo[cache_key] = linkdata.get(nl_attr)
506
507 # we also store the value in pure netlink,
508 # to make the transition easier in the future
509 linkinfo[nl_attr] = linkdata.get(nl_attr)
510 except Exception as e:
511 self.logger.error('%s: parsing birdge IFLA_INFO_DATA %s: %s'
512 % (ifname, nl_attr, str(e)))
513 return linkinfo
514
515 def _link_dump_info_slave_data_bridge(self, ifname, info_slave_data):
516 return info_slave_data
517
5a4147c4
JF
518 def _link_dump_info_data_gre_tunnel(self, ifname, info_slave_data):
519 tunnel_link_ifindex = info_slave_data.get(Link.IFLA_GRE_LINK)
520
521 return {
522 "endpoint": str(info_slave_data.get(Link.IFLA_GRE_REMOTE)),
523 "local": str(info_slave_data.get(Link.IFLA_GRE_LOCAL)),
524 "ttl": str(info_slave_data.get(Link.IFLA_GRE_TTL)),
6039c4d7 525 "tunnel-physdev": self.get_iface_name(tunnel_link_ifindex) if tunnel_link_ifindex else ""
5a4147c4
JF
526 }
527
528 def _link_dump_info_data_iptun_tunnel(self, ifname, info_slave_data):
529 tunnel_link_ifindex = info_slave_data.get(Link.IFLA_IPTUN_LINK)
530
531 return {
532 "endpoint": str(info_slave_data.get(Link.IFLA_IPTUN_REMOTE)),
533 "local": str(info_slave_data.get(Link.IFLA_IPTUN_LOCAL)),
534 "ttl": str(info_slave_data.get(Link.IFLA_IPTUN_TTL)),
6039c4d7 535 "tunnel-physdev": self.get_iface_name(tunnel_link_ifindex) if tunnel_link_ifindex else ""
5a4147c4
JF
536 }
537
538 def _link_dump_info_data_vti_tunnel(self, ifname, info_slave_data):
539 tunnel_link_ifindex = info_slave_data.get(Link.IFLA_VTI_LINK)
540
541 return {
542 "endpoint": str(info_slave_data.get(Link.IFLA_VTI_REMOTE)),
543 "local": str(info_slave_data.get(Link.IFLA_VTI_LOCAL)),
6039c4d7 544 "tunnel-physdev": self.get_iface_name(tunnel_link_ifindex) if tunnel_link_ifindex else ""
5a4147c4
JF
545 }
546
d486dd0d
JF
547 def _link_dump_linkinfo(self, link, dump):
548 linkinfo = link.attributes[Link.IFLA_LINKINFO].get_pretty_value(dict)
549
550 if linkinfo:
551 info_kind = linkinfo.get(Link.IFLA_INFO_KIND)
552 info_data = linkinfo.get(Link.IFLA_INFO_DATA)
553
554 info_slave_kind = linkinfo.get(Link.IFLA_INFO_SLAVE_KIND)
555 info_slave_data = linkinfo.get(Link.IFLA_INFO_SLAVE_DATA)
556
557 dump['kind'] = info_kind
558 dump['slave_kind'] = info_slave_kind
559
560 if info_data:
561 link_kind_handler = self.link_kind_handlers.get(info_kind)
562 if callable(link_kind_handler):
563 dump['linkinfo'] = link_kind_handler(dump['ifname'], info_data)
564
565 if info_slave_data:
566 dump['info_slave_data'] = info_slave_data
567
568 def link_dump(self, ifname=None):
569 if ifname:
570 self.logger.info('netlink: ip link show dev %s' % ifname)
571 else:
572 self.logger.info('netlink: ip link show')
573
574 if ifupdownflags.flags.DRYRUN: return {}
575
576 links = dict()
577
578 try:
579 links_dump = self._nlmanager_api.link_dump(ifname)
580 except Exception as e:
581 raise Exception('netlink: link dump failed: %s' % str(e))
582
583 for link in links_dump:
584 try:
585 dump = dict()
586
587 flags = []
588 for flag, string in Link.flag_to_string.items():
589 if link.flags & flag:
590 flags.append(string[4:])
591
592 dump['flags'] = flags
593 dump['ifflag'] = 'UP' if 'UP' in flags else 'DOWN'
594 dump['ifindex'] = str(link.ifindex)
595
596 if link.device_type == Link.ARPHRD_ETHER:
597 self._link_dump_attr(link, [self.ifla_address], dump)
598
599 self._link_dump_attr(link, self.ifla_attributes, dump)
600
601 if Link.IFLA_LINKINFO in link.attributes:
602 self._link_dump_linkinfo(link, dump)
603
604 links[dump['ifname']] = dump
605 except Exception as e:
606 self.logger.warning('netlink: ip link show: %s' % str(e))
607 return links
608
609 def _addr_dump_extract_ifname(self, addr_packet):
610 addr_ifname_attr = addr_packet.attributes.get(Address.IFA_LABEL)
611
612 if addr_ifname_attr:
613 return addr_ifname_attr.get_pretty_value(str)
614 else:
615 return self.get_iface_name(addr_packet.ifindex)
616
617 @staticmethod
618 def _addr_filter(addr_ifname, addr):
619 return addr_ifname == 'lo' and addr in ['127.0.0.1/8', '::1/128', '0.0.0.0']
620
621 def _addr_dump_entry(self, ifaces, addr_packet, addr_ifname, ifa_attr):
622 attribute = addr_packet.attributes.get(ifa_attr)
623
624 if attribute:
625 address = attribute.get_pretty_value(str)
626
627 if hasattr(addr_packet, 'prefixlen'):
628 address = '%s/%d' % (address, addr_packet.prefixlen)
629
630 if self._addr_filter(addr_ifname, address):
631 return
632
633 addr_family = NetlinkPacket.af_family_to_string.get(addr_packet.family)
634 if not addr_family:
635 return
636
637 ifaces[addr_ifname]['addrs'][address] = {
638 'type': addr_family,
639 'scope': addr_packet.scope
640 }
641
642 ifa_address_attributes = [
643 Address.IFA_ADDRESS,
644 Address.IFA_LOCAL,
645 Address.IFA_BROADCAST,
646 Address.IFA_ANYCAST,
647 Address.IFA_MULTICAST
648 ]
649
650 def addr_dump(self, ifname=None):
651 if ifname:
652 self.logger.info('netlink: ip addr show dev %s' % ifname)
653 else:
654 self.logger.info('netlink: ip addr show')
655
656 ifaces = dict()
657 addr_dump = self._nlmanager_api.addr_dump()
658
659 for addr_packet in addr_dump:
660 addr_ifname = self._addr_dump_extract_ifname(addr_packet)
661
662 if addr_packet.family not in [socket.AF_INET, socket.AF_INET6]:
663 continue
664
665 if ifname and ifname != addr_ifname:
666 continue
667
668 if addr_ifname not in ifaces:
669 ifaces[addr_ifname] = {'addrs': OrderedDict({})}
670
671 for ifa_attr in self.ifa_address_attributes:
672 self._addr_dump_entry(ifaces, addr_packet, addr_ifname, ifa_attr)
673
674 if ifname:
675 return {ifname: ifaces.get(ifname, {})}
676
677 return ifaces
678
679
680netlink = Netlink()