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