xref: /aosp_15_r20/kernel/tests/net/test/netlink.py (revision 2f2c4c7ab4226c71756b9c31670392fdd6887c4f)
1*2f2c4c7aSAndroid Build Coastguard Worker#!/usr/bin/python3
2*2f2c4c7aSAndroid Build Coastguard Worker#
3*2f2c4c7aSAndroid Build Coastguard Worker# Copyright 2014 The Android Open Source Project
4*2f2c4c7aSAndroid Build Coastguard Worker#
5*2f2c4c7aSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
6*2f2c4c7aSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
7*2f2c4c7aSAndroid Build Coastguard Worker# You may obtain a copy of the License at
8*2f2c4c7aSAndroid Build Coastguard Worker#
9*2f2c4c7aSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0
10*2f2c4c7aSAndroid Build Coastguard Worker#
11*2f2c4c7aSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
12*2f2c4c7aSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
13*2f2c4c7aSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*2f2c4c7aSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
15*2f2c4c7aSAndroid Build Coastguard Worker# limitations under the License.
16*2f2c4c7aSAndroid Build Coastguard Worker
17*2f2c4c7aSAndroid Build Coastguard Worker"""Partial Python implementation of iproute functionality."""
18*2f2c4c7aSAndroid Build Coastguard Worker
19*2f2c4c7aSAndroid Build Coastguard Worker# pylint: disable=g-bad-todo
20*2f2c4c7aSAndroid Build Coastguard Worker
21*2f2c4c7aSAndroid Build Coastguard Workerimport os
22*2f2c4c7aSAndroid Build Coastguard Workerimport socket
23*2f2c4c7aSAndroid Build Coastguard Workerimport struct
24*2f2c4c7aSAndroid Build Coastguard Workerimport sys
25*2f2c4c7aSAndroid Build Coastguard Worker
26*2f2c4c7aSAndroid Build Coastguard Workerimport cstruct
27*2f2c4c7aSAndroid Build Coastguard Workerimport util
28*2f2c4c7aSAndroid Build Coastguard Worker
29*2f2c4c7aSAndroid Build Coastguard Worker### Base netlink constants. See include/uapi/linux/netlink.h.
30*2f2c4c7aSAndroid Build Coastguard WorkerNETLINK_ROUTE = 0
31*2f2c4c7aSAndroid Build Coastguard WorkerNETLINK_SOCK_DIAG = 4
32*2f2c4c7aSAndroid Build Coastguard WorkerNETLINK_XFRM = 6
33*2f2c4c7aSAndroid Build Coastguard WorkerNETLINK_GENERIC = 16
34*2f2c4c7aSAndroid Build Coastguard Worker
35*2f2c4c7aSAndroid Build Coastguard Worker# Request constants.
36*2f2c4c7aSAndroid Build Coastguard WorkerNLM_F_REQUEST = 1
37*2f2c4c7aSAndroid Build Coastguard WorkerNLM_F_ACK = 4
38*2f2c4c7aSAndroid Build Coastguard WorkerNLM_F_REPLACE = 0x100
39*2f2c4c7aSAndroid Build Coastguard WorkerNLM_F_EXCL = 0x200
40*2f2c4c7aSAndroid Build Coastguard WorkerNLM_F_CREATE = 0x400
41*2f2c4c7aSAndroid Build Coastguard WorkerNLM_F_DUMP = 0x300
42*2f2c4c7aSAndroid Build Coastguard Worker
43*2f2c4c7aSAndroid Build Coastguard Worker# Message types.
44*2f2c4c7aSAndroid Build Coastguard WorkerNLMSG_ERROR = 2
45*2f2c4c7aSAndroid Build Coastguard WorkerNLMSG_DONE = 3
46*2f2c4c7aSAndroid Build Coastguard Worker
47*2f2c4c7aSAndroid Build Coastguard Worker# Data structure formats.
48*2f2c4c7aSAndroid Build Coastguard Worker# These aren't constants, they're classes. So, pylint: disable=invalid-name
49*2f2c4c7aSAndroid Build Coastguard WorkerNLMsgHdr = cstruct.Struct("NLMsgHdr", "=LHHLL", "length type flags seq pid")
50*2f2c4c7aSAndroid Build Coastguard WorkerNLMsgErr = cstruct.Struct("NLMsgErr", "=i", "error")
51*2f2c4c7aSAndroid Build Coastguard WorkerNLAttr = cstruct.Struct("NLAttr", "=HH", "nla_len nla_type")
52*2f2c4c7aSAndroid Build Coastguard Worker
53*2f2c4c7aSAndroid Build Coastguard Worker# Alignment / padding.
54*2f2c4c7aSAndroid Build Coastguard WorkerNLA_ALIGNTO = 4
55*2f2c4c7aSAndroid Build Coastguard Worker
56*2f2c4c7aSAndroid Build Coastguard Worker# List of attributes that can appear more than once in a given netlink message.
57*2f2c4c7aSAndroid Build Coastguard Worker# These can appear more than once but don't seem to contain any data.
58*2f2c4c7aSAndroid Build Coastguard WorkerDUP_ATTRS_OK = ["INET_DIAG_NONE", "IFLA_PAD"]
59*2f2c4c7aSAndroid Build Coastguard Worker
60*2f2c4c7aSAndroid Build Coastguard Worker
61*2f2c4c7aSAndroid Build Coastguard Workerdef MakeConstantPrefixes(prefixes):
62*2f2c4c7aSAndroid Build Coastguard Worker  return sorted(prefixes, key=len, reverse=True)
63*2f2c4c7aSAndroid Build Coastguard Worker
64*2f2c4c7aSAndroid Build Coastguard Worker
65*2f2c4c7aSAndroid Build Coastguard Workerclass NetlinkSocket(object):
66*2f2c4c7aSAndroid Build Coastguard Worker  """A basic netlink socket object."""
67*2f2c4c7aSAndroid Build Coastguard Worker
68*2f2c4c7aSAndroid Build Coastguard Worker  BUFSIZE = 65536
69*2f2c4c7aSAndroid Build Coastguard Worker  DEBUG = False
70*2f2c4c7aSAndroid Build Coastguard Worker  # List of netlink messages to print, e.g., [], ["NEIGH", "ROUTE"], or ["ALL"]
71*2f2c4c7aSAndroid Build Coastguard Worker  NL_DEBUG = []
72*2f2c4c7aSAndroid Build Coastguard Worker
73*2f2c4c7aSAndroid Build Coastguard Worker  def _Debug(self, s):
74*2f2c4c7aSAndroid Build Coastguard Worker    if self.DEBUG:
75*2f2c4c7aSAndroid Build Coastguard Worker      print(s)
76*2f2c4c7aSAndroid Build Coastguard Worker
77*2f2c4c7aSAndroid Build Coastguard Worker  def _NlAttr(self, nla_type, data):
78*2f2c4c7aSAndroid Build Coastguard Worker    assert isinstance(data, bytes)
79*2f2c4c7aSAndroid Build Coastguard Worker    datalen = len(data)
80*2f2c4c7aSAndroid Build Coastguard Worker    # Pad the data if it's not a multiple of NLA_ALIGNTO bytes long.
81*2f2c4c7aSAndroid Build Coastguard Worker    padding = b"\x00" * util.GetPadLength(NLA_ALIGNTO, datalen)
82*2f2c4c7aSAndroid Build Coastguard Worker    nla_len = datalen + len(NLAttr)
83*2f2c4c7aSAndroid Build Coastguard Worker    return NLAttr((nla_len, nla_type)).Pack() + data + padding
84*2f2c4c7aSAndroid Build Coastguard Worker
85*2f2c4c7aSAndroid Build Coastguard Worker  def _NlAttrIPAddress(self, nla_type, family, address):
86*2f2c4c7aSAndroid Build Coastguard Worker    return self._NlAttr(nla_type, socket.inet_pton(family, address))
87*2f2c4c7aSAndroid Build Coastguard Worker
88*2f2c4c7aSAndroid Build Coastguard Worker  def _NlAttrStr(self, nla_type, value):
89*2f2c4c7aSAndroid Build Coastguard Worker    value = value + "\x00"
90*2f2c4c7aSAndroid Build Coastguard Worker    return self._NlAttr(nla_type, value.encode("UTF-8"))
91*2f2c4c7aSAndroid Build Coastguard Worker
92*2f2c4c7aSAndroid Build Coastguard Worker  def _NlAttrU32(self, nla_type, value):
93*2f2c4c7aSAndroid Build Coastguard Worker    return self._NlAttr(nla_type, struct.pack("=I", value))
94*2f2c4c7aSAndroid Build Coastguard Worker
95*2f2c4c7aSAndroid Build Coastguard Worker  @staticmethod
96*2f2c4c7aSAndroid Build Coastguard Worker  def _GetConstantName(module, value, prefix):
97*2f2c4c7aSAndroid Build Coastguard Worker    def FirstMatching(name, prefixlist):
98*2f2c4c7aSAndroid Build Coastguard Worker      for prefix in prefixlist:
99*2f2c4c7aSAndroid Build Coastguard Worker        if name.startswith(prefix):
100*2f2c4c7aSAndroid Build Coastguard Worker         return prefix
101*2f2c4c7aSAndroid Build Coastguard Worker      return None
102*2f2c4c7aSAndroid Build Coastguard Worker
103*2f2c4c7aSAndroid Build Coastguard Worker    thismodule = sys.modules[module]
104*2f2c4c7aSAndroid Build Coastguard Worker    constant_prefixes = getattr(thismodule, "CONSTANT_PREFIXES", [])
105*2f2c4c7aSAndroid Build Coastguard Worker    for name in dir(thismodule):
106*2f2c4c7aSAndroid Build Coastguard Worker      if value != getattr(thismodule, name) or not name.isupper():
107*2f2c4c7aSAndroid Build Coastguard Worker        continue
108*2f2c4c7aSAndroid Build Coastguard Worker      # If the module explicitly specifies prefixes, only return this name if
109*2f2c4c7aSAndroid Build Coastguard Worker      # the passed-in prefix is the longest prefix that matches the name.
110*2f2c4c7aSAndroid Build Coastguard Worker      # This ensures, for example, that passing in a prefix of "IFA_" and a
111*2f2c4c7aSAndroid Build Coastguard Worker      # value of 1 returns "IFA_ADDRESS" instead of "IFA_F_SECONDARY".
112*2f2c4c7aSAndroid Build Coastguard Worker      # The longest matching prefix is always the first matching prefix because
113*2f2c4c7aSAndroid Build Coastguard Worker      # CONSTANT_PREFIXES must be sorted longest first.
114*2f2c4c7aSAndroid Build Coastguard Worker      if constant_prefixes and prefix != FirstMatching(name, constant_prefixes):
115*2f2c4c7aSAndroid Build Coastguard Worker        continue
116*2f2c4c7aSAndroid Build Coastguard Worker      if name.startswith(prefix):
117*2f2c4c7aSAndroid Build Coastguard Worker        return name
118*2f2c4c7aSAndroid Build Coastguard Worker    return value
119*2f2c4c7aSAndroid Build Coastguard Worker
120*2f2c4c7aSAndroid Build Coastguard Worker  def _Decode(self, command, msg, nla_type, nla_data, nested):
121*2f2c4c7aSAndroid Build Coastguard Worker    """No-op, nonspecific version of decode."""
122*2f2c4c7aSAndroid Build Coastguard Worker    return nla_type, nla_data
123*2f2c4c7aSAndroid Build Coastguard Worker
124*2f2c4c7aSAndroid Build Coastguard Worker  def _ReadNlAttr(self, data):
125*2f2c4c7aSAndroid Build Coastguard Worker    # Read the nlattr header.
126*2f2c4c7aSAndroid Build Coastguard Worker    nla, data = cstruct.Read(data, NLAttr)
127*2f2c4c7aSAndroid Build Coastguard Worker
128*2f2c4c7aSAndroid Build Coastguard Worker    # Read the data.
129*2f2c4c7aSAndroid Build Coastguard Worker    datalen = nla.nla_len - len(nla)
130*2f2c4c7aSAndroid Build Coastguard Worker    padded_len = util.GetPadLength(NLA_ALIGNTO, datalen) + datalen
131*2f2c4c7aSAndroid Build Coastguard Worker    nla_data, data = data[:datalen], data[padded_len:]
132*2f2c4c7aSAndroid Build Coastguard Worker
133*2f2c4c7aSAndroid Build Coastguard Worker    return nla, nla_data, data
134*2f2c4c7aSAndroid Build Coastguard Worker
135*2f2c4c7aSAndroid Build Coastguard Worker  def _ParseAttributes(self, command, msg, data, nested):
136*2f2c4c7aSAndroid Build Coastguard Worker    """Parses and decodes netlink attributes.
137*2f2c4c7aSAndroid Build Coastguard Worker
138*2f2c4c7aSAndroid Build Coastguard Worker    Takes a block of NLAttr data structures, decodes them using Decode, and
139*2f2c4c7aSAndroid Build Coastguard Worker    returns the result in a dict keyed by attribute number.
140*2f2c4c7aSAndroid Build Coastguard Worker
141*2f2c4c7aSAndroid Build Coastguard Worker    Args:
142*2f2c4c7aSAndroid Build Coastguard Worker      command: An integer, the rtnetlink command being carried out.
143*2f2c4c7aSAndroid Build Coastguard Worker      msg: A Struct, the type of the data after the netlink header.
144*2f2c4c7aSAndroid Build Coastguard Worker      data: A byte string containing a sequence of NLAttr data structures.
145*2f2c4c7aSAndroid Build Coastguard Worker      nested: A list, outermost first, of each of the attributes the NLAttrs are
146*2f2c4c7aSAndroid Build Coastguard Worker              nested inside. Empty for non-nested attributes.
147*2f2c4c7aSAndroid Build Coastguard Worker
148*2f2c4c7aSAndroid Build Coastguard Worker    Returns:
149*2f2c4c7aSAndroid Build Coastguard Worker      A dictionary mapping attribute types (integers) to decoded values.
150*2f2c4c7aSAndroid Build Coastguard Worker
151*2f2c4c7aSAndroid Build Coastguard Worker    Raises:
152*2f2c4c7aSAndroid Build Coastguard Worker      ValueError: There was a duplicate attribute type.
153*2f2c4c7aSAndroid Build Coastguard Worker    """
154*2f2c4c7aSAndroid Build Coastguard Worker    attributes = {}
155*2f2c4c7aSAndroid Build Coastguard Worker    while data:
156*2f2c4c7aSAndroid Build Coastguard Worker      nla, nla_data, data = self._ReadNlAttr(data)
157*2f2c4c7aSAndroid Build Coastguard Worker
158*2f2c4c7aSAndroid Build Coastguard Worker      # If it's an attribute we know about, try to decode it.
159*2f2c4c7aSAndroid Build Coastguard Worker      nla_name, nla_data = self._Decode(command, msg, nla.nla_type, nla_data, nested)
160*2f2c4c7aSAndroid Build Coastguard Worker
161*2f2c4c7aSAndroid Build Coastguard Worker      if nla_name in attributes and nla_name not in DUP_ATTRS_OK:
162*2f2c4c7aSAndroid Build Coastguard Worker        raise ValueError("Duplicate attribute %s" % nla_name)
163*2f2c4c7aSAndroid Build Coastguard Worker
164*2f2c4c7aSAndroid Build Coastguard Worker      attributes[nla_name] = nla_data
165*2f2c4c7aSAndroid Build Coastguard Worker      if not nested:
166*2f2c4c7aSAndroid Build Coastguard Worker        self._Debug("      %s" % (str((nla_name, nla_data))))
167*2f2c4c7aSAndroid Build Coastguard Worker
168*2f2c4c7aSAndroid Build Coastguard Worker    return attributes
169*2f2c4c7aSAndroid Build Coastguard Worker
170*2f2c4c7aSAndroid Build Coastguard Worker  def _OpenNetlinkSocket(self, family, groups):
171*2f2c4c7aSAndroid Build Coastguard Worker    sock = socket.socket(socket.AF_NETLINK, socket.SOCK_RAW, family)
172*2f2c4c7aSAndroid Build Coastguard Worker    if groups:
173*2f2c4c7aSAndroid Build Coastguard Worker      sock.bind((0,  groups))
174*2f2c4c7aSAndroid Build Coastguard Worker    sock.connect((0, 0))  # The kernel.
175*2f2c4c7aSAndroid Build Coastguard Worker    return sock
176*2f2c4c7aSAndroid Build Coastguard Worker
177*2f2c4c7aSAndroid Build Coastguard Worker  def __init__(self, family, groups=None):
178*2f2c4c7aSAndroid Build Coastguard Worker    # Global sequence number.
179*2f2c4c7aSAndroid Build Coastguard Worker    self.seq = 0
180*2f2c4c7aSAndroid Build Coastguard Worker    self.sock = self._OpenNetlinkSocket(family, groups)
181*2f2c4c7aSAndroid Build Coastguard Worker    self.pid = self.sock.getsockname()[1]
182*2f2c4c7aSAndroid Build Coastguard Worker
183*2f2c4c7aSAndroid Build Coastguard Worker  def close(self):
184*2f2c4c7aSAndroid Build Coastguard Worker    self.sock.close()
185*2f2c4c7aSAndroid Build Coastguard Worker    self.sock = None
186*2f2c4c7aSAndroid Build Coastguard Worker
187*2f2c4c7aSAndroid Build Coastguard Worker  def __del__(self):
188*2f2c4c7aSAndroid Build Coastguard Worker    if self.sock:
189*2f2c4c7aSAndroid Build Coastguard Worker      self.close()
190*2f2c4c7aSAndroid Build Coastguard Worker
191*2f2c4c7aSAndroid Build Coastguard Worker  def MaybeDebugCommand(self, command, flags, data):
192*2f2c4c7aSAndroid Build Coastguard Worker    # Default no-op implementation to be overridden by subclasses.
193*2f2c4c7aSAndroid Build Coastguard Worker    pass
194*2f2c4c7aSAndroid Build Coastguard Worker
195*2f2c4c7aSAndroid Build Coastguard Worker  def _Send(self, msg):
196*2f2c4c7aSAndroid Build Coastguard Worker    # self._Debug(msg.encode("hex"))
197*2f2c4c7aSAndroid Build Coastguard Worker    self.seq += 1
198*2f2c4c7aSAndroid Build Coastguard Worker    self.sock.send(msg)
199*2f2c4c7aSAndroid Build Coastguard Worker
200*2f2c4c7aSAndroid Build Coastguard Worker  def _Recv(self):
201*2f2c4c7aSAndroid Build Coastguard Worker    data = self.sock.recv(self.BUFSIZE)
202*2f2c4c7aSAndroid Build Coastguard Worker    # self._Debug(data.encode("hex"))
203*2f2c4c7aSAndroid Build Coastguard Worker    return data
204*2f2c4c7aSAndroid Build Coastguard Worker
205*2f2c4c7aSAndroid Build Coastguard Worker  def _ExpectDone(self):
206*2f2c4c7aSAndroid Build Coastguard Worker    response = self._Recv()
207*2f2c4c7aSAndroid Build Coastguard Worker    hdr = NLMsgHdr(response)
208*2f2c4c7aSAndroid Build Coastguard Worker    if hdr.type != NLMSG_DONE:
209*2f2c4c7aSAndroid Build Coastguard Worker      raise ValueError("Expected DONE, got type %d" % hdr.type)
210*2f2c4c7aSAndroid Build Coastguard Worker
211*2f2c4c7aSAndroid Build Coastguard Worker  def _ParseAck(self, response):
212*2f2c4c7aSAndroid Build Coastguard Worker    # Find the error code.
213*2f2c4c7aSAndroid Build Coastguard Worker    hdr, data = cstruct.Read(response, NLMsgHdr)
214*2f2c4c7aSAndroid Build Coastguard Worker    if hdr.type == NLMSG_ERROR:
215*2f2c4c7aSAndroid Build Coastguard Worker      error = -NLMsgErr(data).error
216*2f2c4c7aSAndroid Build Coastguard Worker      if error:
217*2f2c4c7aSAndroid Build Coastguard Worker        raise IOError(error, os.strerror(error))
218*2f2c4c7aSAndroid Build Coastguard Worker    else:
219*2f2c4c7aSAndroid Build Coastguard Worker      raise ValueError("Expected ACK, got type %d" % hdr.type)
220*2f2c4c7aSAndroid Build Coastguard Worker
221*2f2c4c7aSAndroid Build Coastguard Worker  def _ExpectAck(self):
222*2f2c4c7aSAndroid Build Coastguard Worker    response = self._Recv()
223*2f2c4c7aSAndroid Build Coastguard Worker    self._ParseAck(response)
224*2f2c4c7aSAndroid Build Coastguard Worker
225*2f2c4c7aSAndroid Build Coastguard Worker  def _SendNlRequest(self, command, data, flags):
226*2f2c4c7aSAndroid Build Coastguard Worker    """Sends a netlink request and expects an ack."""
227*2f2c4c7aSAndroid Build Coastguard Worker    length = len(NLMsgHdr) + len(data)
228*2f2c4c7aSAndroid Build Coastguard Worker    nlmsg = NLMsgHdr((length, command, flags, self.seq, self.pid)).Pack()
229*2f2c4c7aSAndroid Build Coastguard Worker
230*2f2c4c7aSAndroid Build Coastguard Worker    self.MaybeDebugCommand(command, flags, nlmsg + data)
231*2f2c4c7aSAndroid Build Coastguard Worker
232*2f2c4c7aSAndroid Build Coastguard Worker    # Send the message.
233*2f2c4c7aSAndroid Build Coastguard Worker    self._Send(nlmsg + data)
234*2f2c4c7aSAndroid Build Coastguard Worker
235*2f2c4c7aSAndroid Build Coastguard Worker    if flags & NLM_F_ACK:
236*2f2c4c7aSAndroid Build Coastguard Worker      self._ExpectAck()
237*2f2c4c7aSAndroid Build Coastguard Worker
238*2f2c4c7aSAndroid Build Coastguard Worker  def _ParseNLMsg(self, data, msgtype):
239*2f2c4c7aSAndroid Build Coastguard Worker    """Parses a Netlink message into a header and a dictionary of attributes."""
240*2f2c4c7aSAndroid Build Coastguard Worker    nlmsghdr, data = cstruct.Read(data, NLMsgHdr)
241*2f2c4c7aSAndroid Build Coastguard Worker    self._Debug("  %s" % nlmsghdr)
242*2f2c4c7aSAndroid Build Coastguard Worker
243*2f2c4c7aSAndroid Build Coastguard Worker    if nlmsghdr.type == NLMSG_ERROR or nlmsghdr.type == NLMSG_DONE:
244*2f2c4c7aSAndroid Build Coastguard Worker      print("done")
245*2f2c4c7aSAndroid Build Coastguard Worker      return (None, None), data
246*2f2c4c7aSAndroid Build Coastguard Worker
247*2f2c4c7aSAndroid Build Coastguard Worker    nlmsg, data = cstruct.Read(data, msgtype)
248*2f2c4c7aSAndroid Build Coastguard Worker    self._Debug("    %s" % nlmsg)
249*2f2c4c7aSAndroid Build Coastguard Worker
250*2f2c4c7aSAndroid Build Coastguard Worker    # Parse the attributes in the nlmsg.
251*2f2c4c7aSAndroid Build Coastguard Worker    attrlen = nlmsghdr.length - len(nlmsghdr) - len(nlmsg)
252*2f2c4c7aSAndroid Build Coastguard Worker    attributes = self._ParseAttributes(nlmsghdr.type, nlmsg, data[:attrlen], [])
253*2f2c4c7aSAndroid Build Coastguard Worker    data = data[attrlen:]
254*2f2c4c7aSAndroid Build Coastguard Worker    return (nlmsg, attributes), data
255*2f2c4c7aSAndroid Build Coastguard Worker
256*2f2c4c7aSAndroid Build Coastguard Worker  def _GetMsg(self, msgtype):
257*2f2c4c7aSAndroid Build Coastguard Worker    data = self._Recv()
258*2f2c4c7aSAndroid Build Coastguard Worker    if NLMsgHdr(data).type == NLMSG_ERROR:
259*2f2c4c7aSAndroid Build Coastguard Worker      self._ParseAck(data)
260*2f2c4c7aSAndroid Build Coastguard Worker    return self._ParseNLMsg(data, msgtype)[0]
261*2f2c4c7aSAndroid Build Coastguard Worker
262*2f2c4c7aSAndroid Build Coastguard Worker  def _GetMsgList(self, msgtype, data, expect_done):
263*2f2c4c7aSAndroid Build Coastguard Worker    out = []
264*2f2c4c7aSAndroid Build Coastguard Worker    while data:
265*2f2c4c7aSAndroid Build Coastguard Worker      msg, data = self._ParseNLMsg(data, msgtype)
266*2f2c4c7aSAndroid Build Coastguard Worker      if msg is None:
267*2f2c4c7aSAndroid Build Coastguard Worker        break
268*2f2c4c7aSAndroid Build Coastguard Worker      out.append(msg)
269*2f2c4c7aSAndroid Build Coastguard Worker    if expect_done:
270*2f2c4c7aSAndroid Build Coastguard Worker      self._ExpectDone()
271*2f2c4c7aSAndroid Build Coastguard Worker    return out
272*2f2c4c7aSAndroid Build Coastguard Worker
273*2f2c4c7aSAndroid Build Coastguard Worker  def _Dump(self, command, msg, msgtype, attrs=b""):
274*2f2c4c7aSAndroid Build Coastguard Worker    """Sends a dump request and returns a list of decoded messages.
275*2f2c4c7aSAndroid Build Coastguard Worker
276*2f2c4c7aSAndroid Build Coastguard Worker    Args:
277*2f2c4c7aSAndroid Build Coastguard Worker      command: An integer, the command to run (e.g., RTM_NEWADDR).
278*2f2c4c7aSAndroid Build Coastguard Worker      msg: A struct, the request (e.g., a RTMsg). May be None.
279*2f2c4c7aSAndroid Build Coastguard Worker      msgtype: A cstruct.Struct, the data type to parse the dump results as.
280*2f2c4c7aSAndroid Build Coastguard Worker      attrs: A string, the raw bytes of any request attributes to include.
281*2f2c4c7aSAndroid Build Coastguard Worker
282*2f2c4c7aSAndroid Build Coastguard Worker    Returns:
283*2f2c4c7aSAndroid Build Coastguard Worker      A list of (msg, attrs) tuples where msg is of type msgtype and attrs is
284*2f2c4c7aSAndroid Build Coastguard Worker      a dict of attributes.
285*2f2c4c7aSAndroid Build Coastguard Worker    """
286*2f2c4c7aSAndroid Build Coastguard Worker    # Create a netlink dump request containing the msg.
287*2f2c4c7aSAndroid Build Coastguard Worker    flags = NLM_F_DUMP | NLM_F_REQUEST
288*2f2c4c7aSAndroid Build Coastguard Worker    msg = b"" if msg is None else msg.Pack()
289*2f2c4c7aSAndroid Build Coastguard Worker    length = len(NLMsgHdr) + len(msg) + len(attrs)
290*2f2c4c7aSAndroid Build Coastguard Worker    nlmsghdr = NLMsgHdr((length, command, flags, self.seq, self.pid))
291*2f2c4c7aSAndroid Build Coastguard Worker
292*2f2c4c7aSAndroid Build Coastguard Worker    # Send the request.
293*2f2c4c7aSAndroid Build Coastguard Worker    request = nlmsghdr.Pack() + msg + attrs
294*2f2c4c7aSAndroid Build Coastguard Worker    self.MaybeDebugCommand(command, flags, request)
295*2f2c4c7aSAndroid Build Coastguard Worker    self._Send(request)
296*2f2c4c7aSAndroid Build Coastguard Worker
297*2f2c4c7aSAndroid Build Coastguard Worker    # Keep reading netlink messages until we get a NLMSG_DONE.
298*2f2c4c7aSAndroid Build Coastguard Worker    out = []
299*2f2c4c7aSAndroid Build Coastguard Worker    while True:
300*2f2c4c7aSAndroid Build Coastguard Worker      data = self._Recv()
301*2f2c4c7aSAndroid Build Coastguard Worker      response_type = NLMsgHdr(data).type
302*2f2c4c7aSAndroid Build Coastguard Worker      if response_type == NLMSG_DONE:
303*2f2c4c7aSAndroid Build Coastguard Worker        break
304*2f2c4c7aSAndroid Build Coastguard Worker      elif response_type == NLMSG_ERROR:
305*2f2c4c7aSAndroid Build Coastguard Worker        # Likely means that the kernel didn't like our dump request.
306*2f2c4c7aSAndroid Build Coastguard Worker        # Parse the error and throw an exception.
307*2f2c4c7aSAndroid Build Coastguard Worker        self._ParseAck(data)
308*2f2c4c7aSAndroid Build Coastguard Worker      out.extend(self._GetMsgList(msgtype, data, False))
309*2f2c4c7aSAndroid Build Coastguard Worker
310*2f2c4c7aSAndroid Build Coastguard Worker    return out
311