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