Home | History | Annotate | Download | only in net_test
      1 #!/usr/bin/python
      2 #
      3 # Copyright 2014 The Android Open Source Project
      4 #
      5 # Licensed under the Apache License, Version 2.0 (the "License");
      6 # you may not use this file except in compliance with the License.
      7 # You may obtain a copy of the License at
      8 #
      9 # http://www.apache.org/licenses/LICENSE-2.0
     10 #
     11 # Unless required by applicable law or agreed to in writing, software
     12 # distributed under the License is distributed on an "AS IS" BASIS,
     13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 # See the License for the specific language governing permissions and
     15 # limitations under the License.
     16 
     17 """Partial Python implementation of iproute functionality."""
     18 
     19 # pylint: disable=g-bad-todo
     20 
     21 import errno
     22 import os
     23 import socket
     24 import struct
     25 import sys
     26 
     27 import cstruct
     28 import netlink
     29 
     30 
     31 ### Base netlink constants. See include/uapi/linux/netlink.h.
     32 NETLINK_ROUTE = 0
     33 
     34 # Request constants.
     35 NLM_F_REQUEST = 1
     36 NLM_F_ACK = 4
     37 NLM_F_REPLACE = 0x100
     38 NLM_F_EXCL = 0x200
     39 NLM_F_CREATE = 0x400
     40 NLM_F_DUMP = 0x300
     41 
     42 # Message types.
     43 NLMSG_ERROR = 2
     44 NLMSG_DONE = 3
     45 
     46 # Data structure formats.
     47 # These aren't constants, they're classes. So, pylint: disable=invalid-name
     48 NLMsgHdr = cstruct.Struct("NLMsgHdr", "=LHHLL", "length type flags seq pid")
     49 NLMsgErr = cstruct.Struct("NLMsgErr", "=i", "error")
     50 NLAttr = cstruct.Struct("NLAttr", "=HH", "nla_len nla_type")
     51 
     52 # Alignment / padding.
     53 NLA_ALIGNTO = 4
     54 
     55 
     56 ### rtnetlink constants. See include/uapi/linux/rtnetlink.h.
     57 # Message types.
     58 RTM_NEWLINK = 16
     59 RTM_DELLINK = 17
     60 RTM_GETLINK = 18
     61 RTM_NEWADDR = 20
     62 RTM_DELADDR = 21
     63 RTM_GETADDR = 22
     64 RTM_NEWROUTE = 24
     65 RTM_DELROUTE = 25
     66 RTM_GETROUTE = 26
     67 RTM_NEWNEIGH = 28
     68 RTM_DELNEIGH = 29
     69 RTM_GETNEIGH = 30
     70 RTM_NEWRULE = 32
     71 RTM_DELRULE = 33
     72 RTM_GETRULE = 34
     73 
     74 # Routing message type values (rtm_type).
     75 RTN_UNSPEC = 0
     76 RTN_UNICAST = 1
     77 RTN_UNREACHABLE = 7
     78 
     79 # Routing protocol values (rtm_protocol).
     80 RTPROT_UNSPEC = 0
     81 RTPROT_STATIC = 4
     82 
     83 # Route scope values (rtm_scope).
     84 RT_SCOPE_UNIVERSE = 0
     85 RT_SCOPE_LINK = 253
     86 
     87 # Named routing tables.
     88 RT_TABLE_UNSPEC = 0
     89 
     90 # Routing attributes.
     91 RTA_DST = 1
     92 RTA_SRC = 2
     93 RTA_OIF = 4
     94 RTA_GATEWAY = 5
     95 RTA_PRIORITY = 6
     96 RTA_PREFSRC = 7
     97 RTA_METRICS = 8
     98 RTA_CACHEINFO = 12
     99 RTA_TABLE = 15
    100 RTA_MARK = 16
    101 RTA_UID = 18
    102 
    103 # Route metric attributes.
    104 RTAX_MTU = 2
    105 RTAX_HOPLIMIT = 10
    106 
    107 # Data structure formats.
    108 IfinfoMsg = cstruct.Struct(
    109     "IfinfoMsg", "=BBHiII", "family pad type index flags change")
    110 RTMsg = cstruct.Struct(
    111     "RTMsg", "=BBBBBBBBI",
    112     "family dst_len src_len tos table protocol scope type flags")
    113 RTACacheinfo = cstruct.Struct(
    114     "RTACacheinfo", "=IIiiI", "clntref lastuse expires error used")
    115 
    116 
    117 ### Interface address constants. See include/uapi/linux/if_addr.h.
    118 # Interface address attributes.
    119 IFA_ADDRESS = 1
    120 IFA_LOCAL = 2
    121 IFA_CACHEINFO = 6
    122 
    123 # Address flags.
    124 IFA_F_SECONDARY = 0x01
    125 IFA_F_TEMPORARY = IFA_F_SECONDARY
    126 IFA_F_NODAD = 0x02
    127 IFA_F_OPTIMISTIC = 0x04
    128 IFA_F_DADFAILED = 0x08
    129 IFA_F_HOMEADDRESS = 0x10
    130 IFA_F_DEPRECATED = 0x20
    131 IFA_F_TENTATIVE = 0x40
    132 IFA_F_PERMANENT = 0x80
    133 
    134 # Data structure formats.
    135 IfAddrMsg = cstruct.Struct(
    136     "IfAddrMsg", "=BBBBI",
    137     "family prefixlen flags scope index")
    138 IFACacheinfo = cstruct.Struct(
    139     "IFACacheinfo", "=IIII", "prefered valid cstamp tstamp")
    140 NDACacheinfo = cstruct.Struct(
    141     "NDACacheinfo", "=IIII", "confirmed used updated refcnt")
    142 
    143 
    144 ### Neighbour table entry constants. See include/uapi/linux/neighbour.h.
    145 # Neighbour cache entry attributes.
    146 NDA_DST = 1
    147 NDA_LLADDR = 2
    148 NDA_CACHEINFO = 3
    149 NDA_PROBES = 4
    150 
    151 # Neighbour cache entry states.
    152 NUD_PERMANENT = 0x80
    153 
    154 # Data structure formats.
    155 NdMsg = cstruct.Struct(
    156     "NdMsg", "=BxxxiHBB",
    157     "family ifindex state flags type")
    158 
    159 
    160 ### FIB rule constants. See include/uapi/linux/fib_rules.h.
    161 FRA_IIFNAME = 3
    162 FRA_PRIORITY = 6
    163 FRA_FWMARK = 10
    164 FRA_SUPPRESS_PREFIXLEN = 14
    165 FRA_TABLE = 15
    166 FRA_FWMASK = 16
    167 FRA_OIFNAME = 17
    168 FRA_UID_START = 18
    169 FRA_UID_END = 19
    170 
    171 
    172 # Link constants. See include/uapi/linux/if_link.h.
    173 IFLA_ADDRESS = 1
    174 IFLA_BROADCAST = 2
    175 IFLA_IFNAME = 3
    176 IFLA_MTU = 4
    177 IFLA_QDISC = 6
    178 IFLA_STATS = 7
    179 IFLA_TXQLEN = 13
    180 IFLA_MAP = 14
    181 IFLA_OPERSTATE = 16
    182 IFLA_LINKMODE = 17
    183 IFLA_STATS64 = 23
    184 IFLA_AF_SPEC = 26
    185 IFLA_GROUP = 27
    186 IFLA_EXT_MASK = 29
    187 IFLA_PROMISCUITY = 30
    188 IFLA_NUM_TX_QUEUES = 31
    189 IFLA_NUM_RX_QUEUES = 32
    190 IFLA_CARRIER = 33
    191 
    192 
    193 def CommandVerb(command):
    194   return ["NEW", "DEL", "GET", "SET"][command % 4]
    195 
    196 
    197 def CommandSubject(command):
    198   return ["LINK", "ADDR", "ROUTE", "NEIGH", "RULE"][(command - 16) / 4]
    199 
    200 
    201 def CommandName(command):
    202   try:
    203     return "RTM_%s%s" % (CommandVerb(command), CommandSubject(command))
    204   except IndexError:
    205     return "RTM_%d" % command
    206 
    207 
    208 class IPRoute(netlink.NetlinkSocket):
    209   """Provides a tiny subset of iproute functionality."""
    210 
    211   FAMILY = NETLINK_ROUTE
    212 
    213   def _NlAttrIPAddress(self, nla_type, family, address):
    214     return self._NlAttr(nla_type, socket.inet_pton(family, address))
    215 
    216   def _NlAttrInterfaceName(self, nla_type, interface):
    217     return self._NlAttr(nla_type, interface + "\x00")
    218 
    219   def _GetConstantName(self, value, prefix):
    220     return super(IPRoute, self)._GetConstantName(__name__, value, prefix)
    221 
    222   def _Decode(self, command, msg, nla_type, nla_data):
    223     """Decodes netlink attributes to Python types.
    224 
    225     Values for which the code knows the type (e.g., the fwmark ID in a
    226     RTM_NEWRULE command) are decoded to Python integers, strings, etc. Values
    227     of unknown type are returned as raw byte strings.
    228 
    229     Args:
    230       command: An integer.
    231         - If positive, the number of the rtnetlink command being carried out.
    232           This is used to interpret the attributes. For example, for an
    233           RTM_NEWROUTE command, attribute type 3 is the incoming interface and
    234           is an integer, but for a RTM_NEWRULE command, attribute type 3 is the
    235           incoming interface name and is a string.
    236         - If negative, one of the following (negative) values:
    237           - RTA_METRICS: Interpret as nested route metrics.
    238       family: The address family. Used to convert IP addresses into strings.
    239       nla_type: An integer, then netlink attribute type.
    240       nla_data: A byte string, the netlink attribute data.
    241 
    242     Returns:
    243       A tuple (name, data):
    244        - name is a string (e.g., "FRA_PRIORITY") if we understood the attribute,
    245          or an integer if we didn't.
    246        - data can be an integer, a string, a nested dict of attributes as
    247          returned by _ParseAttributes (e.g., for RTA_METRICS), a cstruct.Struct
    248          (e.g., RTACacheinfo), etc. If we didn't understand the attribute, it
    249          will be the raw byte string.
    250     """
    251     if command == -RTA_METRICS:
    252       name = self._GetConstantName(nla_type, "RTAX_")
    253     elif CommandSubject(command) == "ADDR":
    254       name = self._GetConstantName(nla_type, "IFA_")
    255     elif CommandSubject(command) == "LINK":
    256       name = self._GetConstantName(nla_type, "IFLA_")
    257     elif CommandSubject(command) == "RULE":
    258       name = self._GetConstantName(nla_type, "FRA_")
    259     elif CommandSubject(command) == "ROUTE":
    260       name = self._GetConstantName(nla_type, "RTA_")
    261     elif CommandSubject(command) == "NEIGH":
    262       name = self._GetConstantName(nla_type, "NDA_")
    263     else:
    264       # Don't know what this is. Leave it as an integer.
    265       name = nla_type
    266 
    267     if name in ["FRA_PRIORITY", "FRA_FWMARK", "FRA_TABLE", "FRA_FWMASK",
    268                 "FRA_UID_START", "FRA_UID_END",
    269                 "RTA_OIF", "RTA_PRIORITY", "RTA_TABLE", "RTA_MARK",
    270                 "IFLA_MTU", "IFLA_TXQLEN", "IFLA_GROUP", "IFLA_EXT_MASK",
    271                 "IFLA_PROMISCUITY", "IFLA_NUM_RX_QUEUES",
    272                 "IFLA_NUM_TX_QUEUES", "NDA_PROBES", "RTAX_MTU",
    273                 "RTAX_HOPLIMIT"]:
    274       data = struct.unpack("=I", nla_data)[0]
    275     elif name == "FRA_SUPPRESS_PREFIXLEN":
    276       data = struct.unpack("=i", nla_data)[0]
    277     elif name in ["IFLA_LINKMODE", "IFLA_OPERSTATE", "IFLA_CARRIER"]:
    278       data = ord(nla_data)
    279     elif name in ["IFA_ADDRESS", "IFA_LOCAL", "RTA_DST", "RTA_SRC",
    280                   "RTA_GATEWAY", "RTA_PREFSRC", "RTA_UID",
    281                   "NDA_DST"]:
    282       data = socket.inet_ntop(msg.family, nla_data)
    283     elif name in ["FRA_IIFNAME", "FRA_OIFNAME", "IFLA_IFNAME", "IFLA_QDISC"]:
    284       data = nla_data.strip("\x00")
    285     elif name == "RTA_METRICS":
    286       data = self._ParseAttributes(-RTA_METRICS, msg.family, None, nla_data)
    287     elif name == "RTA_CACHEINFO":
    288       data = RTACacheinfo(nla_data)
    289     elif name == "IFA_CACHEINFO":
    290       data = IFACacheinfo(nla_data)
    291     elif name == "NDA_CACHEINFO":
    292       data = NDACacheinfo(nla_data)
    293     elif name in ["NDA_LLADDR", "IFLA_ADDRESS"]:
    294       data = ":".join(x.encode("hex") for x in nla_data)
    295     else:
    296       data = nla_data
    297 
    298     return name, data
    299 
    300   def __init__(self):
    301     super(IPRoute, self).__init__()
    302 
    303   def _AddressFamily(self, version):
    304     return {4: socket.AF_INET, 6: socket.AF_INET6}[version]
    305 
    306   def _SendNlRequest(self, command, data, flags=0):
    307     """Sends a netlink request and expects an ack."""
    308 
    309     flags |= NLM_F_REQUEST
    310     if CommandVerb(command) != "GET":
    311       flags |= NLM_F_ACK
    312     if CommandVerb(command) == "NEW":
    313       if not flags & NLM_F_REPLACE:
    314         flags |= (NLM_F_EXCL | NLM_F_CREATE)
    315 
    316     super(IPRoute, self)._SendNlRequest(command, data, flags)
    317 
    318   def _Rule(self, version, is_add, rule_type, table, match_nlattr, priority):
    319     """Python equivalent of "ip rule <add|del> <match_cond> lookup <table>".
    320 
    321     Args:
    322       version: An integer, 4 or 6.
    323       is_add: True to add a rule, False to delete it.
    324       rule_type: Type of rule, e.g., RTN_UNICAST or RTN_UNREACHABLE.
    325       table: If nonzero, rule looks up this table.
    326       match_nlattr: A blob of struct nlattrs that express the match condition.
    327         If None, match everything.
    328       priority: An integer, the priority.
    329 
    330     Raises:
    331       IOError: If the netlink request returns an error.
    332       ValueError: If the kernel's response could not be parsed.
    333     """
    334     # Create a struct rtmsg specifying the table and the given match attributes.
    335     family = self._AddressFamily(version)
    336     rtmsg = RTMsg((family, 0, 0, 0, RT_TABLE_UNSPEC,
    337                    RTPROT_STATIC, RT_SCOPE_UNIVERSE, rule_type, 0)).Pack()
    338     rtmsg += self._NlAttrU32(FRA_PRIORITY, priority)
    339     if match_nlattr:
    340       rtmsg += match_nlattr
    341     if table:
    342       rtmsg += self._NlAttrU32(FRA_TABLE, table)
    343 
    344     # Create a netlink request containing the rtmsg.
    345     command = RTM_NEWRULE if is_add else RTM_DELRULE
    346     self._SendNlRequest(command, rtmsg)
    347 
    348   def DeleteRulesAtPriority(self, version, priority):
    349     family = self._AddressFamily(version)
    350     rtmsg = RTMsg((family, 0, 0, 0, RT_TABLE_UNSPEC,
    351                    RTPROT_STATIC, RT_SCOPE_UNIVERSE, RTN_UNICAST, 0)).Pack()
    352     rtmsg += self._NlAttrU32(FRA_PRIORITY, priority)
    353     while True:
    354       try:
    355         self._SendNlRequest(RTM_DELRULE, rtmsg)
    356       except IOError, e:
    357         if e.errno == -errno.ENOENT:
    358           break
    359         else:
    360           raise
    361 
    362   def FwmarkRule(self, version, is_add, fwmark, table, priority):
    363     nlattr = self._NlAttrU32(FRA_FWMARK, fwmark)
    364     return self._Rule(version, is_add, RTN_UNICAST, table, nlattr, priority)
    365 
    366   def IifRule(self, version, is_add, iif, table, priority):
    367     nlattr = self._NlAttrInterfaceName(FRA_IIFNAME, iif)
    368     return self._Rule(version, is_add, RTN_UNICAST, table, nlattr, priority)
    369 
    370   def OifRule(self, version, is_add, oif, table, priority):
    371     nlattr = self._NlAttrInterfaceName(FRA_OIFNAME, oif)
    372     return self._Rule(version, is_add, RTN_UNICAST, table, nlattr, priority)
    373 
    374   def UidRangeRule(self, version, is_add, start, end, table, priority):
    375     nlattr = (self._NlAttrInterfaceName(FRA_IIFNAME, "lo") +
    376               self._NlAttrU32(FRA_UID_START, start) +
    377               self._NlAttrU32(FRA_UID_END, end))
    378     return self._Rule(version, is_add, RTN_UNICAST, table, nlattr, priority)
    379 
    380   def UnreachableRule(self, version, is_add, priority):
    381     return self._Rule(version, is_add, RTN_UNREACHABLE, None, None, priority)
    382 
    383   def DefaultRule(self, version, is_add, table, priority):
    384     return self.FwmarkRule(version, is_add, 0, table, priority)
    385 
    386   def CommandToString(self, command, data):
    387     try:
    388       name = CommandName(command)
    389       subject = CommandSubject(command)
    390       struct_type = {
    391           "ADDR": IfAddrMsg,
    392           "LINK": IfinfoMsg,
    393           "NEIGH": NdMsg,
    394           "ROUTE": RTMsg,
    395           "RULE": RTMsg,
    396       }[subject]
    397       parsed = self._ParseNLMsg(data, struct_type)
    398       return "%s %s" % (name, str(parsed))
    399     except IndexError:
    400       raise ValueError("Don't know how to print command type %s" % name)
    401 
    402   def MaybeDebugCommand(self, command, data):
    403     subject = CommandSubject(command)
    404     if "ALL" not in self.NL_DEBUG and subject not in self.NL_DEBUG:
    405       return
    406     print self.CommandToString(command, data)
    407 
    408   def MaybeDebugMessage(self, message):
    409     hdr = NLMsgHdr(message)
    410     self.MaybeDebugCommand(hdr.type, message)
    411 
    412   def PrintMessage(self, message):
    413     hdr = NLMsgHdr(message)
    414     print self.CommandToString(hdr.type, message)
    415 
    416   def DumpRules(self, version):
    417     """Returns the IP rules for the specified IP version."""
    418     # Create a struct rtmsg specifying the table and the given match attributes.
    419     family = self._AddressFamily(version)
    420     rtmsg = RTMsg((family, 0, 0, 0, 0, 0, 0, 0, 0))
    421     return self._Dump(RTM_GETRULE, rtmsg, RTMsg, "")
    422 
    423   def DumpLinks(self):
    424     ifinfomsg = IfinfoMsg((0, 0, 0, 0, 0, 0))
    425     return self._Dump(RTM_GETLINK, ifinfomsg, IfinfoMsg, "")
    426 
    427   def _Address(self, version, command, addr, prefixlen, flags, scope, ifindex):
    428     """Adds or deletes an IP address."""
    429     family = self._AddressFamily(version)
    430     ifaddrmsg = IfAddrMsg((family, prefixlen, flags, scope, ifindex)).Pack()
    431     ifaddrmsg += self._NlAttrIPAddress(IFA_ADDRESS, family, addr)
    432     if version == 4:
    433       ifaddrmsg += self._NlAttrIPAddress(IFA_LOCAL, family, addr)
    434     self._SendNlRequest(command, ifaddrmsg)
    435 
    436   def AddAddress(self, address, prefixlen, ifindex):
    437     self._Address(6 if ":" in address else 4,
    438                   RTM_NEWADDR, address, prefixlen,
    439                   IFA_F_PERMANENT, RT_SCOPE_UNIVERSE, ifindex)
    440 
    441   def DelAddress(self, address, prefixlen, ifindex):
    442     self._Address(6 if ":" in address else 4,
    443                   RTM_DELADDR, address, prefixlen, 0, 0, ifindex)
    444 
    445   def GetAddress(self, address, ifindex=0):
    446     """Returns an ifaddrmsg for the requested address."""
    447     if ":" not in address:
    448       # The address is likely an IPv4 address.  RTM_GETADDR without the
    449       # NLM_F_DUMP flag is not supported by the kernel.  We do not currently
    450       # implement parsing dump results.
    451       raise NotImplementedError("IPv4 RTM_GETADDR not implemented.")
    452     self._Address(6, RTM_GETADDR, address, 0, 0, RT_SCOPE_UNIVERSE, ifindex)
    453     return self._GetMsg(IfAddrMsg)
    454 
    455   def _Route(self, version, command, table, dest, prefixlen, nexthop, dev,
    456              mark, uid):
    457     """Adds, deletes, or queries a route."""
    458     family = self._AddressFamily(version)
    459     scope = RT_SCOPE_UNIVERSE if nexthop else RT_SCOPE_LINK
    460     rtmsg = RTMsg((family, prefixlen, 0, 0, RT_TABLE_UNSPEC,
    461                    RTPROT_STATIC, scope, RTN_UNICAST, 0)).Pack()
    462     if command == RTM_NEWROUTE and not table:
    463       # Don't allow setting routes in table 0, since its behaviour is confusing
    464       # and differs between IPv4 and IPv6.
    465       raise ValueError("Cowardly refusing to add a route to table 0")
    466     if table:
    467       rtmsg += self._NlAttrU32(FRA_TABLE, table)
    468     if dest != "default":  # The default is the default route.
    469       rtmsg += self._NlAttrIPAddress(RTA_DST, family, dest)
    470     if nexthop:
    471       rtmsg += self._NlAttrIPAddress(RTA_GATEWAY, family, nexthop)
    472     if dev:
    473       rtmsg += self._NlAttrU32(RTA_OIF, dev)
    474     if mark is not None:
    475       rtmsg += self._NlAttrU32(RTA_MARK, mark)
    476     if uid is not None:
    477       rtmsg += self._NlAttrU32(RTA_UID, uid)
    478     self._SendNlRequest(command, rtmsg)
    479 
    480   def AddRoute(self, version, table, dest, prefixlen, nexthop, dev):
    481     self._Route(version, RTM_NEWROUTE, table, dest, prefixlen, nexthop, dev,
    482                 None, None)
    483 
    484   def DelRoute(self, version, table, dest, prefixlen, nexthop, dev):
    485     self._Route(version, RTM_DELROUTE, table, dest, prefixlen, nexthop, dev,
    486                 None, None)
    487 
    488   def GetRoutes(self, dest, oif, mark, uid):
    489     version = 6 if ":" in dest else 4
    490     prefixlen = {4: 32, 6: 128}[version]
    491     self._Route(version, RTM_GETROUTE, 0, dest, prefixlen, None, oif, mark, uid)
    492     data = self._Recv()
    493     # The response will either be an error or a list of routes.
    494     if NLMsgHdr(data).type == NLMSG_ERROR:
    495       self._ParseAck(data)
    496     routes = self._GetMsgList(RTMsg, data, False)
    497     return routes
    498 
    499   def _Neighbour(self, version, is_add, addr, lladdr, dev, state, flags=0):
    500     """Adds or deletes a neighbour cache entry."""
    501     family = self._AddressFamily(version)
    502 
    503     # Convert the link-layer address to a raw byte string.
    504     if is_add and lladdr:
    505       lladdr = lladdr.split(":")
    506       if len(lladdr) != 6:
    507         raise ValueError("Invalid lladdr %s" % ":".join(lladdr))
    508       lladdr = "".join(chr(int(hexbyte, 16)) for hexbyte in lladdr)
    509 
    510     ndmsg = NdMsg((family, dev, state, 0, RTN_UNICAST)).Pack()
    511     ndmsg += self._NlAttrIPAddress(NDA_DST, family, addr)
    512     if is_add and lladdr:
    513       ndmsg += self._NlAttr(NDA_LLADDR, lladdr)
    514     command = RTM_NEWNEIGH if is_add else RTM_DELNEIGH
    515     self._SendNlRequest(command, ndmsg, flags)
    516 
    517   def AddNeighbour(self, version, addr, lladdr, dev):
    518     self._Neighbour(version, True, addr, lladdr, dev, NUD_PERMANENT)
    519 
    520   def DelNeighbour(self, version, addr, lladdr, dev):
    521     self._Neighbour(version, False, addr, lladdr, dev, 0)
    522 
    523   def UpdateNeighbour(self, version, addr, lladdr, dev, state):
    524     self._Neighbour(version, True, addr, lladdr, dev, state,
    525                     flags=NLM_F_REPLACE)
    526 
    527   def DumpNeighbours(self, version):
    528     ndmsg = NdMsg((self._AddressFamily(version), 0, 0, 0, 0))
    529     return self._Dump(RTM_GETNEIGH, ndmsg, NdMsg, "")
    530 
    531   def ParseNeighbourMessage(self, msg):
    532     msg, _ = self._ParseNLMsg(msg, NdMsg)
    533     return msg
    534 
    535 
    536 if __name__ == "__main__":
    537   iproute = IPRoute()
    538   iproute.DEBUG = True
    539   iproute.DumpRules(6)
    540   iproute.DumpLinks()
    541   print iproute.GetRoutes("2001:4860:4860::8888", 0, 0, None)
    542