Improve the dump code.

1. Make it generic and not tied to RTMsg only.
2. Support dumps that are spread across multiple recv calls.

Change-Id: Ifad803d80cc5085dd2fe4e8b5fb555d9459bd5ae
diff --git a/tests/net_test/iproute.py b/tests/net_test/iproute.py
index e75cd7a..0ac7222 100644
--- a/tests/net_test/iproute.py
+++ b/tests/net_test/iproute.py
@@ -460,10 +460,10 @@
     data = data[attrlen:]
     return (nlmsg, attributes), data
 
-  def _GetRTMsgList(self, data, expect_done):
+  def _GetMsgList(self, msgtype, data, expect_done):
     out = []
     while data:
-      msg, data = self._ParseNLMsg(data, RTMsg)
+      msg, data = self._ParseNLMsg(data, msgtype)
       if msg is None:
         break
       out.append(msg)
@@ -488,21 +488,33 @@
     except KeyError:
       raise ValueError("Don't know how to print command type %s" % name)
 
+  def _Dump(self, command, msg, msgtype):
+    """Sends a dump request and returns a list of decoded messages."""
+    # Create a netlink dump request containing the msg.
+    flags = NLM_F_DUMP | NLM_F_REQUEST
+    length = len(NLMsgHdr) + len(msg)
+    nlmsghdr = NLMsgHdr((length, command, flags, self.seq, self.pid))
+
+    # Send the request.
+    self._Send(nlmsghdr.Pack() + msg.Pack())
+
+    # Keep reading netlink messages until we get a NLMSG_DONE.
+    out = []
+    while True:
+      data = self._Recv()
+      response_type = NLMsgHdr(data).type
+      if response_type == NLMSG_DONE:
+        break
+      out.extend(self._GetMsgList(msgtype, data, False))
+
+    return out
+
   def DumpRules(self, version):
     """Returns the IP rules for the specified IP version."""
     # Create a struct rtmsg specifying the table and the given match attributes.
     family = self._AddressFamily(version)
     rtmsg = RTMsg((family, 0, 0, 0, 0, 0, 0, 0, 0))
-
-    # Create a netlink dump request containing the rtmsg.
-    command = RTM_GETRULE
-    flags = NLM_F_DUMP | NLM_F_REQUEST
-    length = len(NLMsgHdr) + len(rtmsg)
-    nlmsghdr = NLMsgHdr((length, command, flags, self.seq, self.pid))
-
-    self._Send(nlmsghdr.Pack() + rtmsg.Pack())
-    data = self._Recv()
-    return self._GetRTMsgList(data, True)
+    return self._Dump(RTM_GETRULE, rtmsg, RTMsg)
 
   def _Address(self, version, command, addr, prefixlen, flags, scope, ifindex):
     """Adds or deletes an IP address."""
@@ -576,7 +588,7 @@
     # The response will either be an error or a list of routes.
     if NLMsgHdr(data).type == NLMSG_ERROR:
       self._ParseAck(data)
-    routes = self._GetRTMsgList(data, False)
+    routes = self._GetMsgList(RTMsg, data, False)
     return routes
 
   def _Neighbour(self, version, is_add, addr, lladdr, dev, state):