PageRenderTime 52ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/tests/net_test/neighbour_test.py

https://gitlab.com/cde/debian_android-tools_android-platform-system-extras
Python | 297 lines | 190 code | 52 blank | 55 comment | 27 complexity | 4de2de05c36456452d4e9414db2266ab MD5 | raw file
  1. #!/usr/bin/python
  2. #
  3. # Copyright 2015 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. import errno
  17. import random
  18. from socket import * # pylint: disable=wildcard-import
  19. import time
  20. import unittest
  21. from scapy import all as scapy
  22. import multinetwork_base
  23. import net_test
  24. RTMGRP_NEIGH = 4
  25. NUD_INCOMPLETE = 0x01
  26. NUD_REACHABLE = 0x02
  27. NUD_STALE = 0x04
  28. NUD_DELAY = 0x08
  29. NUD_PROBE = 0x10
  30. NUD_FAILED = 0x20
  31. NUD_PERMANENT = 0x80
  32. # TODO: Support IPv4.
  33. class NeighbourTest(multinetwork_base.MultiNetworkBaseTest):
  34. # Set a 100-ms retrans timer so we can test for ND retransmits without
  35. # waiting too long. Apparently this cannot go below 500ms.
  36. RETRANS_TIME_MS = 500
  37. # This can only be in seconds, so 1000 is the minimum.
  38. DELAY_TIME_MS = 1000
  39. # Unfortunately, this must be above the delay timer or the kernel ND code will
  40. # not behave correctly (e.g., go straight from REACHABLE into DELAY). This is
  41. # is fuzzed by the kernel from 0.5x to 1.5x of its value, so we need a value
  42. # that's 2x the delay timer.
  43. REACHABLE_TIME_MS = 2 * DELAY_TIME_MS
  44. @classmethod
  45. def setUpClass(cls):
  46. super(NeighbourTest, cls).setUpClass()
  47. for netid in cls.tuns:
  48. iface = cls.GetInterfaceName(netid)
  49. # This can't be set in an RA.
  50. cls.SetSysctl(
  51. "/proc/sys/net/ipv6/neigh/%s/delay_first_probe_time" % iface,
  52. cls.DELAY_TIME_MS / 1000)
  53. def setUp(self):
  54. super(NeighbourTest, self).setUp()
  55. for netid in self.tuns:
  56. # Clear the ND cache entries for all routers, so each test starts with
  57. # the IPv6 default router in state STALE.
  58. addr = self._RouterAddress(netid, 6)
  59. ifindex = self.ifindices[netid]
  60. self.iproute.UpdateNeighbour(6, addr, None, ifindex, NUD_FAILED)
  61. # Configure IPv6 by sending an RA.
  62. self.SendRA(netid,
  63. retranstimer=self.RETRANS_TIME_MS,
  64. reachabletime=self.REACHABLE_TIME_MS)
  65. self.sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)
  66. self.sock.bind((0, RTMGRP_NEIGH))
  67. net_test.SetNonBlocking(self.sock)
  68. self.netid = random.choice(self.tuns.keys())
  69. self.ifindex = self.ifindices[self.netid]
  70. def GetNeighbour(self, addr):
  71. version = 6 if ":" in addr else 4
  72. for msg, args in self.iproute.DumpNeighbours(version):
  73. if args["NDA_DST"] == addr:
  74. return msg, args
  75. def GetNdEntry(self, addr):
  76. return self.GetNeighbour(addr)
  77. def CheckNoNdEvents(self):
  78. self.assertRaisesErrno(errno.EAGAIN, self.sock.recvfrom, 4096, MSG_PEEK)
  79. def assertNeighbourState(self, state, addr):
  80. self.assertEquals(state, self.GetNdEntry(addr)[0].state)
  81. def assertNeighbourAttr(self, addr, name, value):
  82. self.assertEquals(value, self.GetNdEntry(addr)[1][name])
  83. def ExpectNeighbourNotification(self, addr, state, attrs=None):
  84. msg = self.sock.recv(4096)
  85. msg, actual_attrs = self.iproute.ParseNeighbourMessage(msg)
  86. self.assertEquals(addr, actual_attrs["NDA_DST"])
  87. self.assertEquals(state, msg.state)
  88. if attrs:
  89. for name in attrs:
  90. self.assertEquals(attrs[name], actual_attrs[name])
  91. def ExpectProbe(self, is_unicast, addr):
  92. version = 6 if ":" in addr else 4
  93. if version == 6:
  94. llsrc = self.MyMacAddress(self.netid)
  95. if is_unicast:
  96. src = self.MyLinkLocalAddress(self.netid)
  97. dst = addr
  98. else:
  99. solicited = inet_pton(AF_INET6, addr)
  100. last3bytes = tuple([ord(b) for b in solicited[-3:]])
  101. dst = "ff02::1:ff%02x:%02x%02x" % last3bytes
  102. src = self.MyAddress(6, self.netid)
  103. expected = (
  104. scapy.IPv6(src=src, dst=dst) /
  105. scapy.ICMPv6ND_NS(tgt=addr) /
  106. scapy.ICMPv6NDOptSrcLLAddr(lladdr=llsrc)
  107. )
  108. msg = "%s probe" % ("Unicast" if is_unicast else "Multicast")
  109. self.ExpectPacketOn(self.netid, msg, expected)
  110. else:
  111. raise NotImplementedError
  112. def ExpectUnicastProbe(self, addr):
  113. self.ExpectProbe(True, addr)
  114. def ExpectMulticastNS(self, addr):
  115. self.ExpectProbe(False, addr)
  116. def ReceiveUnicastAdvertisement(self, addr, mac, srcaddr=None, dstaddr=None,
  117. S=1, O=0, R=1):
  118. version = 6 if ":" in addr else 4
  119. if srcaddr is None:
  120. srcaddr = addr
  121. if dstaddr is None:
  122. dstaddr = self.MyLinkLocalAddress(self.netid)
  123. if version == 6:
  124. packet = (
  125. scapy.Ether(src=mac, dst=self.MyMacAddress(self.netid)) /
  126. scapy.IPv6(src=srcaddr, dst=dstaddr) /
  127. scapy.ICMPv6ND_NA(tgt=addr, S=S, O=O, R=R) /
  128. scapy.ICMPv6NDOptDstLLAddr(lladdr=mac)
  129. )
  130. self.ReceiveEtherPacketOn(self.netid, packet)
  131. else:
  132. raise NotImplementedError
  133. def MonitorSleepMs(self, interval, addr):
  134. slept = 0
  135. while slept < interval:
  136. sleep_ms = min(100, interval - slept)
  137. time.sleep(sleep_ms / 1000.0)
  138. slept += sleep_ms
  139. print self.GetNdEntry(addr)
  140. def MonitorSleep(self, intervalseconds, addr):
  141. self.MonitorSleepMs(intervalseconds * 1000, addr)
  142. def SleepMs(self, ms):
  143. time.sleep(ms / 1000.0)
  144. def testNotifications(self):
  145. """Tests neighbour notifications.
  146. Relevant kernel commits:
  147. upstream net-next:
  148. 765c9c6 neigh: Better handling of transition to NUD_PROBE state
  149. 53385d2 neigh: Netlink notification for administrative NUD state change
  150. (only checked on kernel v3.13+, not on v3.10)
  151. android-3.10:
  152. e4a6d6b neigh: Better handling of transition to NUD_PROBE state
  153. android-3.18:
  154. 2011e72 neigh: Better handling of transition to NUD_PROBE state
  155. """
  156. router4 = self._RouterAddress(self.netid, 4)
  157. router6 = self._RouterAddress(self.netid, 6)
  158. self.assertNeighbourState(NUD_PERMANENT, router4)
  159. self.assertNeighbourState(NUD_STALE, router6)
  160. # Send a packet and check that we go into DELAY.
  161. routing_mode = random.choice(["mark", "oif", "uid"])
  162. s = self.BuildSocket(6, net_test.UDPSocket, self.netid, routing_mode)
  163. s.connect((net_test.IPV6_ADDR, 53))
  164. s.send(net_test.UDP_PAYLOAD)
  165. self.assertNeighbourState(NUD_DELAY, router6)
  166. # Wait for the probe interval, then check that we're in PROBE, and that the
  167. # kernel has notified us.
  168. self.SleepMs(self.DELAY_TIME_MS)
  169. self.ExpectNeighbourNotification(router6, NUD_PROBE)
  170. self.assertNeighbourState(NUD_PROBE, router6)
  171. self.ExpectUnicastProbe(router6)
  172. # Respond to the NS and verify we're in REACHABLE again.
  173. self.ReceiveUnicastAdvertisement(router6, self.RouterMacAddress(self.netid))
  174. self.assertNeighbourState(NUD_REACHABLE, router6)
  175. if net_test.LINUX_VERSION >= (3, 13, 0):
  176. # commit 53385d2 (v3.13) "neigh: Netlink notification for administrative
  177. # NUD state change" produces notifications for NUD_REACHABLE, but these
  178. # are not generated on earlier kernels.
  179. self.ExpectNeighbourNotification(router6, NUD_REACHABLE)
  180. # Wait until the reachable time has passed, and verify we're in STALE.
  181. self.SleepMs(self.REACHABLE_TIME_MS * 1.5)
  182. self.assertNeighbourState(NUD_STALE, router6)
  183. self.ExpectNeighbourNotification(router6, NUD_STALE)
  184. # Send a packet, and verify we go into DELAY and then to PROBE.
  185. s.send(net_test.UDP_PAYLOAD)
  186. self.assertNeighbourState(NUD_DELAY, router6)
  187. self.SleepMs(self.DELAY_TIME_MS)
  188. self.assertNeighbourState(NUD_PROBE, router6)
  189. self.ExpectNeighbourNotification(router6, NUD_PROBE)
  190. # Wait for the probes to time out, and expect a FAILED notification.
  191. self.assertNeighbourAttr(router6, "NDA_PROBES", 1)
  192. self.ExpectUnicastProbe(router6)
  193. self.SleepMs(self.RETRANS_TIME_MS)
  194. self.ExpectUnicastProbe(router6)
  195. self.assertNeighbourAttr(router6, "NDA_PROBES", 2)
  196. self.SleepMs(self.RETRANS_TIME_MS)
  197. self.ExpectUnicastProbe(router6)
  198. self.assertNeighbourAttr(router6, "NDA_PROBES", 3)
  199. self.SleepMs(self.RETRANS_TIME_MS)
  200. self.assertNeighbourState(NUD_FAILED, router6)
  201. self.ExpectNeighbourNotification(router6, NUD_FAILED, {"NDA_PROBES": 3})
  202. def testRepeatedProbes(self):
  203. router4 = self._RouterAddress(self.netid, 4)
  204. router6 = self._RouterAddress(self.netid, 6)
  205. routermac = self.RouterMacAddress(self.netid)
  206. self.assertNeighbourState(NUD_PERMANENT, router4)
  207. self.assertNeighbourState(NUD_STALE, router6)
  208. def ForceProbe(addr, mac):
  209. self.iproute.UpdateNeighbour(6, addr, None, self.ifindex, NUD_PROBE)
  210. self.assertNeighbourState(NUD_PROBE, addr)
  211. self.SleepMs(1) # TODO: Why is this necessary?
  212. self.assertNeighbourState(NUD_PROBE, addr)
  213. self.ExpectUnicastProbe(addr)
  214. self.ReceiveUnicastAdvertisement(addr, mac)
  215. self.assertNeighbourState(NUD_REACHABLE, addr)
  216. for _ in xrange(5):
  217. ForceProbe(router6, routermac)
  218. def testIsRouterFlag(self):
  219. router6 = self._RouterAddress(self.netid, 6)
  220. self.assertNeighbourState(NUD_STALE, router6)
  221. # Get into FAILED.
  222. ifindex = self.ifindices[self.netid]
  223. self.iproute.UpdateNeighbour(6, router6, None, ifindex, NUD_FAILED)
  224. self.ExpectNeighbourNotification(router6, NUD_FAILED)
  225. self.assertNeighbourState(NUD_FAILED, router6)
  226. time.sleep(1)
  227. # Send another packet and expect a multicast NS.
  228. routing_mode = random.choice(["mark", "oif", "uid"])
  229. s = self.BuildSocket(6, net_test.UDPSocket, self.netid, routing_mode)
  230. s.connect((net_test.IPV6_ADDR, 53))
  231. s.send(net_test.UDP_PAYLOAD)
  232. self.ExpectMulticastNS(router6)
  233. # Receive a unicast NA with the R flag set to 0.
  234. self.ReceiveUnicastAdvertisement(router6, self.RouterMacAddress(self.netid),
  235. srcaddr=self._RouterAddress(self.netid, 6),
  236. dstaddr=self.MyAddress(6, self.netid),
  237. S=1, O=0, R=0)
  238. # Expect that this takes us to REACHABLE.
  239. self.ExpectNeighbourNotification(router6, NUD_REACHABLE)
  240. self.assertNeighbourState(NUD_REACHABLE, router6)
  241. if __name__ == "__main__":
  242. unittest.main()