]>
git.proxmox.com Git - mirror_ifupdown2.git/blob - ifupdown2/ifupdown/netlink.py
3 # Copyright 2014 Cumulus Networks, Inc. All rights reserved.
4 # Author: Scott Feldman, sfeldma@cumulusnetworks.com
7 from os
import strerror
15 logger
= logging
.getLogger(__name__
)
18 # from /usr/include/linux/netlink.h
21 NETLINK_ROUTE
= 0 # Routing/device hook
22 NETLINK_UNUSED
= 1 # Unused number
23 NETLINK_USERSOCK
= 2 # Reserved for user mode socket protocols
24 NETLINK_FIREWALL
= 3 # Firewalling hook
25 NETLINK_INET_DIAG
= 4 # INET socket monitoring
26 NETLINK_NFLOG
= 5 # netfilter/iptables ULOG
27 NETLINK_XFRM
= 6 # ipsec
28 NETLINK_SELINUX
= 7 # SELinux event notifications
29 NETLINK_ISCSI
= 8 # Open-iSCSI
30 NETLINK_AUDIT
= 9 # auditing
31 NETLINK_FIB_LOOKUP
= 10
32 NETLINK_CONNECTOR
= 11
33 NETLINK_NETFILTER
= 12 # netfilter subsystem
35 NETLINK_DNRTMSG
= 14 # DECnet routing messages
36 NETLINK_KOBJECT_UEVENT
= 15 # Kernel messages to userspace
38 NETLINK_SCSITRANSPORT
= 18 # SCSI Transports
41 NETLINK_CRYPTO
= 21 # Crypto layer
43 NLMSG_NOOP
= 1 # Nothing.
44 NLMSG_ERROR
= 2 # Error
45 NLMSG_DONE
= 3 # End of a dump
46 NLMSG_OVERRUN
= 4 # Data lost
48 NETLINK_NO_ENOBUFS
= 5
52 class Nlmsghdr(Structure
):
55 ('nlmsg_len', c_uint32
),
56 ('nlmsg_type', c_uint16
),
57 ('nlmsg_flags', c_uint16
),
58 ('nlmsg_seq', c_uint32
),
59 ('nlmsg_pid', c_uint32
)
63 print 'nlmsg_len', self
.nlmsg_len
64 print 'nlmsg_type', self
.nlmsg_type
65 print 'nlmsg_flags 0x%04x' % self
.nlmsg_flags
66 print 'nlmsg_seq', self
.nlmsg_seq
67 print 'nlmsg_pid', self
.nlmsg_pid
71 NLM_F_REQUEST
= 1 # It is request message.
72 NLM_F_MULTI
= 2 # Multipart message, terminated by NLMSG_DONE
73 NLM_F_ACK
= 4 # Reply with ack, with zero or error code
74 NLM_F_ECHO
= 8 # Echo this request
75 NLM_F_DUMP_INTR
= 16 # Dump was inconsistent due to sequence change
77 # Modifiers to GET request
78 NLM_F_ROOT
= 0x100 # specify tree root
79 NLM_F_MATCH
= 0x200 # return all matching
80 NLM_F_ATOMIC
= 0x400 # atomic GET
81 NLM_F_DUMP
= (NLM_F_ROOT|NLM_F_MATCH
)
83 # Modifiers to NEW request
84 NLM_F_REPLACE
= 0x100 # Override existing
85 NLM_F_EXCL
= 0x200 # Do not touch, if it exists
86 NLM_F_CREATE
= 0x400 # Create, if it does not exist
87 NLM_F_APPEND
= 0x800 # Add to end of list
91 return (len + NLMSG_ALIGNTO
- 1) & ~
(NLMSG_ALIGNTO
- 1)
93 return NLMSG_ALIGN(sizeof(Nlmsghdr
))
94 def NLMSG_LENGTH(len):
95 return len + NLMSG_ALIGN(NLMSG_HDRLEN())
97 return NLMSG_ALIGN(NLMSG_LENGTH(len))
99 return addressof(nlh
) + NLMSG_LENGTH(0)
100 def NLMSG_NEXT(nlh
, len):
101 cur
= NLMSG_ALIGN(nlh
.nlmsg_len
)
102 nlh
= Nlmsghdr
.from_address(addressof(nlh
) + cur
)
103 return len - cur
, nlh
104 def NLMSG_OK(nlh
, len):
105 return len >= sizeof(Nlmsghdr
) and \
106 nlh
.nlmsg_len
>= sizeof(Nlmsghdr
) and \
109 class Nlmsgerr(Structure
):
116 class NetlinkError(Exception):
118 def __init__(self
, message
):
119 Exception.__init
__(self
, message
)
122 class Netlink(socket
.socket
):
124 def __init__(self
, pid
, proto
):
127 self
.recvbuf
= bytearray(8 * 1024)
128 self
.sendbuf
= bytearray(8 * 1024)
129 self
.seq
= int(time())
133 socket
.socket
.__init
__(self
, socket
.AF_NETLINK
, \
134 socket
.SOCK_RAW
, proto
)
137 # Need to turn off ENOBUFS for netlink socket otherwise
138 # in a kernel overrun situation, the socket will return
139 # ENOBUFS on socket recv and be stuck for future recvs.
141 self
.setsockopt(SOL_NETLINK
, NETLINK_NO_ENOBUFS
, 1)
143 except socket
.error
as (errno
, string
):
144 raise NetlinkError("open: socket err[%d]: %s" % \
147 def bind(self
, groups
, cb
):
152 socket
.socket
.bind(self
, (self
.pid
, groups
))
154 except socket
.error
as (errno
, string
):
155 raise NetlinkError("bind: socket err[%d]: %s" % \
158 def sendall(self
, string
):
160 socket
.socket
.sendall(self
, string
)
161 except socket
.error
as (errno
, string
):
162 raise NetlinkError("send: socket err[%d]: %s" % \
165 def _process_nlh(self
, recv
, nlh
):
166 while NLMSG_OK(nlh
, recv
):
168 recv
, nlh
= NLMSG_NEXT(nlh
, recv
)
170 def process(self
, tokens
=[]):
175 recv
, src_addr
= self
.recvfrom_into(self
.recvbuf
)
181 except socket
.error
as (errno
, string
):
182 if errno
in [EINTR
, EAGAIN
]:
184 raise NetlinkError("netlink: socket err[%d]: %s" % \
187 nlh
= Nlmsghdr
.from_buffer(self
.recvbuf
)
188 for recv
, nlh
in self
._process
_nlh
(recv
, nlh
):
190 # print "type %u, seq %u, pid %u" % \
191 # (nlh.nlmsg_type, nlh.nlmsg_seq, nlh.nlmsg_pid)
193 l
= nlh
.nlmsg_len
- sizeof(Nlmsghdr
)
195 if l
< 0 or nlh
.nlmsg_len
> recv
:
196 raise NetlinkError("netlink: malformed msg: len %d" % \
200 current
= (nlh
.nlmsg_pid
, nlh
.nlmsg_seq
)
201 if current
not in tokens
:
204 if nlh
.nlmsg_type
== NLMSG_DONE
:
208 if nlh
.nlmsg_type
== NLMSG_ERROR
:
209 err
= Nlmsgerr
.from_address(NLMSG_DATA(nlh
))
212 raise NetlinkError("netlink: %s" % strerror(abs(err
.error
)))
220 remnant
= recv
- NLMSG_ALIGN(nlh
.nlmsg_len
) > 0
222 raise NetlinkError("netlink: remnant of size %d" % \
227 def process_wait(self
, tokens
):
228 while self
.process(tokens
):
231 def process_forever(self
):
232 epoll
= select
.epoll()
233 epoll
.register(self
.fileno(), select
.EPOLLIN
)
235 events
= epoll
.poll()
236 for fileno
, event
in events
:
237 if fileno
== self
.fileno():
240 def process_event(self
, event
):
241 return self
.process()