]> git.proxmox.com Git - mirror_ifupdown2.git/blob - ifupdown/rtnetlink.py
Change "source" inclusion errors to warns.
[mirror_ifupdown2.git] / ifupdown / rtnetlink.py
1 #!/usr/bin/env python
2 #
3 # Copyright 2014 Cumulus Networks, Inc. All rights reserved.
4 #
5 # Author: Scott Feldman, sfeldma@cumulusnetworks.com
6 # Author: Roopa Prabhu, roopa@cumulusnetworks.com
7 #
8 #
9 from socket import NETLINK_ROUTE, AF_INET, AF_INET6
10 from string import printable
11 from ipaddr import *
12 from ctypes import *
13 from netlink import *
14 import logging
15
16 logger = logging.getLogger(__name__)
17
18 #
19 # from /usr/include/linux/rtnetlink.h
20 #
21
22 RTMGRP_LINK = 0x1
23 RTMGRP_IPV4_IFADDR = 0x10
24 RTMGRP_IPV4_ROUTE = 0x40
25 RTMGRP_IPV6_IFADDR = 0x100
26 RTMGRP_IPV6_ROUTE = 0x400
27
28 RTM_NEWLINK = 16
29 RTM_DELLINK = 17
30 RTM_GETLINK = 18
31 RTM_NEWADDR = 20
32 RTM_DELADDR = 21
33 RTM_GETADDR = 22
34 RTM_NEWROUTE = 24
35 RTM_DELROUTE = 25
36 RTM_GETROUTE = 26
37
38 # Definitions used in routing table administration.
39
40 class Nlmsg(Structure):
41
42 def _stringify(self):
43 return string_at(addressof(self), sizeof(self))
44
45 def __eq__(self, other):
46 return self._stringify() == other._stringify() and \
47 self.__dict__ == other.__dict__
48
49 def to_rta(self):
50 return Rtattr.from_address(addressof(self) + NLMSG_ALIGN(sizeof(self)))
51
52 def pack_extra(self, extra, addr):
53 memmove(addr, addressof(extra), sizeof(extra))
54 return NLMSG_ALIGN(sizeof(extra))
55
56 def pack_rtas(self, rtas, addr):
57 total_len = 0
58 for rta_type, value in rtas.iteritems():
59 rta = Rtattr.from_address(addr)
60 rta.rta_type = rta_type
61 pack_fn = self.rta_fn(rta_type)
62 rta_len = NLMSG_ALIGN(pack_fn(rta, value))
63 total_len += rta_len
64 addr += rta_len
65 return total_len
66
67 def pack_rtas_new(self, rtas, addr, policy):
68 total_len = 0
69
70 for rta_type, value in rtas.iteritems():
71 if type(value) == dict:
72 rta = Rtattr.from_address(addr)
73 rta.rta_type = rta_type
74 rta.rta_len = RTA_LENGTH(0)
75 rta_len = NLMSG_ALIGN(rta.rta_len)
76 total_len += rta_len
77 addr += rta_len
78 pack_fn = policy.get(rta_type)
79 rta_len = NLMSG_ALIGN(pack_fn(addr, value))
80
81 rta.rta_len += rta_len
82 else:
83 rta = Rtattr.from_address(addr)
84 rta.rta_type = rta_type
85 pack_fn = policy.get(rta_type)
86 rta_len = NLMSG_ALIGN(pack_fn(rta, value))
87 total_len += rta_len
88 addr += rta_len
89 return total_len
90
91 def rta_linkinfo(self, addr, rtas):
92 total_len = 0
93
94 # Start nested linkinfo
95 #rta = Rtattr.from_address(addr)
96 #rta.rta_type = IFLA_LINKINFO
97 #rta.rta_len = RTA_LENGTH(0)
98 #rta_len = NLMSG_ALIGN(rta.rta_len)
99 #total_len += rta_len
100 #addr += rta_len
101 #nest_start_linkinfo = rta
102
103 # Check interface kind
104 kind = rtas.get(IFLA_INFO_KIND)
105 if kind == 'vlan':
106 data_policy = self.rta_linkinfo_data_vlan_policy()
107 else:
108 data_policy = self.rta_linkinfo_data_macvlan_policy()
109
110 # Pack info kind
111 rta = Rtattr.from_address(addr)
112 rta.rta_type = IFLA_INFO_KIND
113 rta_len = NLMSG_ALIGN(self.rta_string(rta, kind))
114 total_len += rta_len
115 addr += rta_len
116
117 # nest start link info data
118 rta = Rtattr.from_address(addr)
119 rta.rta_type = IFLA_INFO_DATA
120 rta.rta_len = RTA_LENGTH(0)
121 rta_len = NLMSG_ALIGN(rta.rta_len)
122 total_len += rta_len
123 addr += rta_len
124 rta_len = self.pack_rtas_new(rtas.get(IFLA_INFO_DATA), addr,
125 data_policy)
126 rta.rta_len += rta_len
127
128 total_len += rta_len
129 addr += rta_len
130
131 return total_len
132
133 def rta_linkinfo_data_vlan(self, addr, rtas):
134 return self.pack_rtas_new(rtas, addr, self.rta_linkinfo_data_vlan_policy())
135
136 def rta_linkinfo_data(self, addr, rtas):
137 return self.pack_rtas_new(rtas, addr, self.rta_linkinfo_data_vlan_policy())
138
139 def unpack_rtas(self, which_ones=[]):
140 len = self.nlh.nlmsg_len - NLMSG_LENGTH(sizeof(self))
141 rta = self.to_rta()
142 rtas = {}
143 while RTA_OK(rta, len):
144 rta_type = rta.rta_type
145 if not which_ones or rta_type in which_ones:
146 unpack_fn = self.rta_fn(rta_type)
147 rtas[rta_type] = unpack_fn(rta)
148 len, rta = RTA_NEXT(rta, len)
149 return rtas
150
151 def dump_rtas(self):
152 rtas = self.unpack_rtas()
153 for type, value in rtas.iteritems():
154 print "rta", type, ":", value
155
156 class _IPv6Addr(BigEndianStructure):
157 _fields_ = [
158 ('upper', c_uint64),
159 ('lower', c_uint64),
160 ]
161
162 class _IPv4Addr(BigEndianStructure):
163 _fields_ = [
164 ('addr', c_uint32),
165 ]
166
167 def rta_uint8(self, rta, value=None):
168 data = RTA_DATA(rta)
169 if value:
170 c_uint8.from_address(data).value = value
171 rta.rta_len = RTA_LENGTH(sizeof(c_uint8))
172 return rta.rta_len
173 else:
174 return c_uint8.from_address(data).value
175
176 def rta_uint16(self, rta, value=None):
177 data = RTA_DATA(rta)
178 if value:
179 c_uint16.from_address(data).value = value
180 rta.rta_len = RTA_LENGTH(sizeof(c_uint16))
181 return rta.rta_len
182 else:
183 return c_uint16.from_address(data).value
184
185 def rta_uint32(self, rta, value=None):
186 data = RTA_DATA(rta)
187 if value:
188 c_uint32.from_address(data).value = value
189 rta.rta_len = RTA_LENGTH(sizeof(c_uint32))
190 return rta.rta_len
191 else:
192 return c_uint32.from_address(data).value
193
194 def rta_string(self, rta, value=None):
195 data = RTA_DATA(rta)
196 if value:
197 s = create_string_buffer(value)
198 memmove(data, addressof(s), len(value))
199 rta.rta_len = RTA_LENGTH(len(value))
200 return rta.rta_len
201 else:
202 return c_char_p(data).value
203
204 def rta_addr(self, rta, value=None):
205 data = RTA_DATA(rta)
206 if value:
207 if isinstance(value, IPv4Address):
208 self._IPv4Addr.from_address(data).addr = value._ip
209 rta.rta_len = RTA_LENGTH(sizeof(self._IPv4Addr))
210 elif isinstance(value, IPv6Address):
211 addr = self._IPv6Addr.from_address(data)
212 addr.upper = value._ip >> 64
213 addr.lower = value._ip & 0xffffffffffffffff
214 rta.rta_len = RTA_LENGTH(sizeof(self._IPv6Addr))
215 else:
216 assert(False)
217 return rta.rta_len
218 else:
219 if RTA_PAYLOAD(rta) == 4:
220 addr = c_uint32.__ctype_be__.from_address(data).value
221 addr = IPv4Address(addr)
222 else:
223 addr = self._IPv6Addr.from_address(data)
224 addr = IPv6Address((addr.upper << 64) + addr.lower)
225 return addr
226
227 def rta_uint8_array(self, rta, value=None):
228 if value:
229 assert(False)
230 else:
231 data = RTA_DATA(rta)
232 array = (c_uint8 * RTA_PAYLOAD(rta))()
233 memmove(array, data, RTA_PAYLOAD(rta))
234 return array
235
236 def rta_uint32_array(self, rta, value=None):
237 if value:
238 assert(False)
239 else:
240 data = RTA_DATA(rta)
241 size = RTA_PAYLOAD(rta) / sizeof(c_uint32)
242 array = (c_uint32 * size)()
243 memmove(array, data, RTA_PAYLOAD(rta))
244 return array
245
246 def rta_multipath(self, rta, value=None):
247 # XXX implement this
248 return None
249
250 def rta_wtf(self, rta, value=None):
251 return None
252
253 def rta_none(self, rta, value=None):
254 return None
255
256 def rta_fn(self, rta_type):
257 return None
258
259
260 # rtm_type
261
262 RTN_UNSPEC = 0
263 RTN_UNICAST = 1 # Gateway or direct route
264 RTN_LOCAL = 2 # Accept locally
265 RTN_BROADCAST = 3 # Accept locally as broadcast,
266 # send as broadcast
267 RTN_ANYCAST = 4 # Accept locally as broadcast,
268 # but send as unicast
269 RTN_MULTICAST = 5 # Multicast route
270 RTN_BLACKHOLE = 6 # Drop
271 RTN_UNREACHABLE = 7 # Destination is unreachable
272 RTN_PROHIBIT = 8 # Administratively prohibited
273 RTN_THROW = 9 # Not in this table
274 RTN_NAT = 10 # Translate this address
275 RTN_XRESOLVE = 11 # Use external resolver
276 RTN_MAX = 11
277
278 # rtm_protocol
279
280 RTPROT_UNSPEC = 0
281 RTPROT_REDIRECT = 1 # Route installed by ICMP redirects;
282 # not used by current IPv4
283 RTPROT_KERNEL = 2 # Route installed by kernel
284 RTPROT_BOOT = 3 # Route installed during boot
285 RTPROT_STATIC = 4 # Route installed by administrator
286
287 # Values of protocol >= RTPROT_STATIC are not interpreted by kernel;
288 # they are just passed from user and back as is.
289 # It will be used by hypothetical multiple routing daemons.
290 # Note that protocol values should be standardized in order to
291 # avoid conflicts.
292
293 RTPROT_GATED = 8 # Apparently, GateD
294 RTPROT_RA = 9 # RDISC/ND router advertisements
295 RTPROT_MRT = 10 # Merit MRT
296 RTPROT_ZEBRA = 11 # Zebra
297 RTPROT_BIRD = 12 # BIRD
298 RTPROT_DNROUTED = 13 # DECnet routing daemon
299 RTPROT_XORP = 14 # XORP
300 RTPROT_NTK = 15 # Netsukuku
301 RTPROT_DHCP = 16 # DHCP client
302
303 # rtm_scope
304
305 # Really it is not scope, but sort of distance to the destination.
306 # NOWHERE are reserved for not existing destinations, HOST is our
307 # local addresses, LINK are destinations, located on directly attached
308 # link and UNIVERSE is everywhere in the Universe.
309
310 # Intermediate values are also possible f.e. interior routes
311 # could be assigned a value between UNIVERSE and LINK.
312
313 RT_SCOPE_UNIVERSE = 0
314 # User defined values
315 RT_SCOPE_SITE = 200
316 RT_SCOPE_LINK = 253
317 RT_SCOPE_HOST = 254
318 RT_SCOPE_NOWHERE=255
319
320 # rtm_flags
321
322 RTM_F_NOTIFY = 0x100 # Notify user of route change
323 RTM_F_CLONED = 0x200 # This route is cloned
324 RTM_F_EQUALIZE = 0x400 # Multipath equalizer: NI
325 RTM_F_PREFIX = 0x800 # Prefix addresses
326
327 # Reserved table identifiers
328
329 RT_TABLE_UNSPEC = 0
330 # User defined values
331 RT_TABLE_COMPAT = 252
332 RT_TABLE_DEFAULT = 253
333 RT_TABLE_MAIN = 254
334 RT_TABLE_LOCAL = 255
335 RT_TABLE_MAX = 0xFFFFFFFF
336
337 # Generic structure for encapsulation of optional route information.
338 # It is reminiscent of sockaddr, but with sa_family replaced
339 # with attribute type.
340
341 class Rtattr(Structure):
342
343 _fields_ = [
344 ('rta_len', c_uint16),
345 ('rta_type', c_uint16),
346 ]
347
348 # Routing message attributes
349
350 RTA_UNSPEC = 0
351 RTA_DST = 1
352 RTA_SRC = 2
353 RTA_IIF = 3
354 RTA_OIF = 4
355 RTA_GATEWAY = 5
356 RTA_PRIORITY = 6
357 RTA_PREFSRC = 7
358 RTA_METRICS = 8
359 RTA_MULTIPATH = 9
360 RTA_PROTOINFO = 10 # no longer used
361 RTA_FLOW = 11
362 RTA_CACHEINFO = 12
363 RTA_SESSION = 13 # no longer used
364 RTA_MP_ALGO = 14 # no longer used
365 RTA_TABLE = 15
366 RTA_MAX = 15
367
368 # Macros to handle rtattributes
369
370 RTA_ALIGNTO = 4
371 def RTA_ALIGN(len):
372 return (len + RTA_ALIGNTO - 1) & ~(RTA_ALIGNTO - 1)
373 def RTA_OK(rta, len):
374 return len >= sizeof(Rtattr) and \
375 rta.rta_len >= sizeof(Rtattr) and \
376 rta.rta_len <= len
377 def RTA_NEXT(rta, len):
378 cur = RTA_ALIGN(rta.rta_len)
379 rta = Rtattr.from_address(addressof(rta) + cur)
380 return len - cur, rta
381 def RTA_LENGTH(len):
382 return len + RTA_ALIGN(sizeof(Rtattr))
383 def RTA_SPACE(len):
384 return RTA_ALIGN(RTA_LENGTH(len))
385 def RTA_DATA(rta):
386 return addressof(rta) + RTA_LENGTH(0)
387 def RTA_PAYLOAD(rta):
388 return rta.rta_len - RTA_LENGTH(0)
389
390 RTNH_F_DEAD = 1 # Nexthop is dead (used by multipath)
391 RTNH_F_PERVASIVE = 2 # Do recursive gateway lookup
392 RTNH_F_ONLINK = 4 # Gateway is forced on link
393
394 # Reserved table identifiers
395
396 RT_TABLE_UNSPEC = 0
397 # User defined values
398 RT_TABLE_COMPAT = 252
399 RT_TABLE_DEFAULT = 253
400 RT_TABLE_MAIN = 254
401 RT_TABLE_LOCAL = 255
402 RT_TABLE_MAX = 0xFFFFFFFF
403
404 class Rtmsg(Nlmsg):
405
406 _fields_ = [
407 ('rtm_family', c_uint8),
408 ('rtm_dst_len', c_uint8),
409 ('rtm_src_len', c_uint8),
410 ('rtm_tos', c_uint8),
411 ('rtm_table', c_uint8),
412 ('rtm_protocol', c_uint8),
413 ('rtm_scope', c_uint8),
414 ('rtm_type', c_uint8),
415 ('rtm_flags', c_uint32),
416 ]
417
418 _table_str = {
419 RT_TABLE_UNSPEC: "unspecified",
420 RT_TABLE_COMPAT: "compat",
421 RT_TABLE_DEFAULT: "default",
422 RT_TABLE_MAIN: "main",
423 RT_TABLE_LOCAL: "local",
424 }
425
426 _proto_str = {
427 RTPROT_UNSPEC: "none",
428 RTPROT_REDIRECT: "redirect",
429 RTPROT_KERNEL: "kernel",
430 RTPROT_BOOT: "boot",
431 RTPROT_STATIC: "static",
432 RTPROT_GATED: "gated",
433 RTPROT_RA: "ra",
434 RTPROT_MRT: "mrtmrt",
435 RTPROT_ZEBRA: "zebra",
436 RTPROT_BIRD: "bird",
437 RTPROT_DNROUTED: "dnrouted",
438 RTPROT_XORP: "xorp",
439 RTPROT_NTK: "ntk",
440 RTPROT_DHCP: "dhcp",
441 }
442
443 _scope_str = {
444 RT_SCOPE_UNIVERSE: "universe",
445 RT_SCOPE_SITE: "site",
446 RT_SCOPE_LINK: "link",
447 RT_SCOPE_HOST: "host",
448 RT_SCOPE_NOWHERE: "nowhere",
449 }
450
451 _type_str = {
452 RTN_UNSPEC: "unspecified",
453 RTN_UNICAST: "unicast",
454 RTN_LOCAL: "local",
455 RTN_BROADCAST: "broadcast",
456 RTN_ANYCAST: "anycast",
457 RTN_MULTICAST: "multicast",
458 RTN_BLACKHOLE: "blackhole",
459 RTN_UNREACHABLE: "unreachable",
460 RTN_PROHIBIT: "prohibit",
461 RTN_THROW: "throw",
462 RTN_NAT: "nat",
463 RTN_XRESOLVE: "xresolve",
464 }
465
466 def dump(self):
467 print 'rtm_family', self.rtm_family
468 print 'rtm_dst_len', self.rtm_dst_len
469 print 'rtm_src_len', self.rtm_src_len
470 print 'rtm_tos', self.rtm_tos
471 print 'rtm_table', self._table_str.get(self.rtm_table, self.rtm_table)
472 print 'rtm_protocol', self._proto_str.get(self.rtm_protocol)
473 print 'rtm_scope', self._scope_str.get(self.rtm_scope)
474 print 'rtm_type', self._type_str.get(self.rtm_type)
475 print 'rtm_flags 0x%08x' % self.rtm_flags
476
477 def rta_fn(self, rta_type):
478 fns = {
479 RTA_DST: self.rta_addr,
480 RTA_SRC: self.rta_addr,
481 RTA_IIF: self.rta_uint32,
482 RTA_OIF: self.rta_uint32,
483 RTA_GATEWAY: self.rta_addr,
484 RTA_PRIORITY: self.rta_uint32,
485 RTA_PREFSRC: self.rta_addr,
486 RTA_METRICS: self.rta_uint32_array,
487 RTA_MULTIPATH: self.rta_multipath,
488 RTA_PROTOINFO: self.rta_none,
489 RTA_FLOW: self.rta_uint32,
490 RTA_CACHEINFO: self.rta_none,
491 RTA_SESSION: self.rta_none,
492 RTA_MP_ALGO: self.rta_none,
493 RTA_TABLE: self.rta_uint32,
494 }
495
496 return fns.get(rta_type)
497
498 class Rtgenmsg(Nlmsg):
499
500 _fields_ = [
501 ('rtgen_family', c_uint8),
502 ]
503
504 def dump(self):
505 print 'rtgen_family', self.rtgen_family
506
507 # New extended info filters for IFLA_EXT_MASK
508 RTEXT_FILTER_VF = (1 << 0)
509
510 # passes link level specific information, not dependent
511 # on network protocol.
512
513 IFLA_UNSPEC = 0
514 IFLA_ADDRESS = 1
515 IFLA_BROADCAST = 2
516 IFLA_IFNAME = 3
517 IFLA_MTU = 4
518 IFLA_LINK = 5
519 IFLA_QDISC = 6
520 IFLA_STATS = 7
521 IFLA_COST = 8
522 IFLA_PRIORITY = 9
523 IFLA_MASTER = 10
524 IFLA_WIRELESS = 11 # Wireless Extension event - see wireless.h
525 IFLA_PROTINFO = 12 # Protocol specific information for a link
526 IFLA_TXQLEN = 13
527 IFLA_MAP = 14
528 IFLA_WEIGHT = 15
529 IFLA_OPERSTATE = 16
530 IFLA_LINKMODE = 17
531 IFLA_LINKINFO = 18
532 IFLA_NET_NS_PID = 19
533 IFLA_IFALIAS = 20
534 IFLA_NUM_VF = 21 # Number of VFs if device is SR-IOV PF
535 IFLA_VFINFO_LIST = 22
536 IFLA_STATS64 = 23
537 IFLA_VF_PORTS = 24
538 IFLA_PORT_SELF = 25
539 IFLA_AF_SPEC = 26
540 IFLA_GROUP = 27 # Group the device belongs to
541 IFLA_NET_NS_FD = 28
542 IFLA_EXT_MASK = 29 # Extended info mask, VFs, etc
543 IFLA_MAX = 29
544
545
546 # IFLA_LINKINFO attributes
547 IFLA_INFO_UNSPEC = 0
548 IFLA_INFO_KIND = 1
549 IFLA_INFO_DATA = 2
550 IFLA_INFO_XSTATS = 3
551 IFLA_INFO_MAX = 4
552
553 # IFLA_LINKINFO_DATA attributes for vlan
554 IFLA_VLAN_UNSPEC = 0
555 IFLA_VLAN_ID = 1
556
557 # IFLA_LINKINFO_DATA attributes for macvlan
558 IFLA_MACVLAN_UNSPEC = 0
559 IFLA_MACVLAN_MODE = 1
560
561 # macvlan modes
562 MACVLAN_MODE_PRIVATE = 1
563 MACVLAN_MODE_VEPA = 2
564 MACVLAN_MODE_BRIDGE = 3
565 MACVLAN_MODE_PASSTHRU = 4
566
567 class Ifinfomsg(Nlmsg):
568
569 _fields_ = [
570 ('ifi_family', c_uint8),
571 ('__ifi_pad', c_uint8),
572 ('ifi_type', c_uint16), # ARPHRD_*
573 ('ifi_index', c_int32), # Link index
574 ('ifi_flags', c_uint32), # IFF_* flags
575 ('ifi_change', c_uint32), # IFF_* change mask
576 ]
577
578 def dump(self):
579 print 'ifi_family', self.ifi_family
580 print 'ifi_type', self.ifi_type
581 print 'ifi_index', self.ifi_index
582 print 'ifi_flags 0x%08x' % self.ifi_flags
583 print 'ifi_change 0x%08x' % self.ifi_change
584
585 def rta_linkinfo_data_vlan_policy(self):
586 fns = {
587 IFLA_VLAN_ID : self.rta_uint16,
588 }
589 return fns
590
591 def rta_linkinfo_data_macvlan_policy(self):
592 fns = {
593 IFLA_MACVLAN_MODE : self.rta_uint32,
594 }
595 return fns
596
597 def rta_linkinfo_policy(self):
598 fns = {
599 IFLA_INFO_KIND : self.rta_string,
600 IFLA_INFO_DATA : self.rta_linkinfo_data,
601 }
602 return fns
603
604 def rta_policy(self):
605 fns = {
606 IFLA_UNSPEC: self.rta_wtf,
607 IFLA_ADDRESS: self.rta_uint8_array,
608 IFLA_BROADCAST: self.rta_uint8_array,
609 IFLA_IFNAME: self.rta_string,
610 IFLA_MTU: self.rta_uint32,
611 IFLA_LINK: self.rta_uint32,
612 IFLA_QDISC: self.rta_string,
613 IFLA_STATS: self.rta_none,
614 IFLA_COST: self.rta_none,
615 IFLA_PRIORITY: self.rta_none,
616 IFLA_MASTER: self.rta_uint32,
617 IFLA_WIRELESS: self.rta_none,
618 IFLA_PROTINFO: self.rta_none,
619 IFLA_TXQLEN: self.rta_uint32,
620 IFLA_MAP: self.rta_none,
621 IFLA_WEIGHT: self.rta_uint32,
622 IFLA_OPERSTATE: self.rta_uint8,
623 IFLA_LINKMODE: self.rta_uint8,
624 IFLA_LINKINFO: self.rta_linkinfo,
625 IFLA_NET_NS_PID: self.rta_uint32,
626 IFLA_IFALIAS: self.rta_string,
627 IFLA_NUM_VF: self.rta_uint32,
628 IFLA_VFINFO_LIST: self.rta_none,
629 IFLA_STATS64: self.rta_none,
630 IFLA_VF_PORTS: self.rta_none,
631 IFLA_PORT_SELF: self.rta_none,
632 IFLA_AF_SPEC: self.rta_none,
633 IFLA_GROUP: self.rta_none,
634 IFLA_NET_NS_FD: self.rta_none,
635 IFLA_EXT_MASK: self.rta_none,
636 }
637 return fns;
638
639 def rta_fn(self, rta_type):
640 fns = {
641 IFLA_UNSPEC: self.rta_wtf,
642 IFLA_ADDRESS: self.rta_uint8_array,
643 IFLA_BROADCAST: self.rta_uint8_array,
644 IFLA_IFNAME: self.rta_string,
645 IFLA_MTU: self.rta_uint32,
646 IFLA_LINK: self.rta_uint32,
647 IFLA_QDISC: self.rta_string,
648 IFLA_STATS: self.rta_none,
649 IFLA_COST: self.rta_none,
650 IFLA_PRIORITY: self.rta_none,
651 IFLA_MASTER: self.rta_uint32,
652 IFLA_WIRELESS: self.rta_none,
653 IFLA_PROTINFO: self.rta_none,
654 IFLA_TXQLEN: self.rta_uint32,
655 IFLA_MAP: self.rta_none,
656 IFLA_WEIGHT: self.rta_uint32,
657 IFLA_OPERSTATE: self.rta_uint8,
658 IFLA_LINKMODE: self.rta_uint8,
659 IFLA_LINKINFO: self.rta_linkinfo,
660 IFLA_NET_NS_PID: self.rta_uint32,
661 IFLA_IFALIAS: self.rta_string,
662 IFLA_NUM_VF: self.rta_uint32,
663 IFLA_VFINFO_LIST: self.rta_none,
664 IFLA_STATS64: self.rta_none,
665 IFLA_VF_PORTS: self.rta_none,
666 IFLA_PORT_SELF: self.rta_none,
667 IFLA_AF_SPEC: self.rta_none,
668 IFLA_GROUP: self.rta_none,
669 IFLA_NET_NS_FD: self.rta_none,
670 IFLA_EXT_MASK: self.rta_none,
671 }
672 return fns.get(rta_type)
673
674 # passes address specific information
675
676 # Important comment:
677 # IFA_ADDRESS is prefix address, rather than local interface address.
678 # It makes no difference for normally configured broadcast interfaces,
679 # but for point-to-point IFA_ADDRESS is DESTINATION address,
680 # local address is supplied in IFA_LOCAL attribute.
681
682 IFA_UNSPEC = 0
683 IFA_ADDRESS = 1
684 IFA_LOCAL = 2
685 IFA_LABEL = 3
686 IFA_BROADCAST = 4
687 IFA_ANYCAST = 5
688 IFA_CACHEINFO = 6
689 IFA_MULTICAST = 7
690 IFA_MAX = 7
691
692 class Ifaddrmsg(Nlmsg):
693
694 _fields_ = [
695 ('ifa_family', c_uint8),
696 ('ifa_prefixlen', c_uint8), # The prefix length
697 ('ifa_flags', c_uint8), # Flags
698 ('ifa_scope', c_uint8), # Address scope
699 ('ifa_index', c_uint32), # Link index
700 ]
701
702 _family_str = {
703 AF_INET: "inet",
704 AF_INET6: "inet6",
705 }
706
707 def dump(self):
708 print 'ifa_family', self.ifa_family
709 print 'ifa_prefixlen', self.ifa_prefixlen
710 print 'ifa_flags 0x%02x' % self.ifa_flags
711 print 'ifa_scope', self.ifa_scope
712 print 'ifa_index', self.ifa_index
713
714 def rta_fn(self, rta_type):
715 fns = {
716 IFA_ADDRESS: self.rta_addr,
717 IFA_LOCAL: self.rta_addr,
718 IFA_LABEL: self.rta_string,
719 IFA_BROADCAST: self.rta_addr,
720 IFA_ANYCAST: self.rta_addr,
721 IFA_CACHEINFO: self.rta_none,
722 IFA_MULTICAST: self.rta_addr,
723 }
724 return fns.get(rta_type)
725
726 class RtNetlinkError(Exception):
727
728 def __init__(self, message):
729 Exception.__init__(self, message)
730 logger.error(message)
731
732 class RtNetlink(Netlink):
733
734 def __init__(self, pid):
735 Netlink.__init__(self, pid, NETLINK_ROUTE)
736
737 _rt_nlmsg_type_str = {
738 RTM_NEWROUTE: "RTM_NEWROUTE",
739 RTM_DELROUTE: "RTM_DELROUTE",
740 RTM_NEWLINK: "RTM_NEWLINK",
741 RTM_DELLINK: "RTM_DELLINK",
742 RTM_GETLINK: "RTM_GETLINK",
743 RTM_NEWADDR: "RTM_NEWADDR",
744 RTM_DELADDR: "RTM_DELADDR",
745 }
746
747 def _hexdump(self, buf):
748 while buf:
749 chunk = buf[:16]
750 buf = buf[16:]
751 nums = ["%02x" % c for c in chunk]
752 txt = [chr(c) if chr(c) in printable[:-5] else '.' for c in chunk]
753 print " ".join(nums).ljust(48), "".join(txt)
754
755 def dump(self, nlh):
756 nlmsg = self.nlmsg(nlh)
757 print
758 self._hexdump(self.sendbuf[:nlh.nlmsg_len])
759 print
760 nlh.dump()
761 print
762 nlmsg.dump()
763 print
764 nlmsg.dump_rtas()
765
766 def nlmsg(self, nlh):
767 nlmsg_struct = {
768 RTM_NEWROUTE: Rtmsg,
769 RTM_DELROUTE: Rtmsg,
770 RTM_GETROUTE: Rtmsg,
771 RTM_NEWLINK: Ifinfomsg,
772 RTM_DELLINK: Ifinfomsg,
773 RTM_GETLINK: Rtgenmsg,
774 RTM_NEWADDR: Ifaddrmsg,
775 RTM_DELADDR: Ifaddrmsg,
776 RTM_GETADDR: Rtgenmsg,
777 }
778 nldata = NLMSG_DATA(nlh)
779 nlmsg = nlmsg_struct[nlh.nlmsg_type].from_address(nldata)
780 nlmsg.nlh = nlh
781 return nlmsg
782
783 def _nl_cb(self, nlh):
784 # print "nl cb", self._rt_nlmsg_type_str[nlh.nlmsg_type]
785
786 if nlh.nlmsg_type in self._cbs:
787
788 nlmsg = self.nlmsg(nlh)
789
790 # validate nl length
791 if nlh.nlmsg_len - NLMSG_LENGTH(sizeof(nlmsg)) < 0:
792 raise RtNetlinkError("invalid nl length")
793
794 self._cbs[nlh.nlmsg_type](nlh, nlmsg)
795
796 def bind(self, groups, cbs):
797 self._cbs = cbs
798 Netlink.bind(self, groups, self._nl_cb)
799
800 def request(self, nlmsg_type, flags, extra, rtas={}):
801
802 nlh = Nlmsghdr.from_buffer(self.sendbuf)
803 nlh_p = addressof(nlh)
804
805 seq = self.seq
806 pid = self.pid
807
808 nlh.nlmsg_len = NLMSG_HDRLEN()
809 nlh.nlmsg_type = nlmsg_type
810 nlh.nlmsg_flags = flags
811 nlh.nlmsg_pid = pid
812 nlh.nlmsg_seq = seq
813
814 nlmsg = self.nlmsg(nlh)
815
816 nlh.nlmsg_len += nlmsg.pack_extra(extra, nlh_p + nlh.nlmsg_len)
817 nlh.nlmsg_len += nlmsg.pack_rtas_new(rtas, nlh_p + nlh.nlmsg_len, nlmsg.rta_policy())
818
819 #self.dump(nlh)
820 self.sendall(string_at(nlh_p, nlh.nlmsg_len))
821 self.seq += 1
822
823 token = (pid, seq)
824 return token
825
826 def rta_linkinfo_policy(self):
827 fns = {
828 [IFLA_INFO_KIND] : self.rta_string,
829 [IFLA_INFO_DATA] : self.rta_linkinfo_data,
830 }
831 return fns
832
833 def rta_policy(self):
834 fns = {
835 IFLA_UNSPEC: self.rta_wtf,
836 IFLA_ADDRESS: self.rta_uint8_array,
837 IFLA_BROADCAST: self.rta_uint8_array,
838 IFLA_IFNAME: self.rta_string,
839 IFLA_MTU: self.rta_uint32,
840 IFLA_LINK: self.rta_uint32,
841 IFLA_QDISC: self.rta_string,
842 IFLA_STATS: self.rta_none,
843 IFLA_COST: self.rta_none,
844 IFLA_PRIORITY: self.rta_none,
845 IFLA_MASTER: self.rta_uint32,
846 IFLA_WIRELESS: self.rta_none,
847 IFLA_PROTINFO: self.rta_none,
848 IFLA_TXQLEN: self.rta_uint32,
849 IFLA_MAP: self.rta_none,
850 IFLA_WEIGHT: self.rta_uint32,
851 IFLA_OPERSTATE: self.rta_uint8,
852 IFLA_LINKMODE: self.rta_uint8,
853 IFLA_LINKINFO: self.rta_linkinfo,
854 IFLA_NET_NS_PID: self.rta_uint32,
855 IFLA_IFALIAS: self.rta_string,
856 IFLA_NUM_VF: self.rta_uint32,
857 IFLA_VFINFO_LIST: self.rta_none,
858 IFLA_STATS64: self.rta_none,
859 IFLA_VF_PORTS: self.rta_none,
860 IFLA_PORT_SELF: self.rta_none,
861 IFLA_AF_SPEC: self.rta_none,
862 IFLA_GROUP: self.rta_none,
863 IFLA_NET_NS_FD: self.rta_none,
864 IFLA_EXT_MASK: self.rta_none,
865 }
866 return fns;