]> git.proxmox.com Git - mirror_ifupdown2.git/blame - ifupdown2/nlmanager/nllistener.py
bridge: vlan-aware: add new boolean policy "vlan_aware_bridge_address_support"
[mirror_ifupdown2.git] / ifupdown2 / nlmanager / nllistener.py
CommitLineData
198ded6a 1#!/usr/bin/env python
d486dd0d
JF
2#
3# Copyright (C) 2015, 2017 Cumulus Networks, Inc. all rights reserved
4#
5# This program is free software; you can redistribute it and/or
6# modify it under the terms of the GNU General Public License as
7# published by the Free Software Foundation; version 2.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12# General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with this program; if not, write to the Free Software
16# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17# 02110-1301, USA.
18#
19# https://www.gnu.org/licenses/gpl-2.0-standalone.html
20#
21# Authors:
22# Daniel Walton, dwalton@cumulusnetworks.com
23# Julien Fortin, julien@cumulusnetworks.com
24#
25# Netlink Listener --
26#
198ded6a
JF
27
28from nlpacket import *
29from nlmanager import NetlinkManager
30from select import select
31from struct import pack, unpack, calcsize
32from threading import Thread, Event, Lock
33from Queue import Queue
34import logging
35import socket
d486dd0d 36import errno
198ded6a
JF
37
38log = logging.getLogger(__name__)
39
40
41class NetlinkListener(Thread):
42
d486dd0d 43 def __init__(self, manager, groups, pid_offset=1, error_notification=False, rcvbuf_sz=10000000):
198ded6a
JF
44 """
45 groups controls what types of messages we are interested in hearing
46 To get everything pass:
47 RTMGRP_LINK | \
48 RTMGRP_IPV4_IFADDR | \
49 RTMGRP_IPV4_ROUTE | \
50 RTMGRP_IPV6_IFADDR | \
51 RTMGRP_IPV6_ROUTE
52 """
53 Thread.__init__(self)
54 self.manager = manager
55 self.shutdown_event = Event()
56 self.groups = groups
9f25ff0d 57 self.pid_offset = pid_offset
d486dd0d
JF
58 self.rcvbuf_sz = rcvbuf_sz
59
60 # if the app has requested for error notification socket errors will
61 # be sent via the SERVICE_ERROR event
62 self.error_notification = error_notification
63
64 self.supported_messages = [RTM_NEWLINK, RTM_DELLINK, RTM_NEWADDR,
65 RTM_DELADDR, RTM_NEWNEIGH, RTM_DELNEIGH,
66 RTM_NEWROUTE, RTM_DELROUTE]
67 self.ignore_messages = [RTM_GETLINK, RTM_GETADDR, RTM_GETNEIGH,
68 RTM_GETROUTE, RTM_GETQDISC, NLMSG_ERROR, NLMSG_DONE]
198ded6a
JF
69
70 def __str__(self):
71 return 'NetlinkListener'
72
d486dd0d
JF
73 def supported_messages_add(self, msgtype):
74
75 if msgtype not in self.supported_messages:
76 self.supported_messages.append(msgtype)
77
78 if msgtype in self.ignore_messages:
79 self.ignore_messages.remove(msgtype)
80
81 def supported_messages_del(self, msgtype):
82
83 if msgtype in self.supported_messages:
84 self.supported_messages.remove(msgtype)
85
86 if msgtype not in self.ignore_messages:
87 self.ignore_messages.append(msgtype)
88
198ded6a
JF
89 def run(self):
90 manager = self.manager
91 header_PACK = 'IHHII'
92 header_LEN = calcsize(header_PACK)
93
94 # The RX socket is used to listen to all netlink messages that fly by
95 # as things change in the kernel. We need a very large SO_RCVBUF here
96 # else we tend to miss messages.
9f25ff0d
SE
97 # PID_MAX_LIMIT is 2^22 allowing 1024 sockets per-pid. We default to
98 # use 2 in the upper space (top 10 bits) instead of 0 to avoid conflicts
99 # with the netlink manager which always attempts to bind with the pid.
198ded6a 100 self.rx_socket = socket.socket(socket.AF_NETLINK, socket.SOCK_RAW, 0)
d486dd0d
JF
101 _SO_RCVBUFFORCE = socket.SO_RCVBUFFORCE if hasattr(socket, 'SO_RCVBUFFORCE') else 33
102 self.rx_socket.setsockopt(socket.SOL_SOCKET, _SO_RCVBUFFORCE, self.rcvbuf_sz)
9f25ff0d 103 self.rx_socket.bind((manager.pid | (self.pid_offset << 22), self.groups))
198ded6a
JF
104 self.rx_socket_prev_seq = {}
105
d486dd0d 106 manager.target_lock.acquire()
198ded6a
JF
107 if not manager.tx_socket:
108 manager.tx_socket_allocate()
d486dd0d 109 manager.target_lock.release()
198ded6a
JF
110
111 my_sockets = (manager.tx_socket, self.rx_socket)
112
113 socket_string = {
114 manager.tx_socket: "TX",
115 self.rx_socket: "RX"
116 }
117
198ded6a
JF
118 while True:
119
120 if self.shutdown_event.is_set():
121 log.info("%s: shutting down" % self)
d486dd0d 122 break
198ded6a 123
d3d4f288 124 # Only block for 1 second so we can wake up to see if shutdown_event is set
198ded6a
JF
125 try:
126 (readable, writeable, exceptional) = select(my_sockets, [], my_sockets, 1)
127 except Exception as e:
128 log.error('select() error: ' + str(e))
129 continue
130
131 if not readable:
132 continue
133
134 set_alarm = False
d486dd0d 135 set_overrun = False
198ded6a 136 set_tx_socket_rxed_ack_alarm = False
198ded6a
JF
137
138 for s in readable:
d3d4f288 139 data = []
198ded6a
JF
140
141 try:
142 data = s.recv(4096)
d486dd0d
JF
143 except socket.error, e:
144 log.error('recv() error: ' + str(e))
145 data = []
146 if e.errno is errno.ENOBUFS and self.error_notification:
147 set_overrun = True
198ded6a
JF
148 except Exception as e:
149 log.error('recv() error: ' + str(e))
d486dd0d 150 data = []
198ded6a
JF
151
152 total_length = len(data)
153 while data:
154
155 # Extract the length, etc from the header
156 (length, msgtype, flags, seq, pid) = unpack(header_PACK, data[:header_LEN])
157
ddafc33d
JF
158 log.debug('%s %s: RXed %s seq %d, pid %d, %d bytes (%d total)' %
159 (self, socket_string[s], NetlinkPacket.type_to_string[msgtype],
160 seq, pid, length, total_length))
161 possible_ack = False
162
163 if msgtype == NLMSG_DONE:
164 possible_ack = True
165
166 elif msgtype == NLMSG_ERROR:
167 possible_ack = True
198ded6a 168
d3d4f288
JF
169 # The error code is a signed negative number.
170 error_code = abs(unpack('=i', data[header_LEN:header_LEN+4])[0])
171 msg = Error(msgtype, True)
172 msg.decode_packet(length, flags, seq, pid, data)
198ded6a
JF
173
174 if error_code:
d3d4f288 175 log.debug("%s %s: RXed NLMSG_ERROR code %s (%d)" % (self, socket_string[s], msg.error_to_string.get(error_code), error_code))
198ded6a 176
ddafc33d
JF
177 if possible_ack and seq == manager.target_seq and pid == manager.target_pid:
178 log.debug("%s %s: Setting RXed ACK alarm for seq %d, pid %d" %
179 (self, socket_string[s], seq, pid))
198ded6a
JF
180 set_tx_socket_rxed_ack_alarm = True
181
182 # Put the message on the manager's netlinkq
d486dd0d 183 if msgtype in self.supported_messages:
198ded6a
JF
184 set_alarm = True
185 manager.netlinkq.append((msgtype, length, flags, seq, pid, data[0:length]))
186
187 # There are certain message types we do not care about
188 # (RTM_GETs for example)
d486dd0d 189 elif msgtype in self.ignore_messages:
198ded6a
JF
190 pass
191
192 # And there are certain message types we have not added
193 # support for yet (QDISC). Log an error for these just
194 # as a reminder to add support for them.
195 else:
196 if msgtype in NetlinkPacket.type_to_string:
d3d4f288
JF
197 log.warning('%s %s: RXed unsupported message %s (type %d)' %
198 (self, socket_string[s], NetlinkPacket.type_to_string[msgtype], msgtype))
198ded6a 199 else:
d3d4f288
JF
200 log.warning('%s %s: RXed unknown message type %d' %
201 (self, socket_string[s], msgtype))
198ded6a
JF
202
203 # Track the previous PID sequence number for RX and TX sockets
204 if s == self.rx_socket:
205 prev_seq = self.rx_socket_prev_seq
206 elif s == manager.tx_socket:
207 prev_seq = manager.tx_socket_prev_seq
208
209 if pid in prev_seq and prev_seq[pid] and prev_seq[pid] != seq and (prev_seq[pid]+1 != seq):
d3d4f288 210 log.debug('%s %s: went from seq %d to %d' % (self, socket_string[s], prev_seq[pid], seq))
198ded6a
JF
211 prev_seq[pid] = seq
212
213 data = data[length:]
214
215 if set_tx_socket_rxed_ack_alarm:
216 manager.target_lock.acquire()
217 manager.target_seq = None
218 manager.target_pid = None
219 manager.target_lock.release()
220 manager.tx_socket_rxed_ack.set()
221
222 if set_alarm:
223 manager.workq.put(('SERVICE_NETLINK_QUEUE', None))
d486dd0d
JF
224
225 if set_overrun:
226 manager.workq.put(('SERVICE_ERROR', "OVERFLOW"))
227
228 if set_alarm or set_overrun:
198ded6a
JF
229 manager.alarm.set()
230
231 self.rx_socket.close()
232
233
234class NetlinkManagerWithListener(NetlinkManager):
235
d486dd0d
JF
236 def __init__(self, groups, start_listener=True, use_color=True, pid_offset=0, error_notification=False, rcvbuf_sz=10000000):
237 NetlinkManager.__init__(self, use_color=use_color, pid_offset=pid_offset)
198ded6a
JF
238 self.groups = groups
239 self.workq = Queue()
240 self.netlinkq = []
241 self.alarm = Event()
242 self.shutdown_event = Event()
243 self.tx_socket_rxed_ack = Event()
244 self.tx_socket_rxed_ack.clear()
245 self.target_seq = None
246 self.target_pid = None
247 self.target_seq_pid_debug = False
248 self.target_lock = Lock()
249 self.tx_socket_prev_seq = {}
250 self.debug_listener = False
251 self.debug_seq_pid = {}
252 self.ifname_by_index = {}
253 self.blacklist_filter = {}
254 self.whitelist_filter = {}
d486dd0d
JF
255 self.rcvbuf_sz = rcvbuf_sz
256 self.error_notification = error_notification
257 self.pid_offset = pid_offset
198ded6a
JF
258
259 # Listen to netlink messages
260 if start_listener:
d486dd0d 261 self.restart_listener()
198ded6a
JF
262 else:
263 self.listener = None
264
265 def __str__(self):
266 return 'NetlinkManagerWithListener'
267
d486dd0d
JF
268 def restart_listener(self):
269 self.listener = NetlinkListener(self, self.groups, self.pid_offset+1, self.error_notification, self.rcvbuf_sz)
270 self.listener.start()
271
198ded6a
JF
272 def signal_term_handler(self, signal, frame):
273 log.info("NetlinkManagerWithListener: Caught SIGTERM")
d3d4f288
JF
274
275 if self.listener:
276 self.listener.shutdown_event.set()
277
198ded6a
JF
278 self.shutdown_flag = True # For NetlinkManager shutdown
279 self.shutdown_event.set()
280 self.alarm.set()
281
282 def signal_int_handler(self, signal, frame):
283 log.info("NetlinkManagerWithListener: Caught SIGINT")
d3d4f288
JF
284
285 if self.listener:
286 self.listener.shutdown_event.set()
287
198ded6a
JF
288 self.shutdown_flag = True # For NetlinkManager shutdown
289 self.shutdown_event.set()
290 self.alarm.set()
291
d3d4f288 292 def tx_nlpacket_get_response(self, nlpacket):
198ded6a
JF
293 """
294 TX the message and wait for an ack
295 """
296
297 # NetlinkListener looks at the manager's target_seq and target_pid
298 # to know when we've RXed the ack that we want
299 self.target_lock.acquire()
300 self.target_seq = nlpacket.seq
301 self.target_pid = nlpacket.pid
198ded6a
JF
302
303 if not self.tx_socket:
304 self.tx_socket_allocate()
d486dd0d 305 self.target_lock.release()
ddafc33d
JF
306
307 log.debug('%s TX: TXed %s seq %d, pid %d, %d bytes' %
308 (self, NetlinkPacket.type_to_string[nlpacket.msgtype],
309 nlpacket.seq, nlpacket.pid, nlpacket.length))
310
198ded6a
JF
311 self.tx_socket.sendall(nlpacket.message)
312
313 # Wait for NetlinkListener to RX an ACK or DONE for this (seq, pid)
314 self.tx_socket_rxed_ack.wait()
315 self.tx_socket_rxed_ack.clear()
316
317 # These are here to show some basic examples of how one might react to RXing
318 # various netlink message types. Odds are our child class will redefine these
319 # to do more than log a message.
320 def rx_rtm_newlink(self, msg):
d3d4f288
JF
321 log.debug("RXed RTM_NEWLINK seq %d, pid %d, %d bytes, for %s, state %s" %
322 (msg.seq, msg.pid, msg.length, msg.get_attribute_value(msg.IFLA_IFNAME), "up" if msg.is_up() else "down"))
198ded6a
JF
323
324 def rx_rtm_dellink(self, msg):
d3d4f288
JF
325 log.debug("RXed RTM_DELLINK seq %d, pid %d, %d bytes, for %s, state %s" %
326 (msg.seq, msg.pid, msg.length, msg.get_attribute_value(msg.IFLA_IFNAME), "up" if msg.is_up() else "down"))
198ded6a
JF
327
328 def rx_rtm_newaddr(self, msg):
d3d4f288
JF
329 log.debug("RXed RTM_NEWADDR seq %d, pid %d, %d bytes, for %s/%d on %s" %
330 (msg.seq, msg.pid, msg.length, msg.get_attribute_value(msg.IFA_ADDRESS), msg.prefixlen, self.ifname_by_index.get(msg.ifindex)))
198ded6a
JF
331
332 def rx_rtm_deladdr(self, msg):
d3d4f288
JF
333 log.debug("RXed RTM_DELADDR seq %d, pid %d, %d bytes, for %s/%d on %s" %
334 (msg.seq, msg.pid, msg.length, msg.get_attribute_value(msg.IFA_ADDRESS), msg.prefixlen, self.ifname_by_index.get(msg.ifindex)))
198ded6a
JF
335
336 def rx_rtm_newneigh(self, msg):
d3d4f288
JF
337 log.debug("RXed RTM_NEWNEIGH seq %d, pid %d, %d bytes, for %s on %s" %
338 (msg.seq, msg.pid, msg.length, msg.get_attribute_value(msg.NDA_DST), self.ifname_by_index.get(msg.ifindex)))
198ded6a
JF
339
340 def rx_rtm_delneigh(self, msg):
d3d4f288
JF
341 log.debug("RXed RTM_DELNEIGH seq %d, pid %d, %d bytes, for %s on %s" %
342 (msg.seq, msg.pid, msg.length, msg.get_attribute_value(msg.NDA_DST), self.ifname_by_index.get(msg.ifindex)))
198ded6a
JF
343
344 def rx_rtm_newroute(self, msg):
d3d4f288
JF
345 log.debug("RXed RTM_NEWROUTE seq %d, pid %d, %d bytes, for %s%s" %
346 (msg.seq, msg.pid, msg.length, msg.get_prefix_string(), msg.get_nexthops_string(self.ifname_by_index)))
198ded6a
JF
347
348 def rx_rtm_delroute(self, msg):
d3d4f288
JF
349 log.debug("RXed RTM_DELROUTE seq %d, pid %d, %d bytes, for %s%s" %
350 (msg.seq, msg.pid, msg.length, msg.get_prefix_string(), msg.get_nexthops_string(self.ifname_by_index)))
198ded6a 351
d486dd0d
JF
352 def rx_nlmsg_done(self, msg):
353 log.debug("RXed NLMSG_DONE seq %d, pid %d, %d bytes" % (msg.seq, msg.pid, msg.length))
354
d3d4f288 355 # Note that tx_nlpacket_get_response will block until NetlinkListener has RXed
198ded6a
JF
356 # an Ack/DONE for the message we TXed
357 def get_all_addresses(self):
358 family = socket.AF_UNSPEC
359 debug = RTM_GETADDR in self.debug
360
a61d1777 361 addr = Address(RTM_GETADDR, debug, use_color=self.use_color)
198ded6a
JF
362 addr.flags = NLM_F_REQUEST | NLM_F_DUMP
363 addr.body = pack('Bxxxi', family, 0)
364 addr.build_message(self.sequence.next(), self.pid)
365
366 if debug:
367 self.debug_seq_pid[(addr.seq, addr.pid)] = True
368
d3d4f288 369 self.tx_nlpacket_get_response(addr)
198ded6a
JF
370
371 def get_all_links(self):
372 family = socket.AF_UNSPEC
373 debug = RTM_GETLINK in self.debug
374
a61d1777 375 link = Link(RTM_GETLINK, debug, use_color=self.use_color)
198ded6a
JF
376 link.flags = NLM_F_REQUEST | NLM_F_DUMP
377 link.body = pack('Bxxxiii', family, 0, 0, 0)
378 link.build_message(self.sequence.next(), self.pid)
379
380 if debug:
381 self.debug_seq_pid[(link.seq, link.pid)] = True
382
d3d4f288 383 self.tx_nlpacket_get_response(link)
198ded6a 384
d486dd0d
JF
385 def get_all_br_links(self, compress_vlans=True):
386 family = socket.AF_BRIDGE
387 debug = RTM_GETLINK in self.debug
388
389 link = Link(RTM_GETLINK, debug, use_color=self.use_color)
390 link.flags = NLM_F_REQUEST | NLM_F_DUMP
391 link.body = pack('Bxxxiii', family, 0, 0, 0)
392 if compress_vlans:
393 link.add_attribute(Link.IFLA_EXT_MASK, Link.RTEXT_FILTER_BRVLAN_COMPRESSED)
394 else:
395 link.add_attribute(Link.IFLA_EXT_MASK, Link.RTEXT_FILTER_BRVLAN)
396 link.build_message(self.sequence.next(), self.pid)
397
398 if debug:
399 self.debug_seq_pid[(link.seq, link.pid)] = True
400
401 self.tx_nlpacket_get_response(link)
402
198ded6a
JF
403 def get_all_neighbors(self):
404 family = socket.AF_UNSPEC
405 debug = RTM_GETNEIGH in self.debug
406
a61d1777 407 neighbor = Neighbor(RTM_GETNEIGH, debug, use_color=self.use_color)
198ded6a
JF
408 neighbor.flags = NLM_F_REQUEST | NLM_F_DUMP
409 neighbor.body = pack('Bxxxii', family, 0, 0)
410 neighbor.build_message(self.sequence.next(), self.pid)
411
412 if debug:
413 self.debug_seq_pid[(neighbor.seq, neighbor.pid)] = True
414
d3d4f288 415 self.tx_nlpacket_get_response(neighbor)
198ded6a
JF
416
417 def get_all_routes(self):
418 family = socket.AF_UNSPEC
419 debug = RTM_GETROUTE in self.debug
420
a61d1777 421 route = Route(RTM_GETROUTE, debug, use_color=self.use_color)
198ded6a
JF
422 route.flags = NLM_F_REQUEST | NLM_F_DUMP
423 route.body = pack('Bxxxii', family, 0, 0)
424 route.build_message(self.sequence.next(), self.pid)
425
426 if debug:
427 self.debug_seq_pid[(route.seq, route.pid)] = True
428
d3d4f288 429 self.tx_nlpacket_get_response(route)
198ded6a
JF
430
431 def nested_attributes_match(self, msg, attr_filter):
432 """
433 attr_filter will be a dictionary such as:
434 attr_filter = {
435 Link.IFLA_LINKINFO: {
436 Link.IFLA_INFO_KIND: 'vlan'
437 }
438 }
439 """
440 for (key, value) in attr_filter.items():
441 if type(value) is dict:
442 if not self.nested_attributes_match(msg, value):
443 return False
444 else:
445 attr_value = msg.get_attribute_value(key)
446 if attr_value != value:
447 return False
448 return True
449
450 def filter_rule_matches(self, msg, rule):
451 field = rule[0]
452 options = rule[1:]
453
454 if field == 'IFINDEX':
455 ifindex = options[0]
456
457 if msg.ifindex == ifindex:
458 return True
459
460 elif field == 'ATTRIBUTE':
461 (attr_type, target_value) = options[0:2]
462 attr_value = msg.get_attribute_value(attr_type)
463
464 if attr_value == target_value:
465 return True
466
467 elif field == 'NESTED_ATTRIBUTE':
468 if self.nested_attributes_match(msg, options[0]):
469 return True
470
471 elif field == 'FAMILY':
472 family = options[0]
473
474 if msg.family == family:
475 return True
476 else:
477 raise Exception("Add support to filter based on %s" % field)
478
479 return False
480
481 def filter_permit(self, msg):
482 """
483 Return True if our whitelist/blacklist filters permit this netlink msg
484 """
485 if msg.msgtype in self.whitelist_filter:
486 found_it = False
487
488 for rule in self.whitelist_filter[msg.msgtype]:
489 if self.filter_rule_matches(msg, rule):
490 found_it = True
491 break
492
493 return found_it
494
495 elif msg.msgtype in self.blacklist_filter:
496 for rule in self.blacklist_filter[msg.msgtype]:
497 if self.filter_rule_matches(msg, rule):
498 return False
499 return True
500
501 else:
502 return True
503
504 def _filter_update(self, add, filter_type, msgtype, filter_guts):
505 assert filter_type in ('whitelist', 'blacklist'), "whitelist and blacklist are the only supported filter options"
506
507 if add:
508 if filter_type == 'whitelist':
509
510 # Keep things simple, do not allow both whitelist and blacklist
511 if self.blacklist_filter and self.blacklist_filter.get(msgtype):
512 raise Exception("whitelist and blacklist filters cannot be used at the same time")
513
514 if msgtype not in self.whitelist_filter:
515 self.whitelist_filter[msgtype] = []
516 self.whitelist_filter[msgtype].append(filter_guts)
517
518 elif filter_type == 'blacklist':
519
520 # Keep things simple, do not allow both whitelist and blacklist
521 if self.whitelist_filter and self.whitelist_filter.get(msgtype):
522 raise Exception("whitelist and blacklist filters cannot be used at the same time")
523
524 if msgtype not in self.blacklist_filter:
525 self.blacklist_filter[msgtype] = []
526 self.blacklist_filter[msgtype].append(filter_guts)
527
528 else:
529 if filter_type == 'whitelist':
530 if msgtype in self.whitelist_filter:
531 self.whitelist_filter[msgtype].remove(filter_guts)
532
533 if not self.whitelist_filter[msgtype]:
534 del self.whitelist_filter[msgtype]
535
536 elif filter_type == 'blacklist':
537 if msgtype in self.blacklist_filter:
538 self.blacklist_filter[msgtype].remove(filter_guts)
539
540 if not self.blacklist_filter[msgtype]:
541 del self.blacklist_filter[msgtype]
542
543 def filter_by_address_family(self, add, filter_type, msgtype, family):
544 self._filter_update(add, filter_type, msgtype, ('FAMILY', family))
545
546 def filter_by_ifindex(self, add, filter_type, msgtype, ifindex):
547 self._filter_update(add, filter_type, msgtype, ('IFINDEX', ifindex))
548
549 def filter_by_attribute(self, add, filter_type, msgtype, attribute, attribute_value):
550 self._filter_update(add, filter_type, msgtype, ('ATTRIBUTE', attribute, attribute_value))
551
552 def filter_by_nested_attribute(self, add, filter_type, msgtype, attr_filter):
553 self._filter_update(add, filter_type, msgtype, ('NESTED_ATTRIBUTE', attr_filter))
554
555 def service_netlinkq(self):
556 msg_count = {}
557 processed = 0
558
559 for (msgtype, length, flags, seq, pid, data) in self.netlinkq:
560 processed += 1
561
562 # If this is a reply to a TX message that debugs were enabled for then debug the reply
563 if (seq, pid) in self.debug_seq_pid:
564 debug = True
565 else:
566 debug = self.debug_this_packet(msgtype)
567
568 if msgtype == RTM_NEWLINK or msgtype == RTM_DELLINK:
a61d1777 569 msg = Link(msgtype, debug, use_color=self.use_color)
198ded6a
JF
570
571 elif msgtype == RTM_NEWADDR or msgtype == RTM_DELADDR:
a61d1777 572 msg = Address(msgtype, debug, use_color=self.use_color)
198ded6a
JF
573
574 elif msgtype == RTM_NEWNEIGH or msgtype == RTM_DELNEIGH:
a61d1777 575 msg = Neighbor(msgtype, debug, use_color=self.use_color)
198ded6a
JF
576
577 elif msgtype == RTM_NEWROUTE or msgtype == RTM_DELROUTE:
a61d1777 578 msg = Route(msgtype, debug, use_color=self.use_color)
198ded6a 579
d486dd0d
JF
580 elif msgtype == NLMSG_DONE:
581 msg = Done(msgtype, debug, use_color=self.use_color)
582
198ded6a
JF
583 else:
584 log.warning('RXed unknown netlink message type %s' % msgtype)
585 continue
586
587 msg.decode_packet(length, flags, seq, pid, data)
588
589 if not self.filter_permit(msg):
590 continue
591
592 if debug:
593 msg.dump()
594
595 # Only used for printing debugs about how many we RXed of each type
596 if msg.msgtype not in msg_count:
597 msg_count[msg.msgtype] = 0
598 msg_count[msg.msgtype] += 1
599
600 # Call the appropriate handler method based on the msgtype. The handler
601 # functions are defined in our child class.
602 if msg.msgtype == RTM_NEWLINK:
603
604 # We will use ifname_by_index to display the interface name in debug output
605 self.ifname_by_index[msg.ifindex] = msg.get_attribute_value(msg.IFLA_IFNAME)
606 self.rx_rtm_newlink(msg)
607
608 elif msg.msgtype == RTM_DELLINK:
609
610 # We will use ifname_by_index to display the interface name in debug output
611 if msg.ifindex in self.ifname_by_index:
612 del self.ifname_by_index[msg.ifindex]
613 self.rx_rtm_dellink(msg)
614
615 elif msg.msgtype == RTM_NEWADDR:
616 self.rx_rtm_newaddr(msg)
617
618 elif msg.msgtype == RTM_DELADDR:
619 self.rx_rtm_deladdr(msg)
620
621 elif msg.msgtype == RTM_NEWNEIGH:
622 self.rx_rtm_newneigh(msg)
623
624 elif msg.msgtype == RTM_DELNEIGH:
625 self.rx_rtm_delneigh(msg)
626
627 elif msg.msgtype == RTM_NEWROUTE:
628 self.rx_rtm_newroute(msg)
629
630 elif msg.msgtype == RTM_DELROUTE:
631 self.rx_rtm_delroute(msg)
632
d486dd0d
JF
633 elif msg.msgtype == NLMSG_DONE:
634 self.rx_nlmsg_done(msg)
635
198ded6a
JF
636 else:
637 log.warning('RXed unknown netlink message type %s' % msgtype)
638
639 if processed:
640 self.netlinkq = self.netlinkq[processed:]
641
642 # too chatty
643 # for msgtype in msg_count:
644 # log.debug('RXed %d %s messages' % (msg_count[msgtype], NetlinkPacket.type_to_string[msgtype]))