xref: /aosp_15_r20/kernel/tests/net/test/anycast_test.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 Workerimport os
18*2f2c4c7aSAndroid Build Coastguard Workerfrom socket import *  # pylint: disable=wildcard-import
19*2f2c4c7aSAndroid Build Coastguard Workerimport threading
20*2f2c4c7aSAndroid Build Coastguard Workerimport time
21*2f2c4c7aSAndroid Build Coastguard Workerimport unittest
22*2f2c4c7aSAndroid Build Coastguard Worker
23*2f2c4c7aSAndroid Build Coastguard Workerimport cstruct
24*2f2c4c7aSAndroid Build Coastguard Workerimport multinetwork_base
25*2f2c4c7aSAndroid Build Coastguard Workerimport net_test
26*2f2c4c7aSAndroid Build Coastguard Worker
27*2f2c4c7aSAndroid Build Coastguard WorkerIPV6_JOIN_ANYCAST = 27
28*2f2c4c7aSAndroid Build Coastguard WorkerIPV6_LEAVE_ANYCAST = 28
29*2f2c4c7aSAndroid Build Coastguard Worker
30*2f2c4c7aSAndroid Build Coastguard Worker# pylint: disable=invalid-name
31*2f2c4c7aSAndroid Build Coastguard WorkerIPv6Mreq = cstruct.Struct("IPv6Mreq", "=16si", "multiaddr ifindex")
32*2f2c4c7aSAndroid Build Coastguard Worker
33*2f2c4c7aSAndroid Build Coastguard Worker
34*2f2c4c7aSAndroid Build Coastguard Worker_CLOSE_HUNG = False
35*2f2c4c7aSAndroid Build Coastguard Worker
36*2f2c4c7aSAndroid Build Coastguard Worker
37*2f2c4c7aSAndroid Build Coastguard Workerdef CauseOops():
38*2f2c4c7aSAndroid Build Coastguard Worker  with open("/proc/sysrq-trigger", "w") as trigger:
39*2f2c4c7aSAndroid Build Coastguard Worker    trigger.write("c")
40*2f2c4c7aSAndroid Build Coastguard Worker
41*2f2c4c7aSAndroid Build Coastguard Worker
42*2f2c4c7aSAndroid Build Coastguard Workerclass CloseFileDescriptorThread(threading.Thread):
43*2f2c4c7aSAndroid Build Coastguard Worker
44*2f2c4c7aSAndroid Build Coastguard Worker  def __init__(self, fd):
45*2f2c4c7aSAndroid Build Coastguard Worker    super(CloseFileDescriptorThread, self).__init__()
46*2f2c4c7aSAndroid Build Coastguard Worker    self.daemon = True
47*2f2c4c7aSAndroid Build Coastguard Worker    self._fd = fd
48*2f2c4c7aSAndroid Build Coastguard Worker    self.finished = False
49*2f2c4c7aSAndroid Build Coastguard Worker
50*2f2c4c7aSAndroid Build Coastguard Worker  def run(self):
51*2f2c4c7aSAndroid Build Coastguard Worker    global _CLOSE_HUNG
52*2f2c4c7aSAndroid Build Coastguard Worker    _CLOSE_HUNG = True
53*2f2c4c7aSAndroid Build Coastguard Worker    self._fd.close()
54*2f2c4c7aSAndroid Build Coastguard Worker    _CLOSE_HUNG = False
55*2f2c4c7aSAndroid Build Coastguard Worker    self.finished = True
56*2f2c4c7aSAndroid Build Coastguard Worker
57*2f2c4c7aSAndroid Build Coastguard Worker
58*2f2c4c7aSAndroid Build Coastguard Workerclass AnycastTest(multinetwork_base.MultiNetworkBaseTest):
59*2f2c4c7aSAndroid Build Coastguard Worker  """Tests for IPv6 anycast addresses.
60*2f2c4c7aSAndroid Build Coastguard Worker
61*2f2c4c7aSAndroid Build Coastguard Worker  Relevant kernel commits:
62*2f2c4c7aSAndroid Build Coastguard Worker    upstream net-next:
63*2f2c4c7aSAndroid Build Coastguard Worker      381f4dc ipv6: clean up anycast when an interface is destroyed
64*2f2c4c7aSAndroid Build Coastguard Worker
65*2f2c4c7aSAndroid Build Coastguard Worker    android-3.10:
66*2f2c4c7aSAndroid Build Coastguard Worker      86a47ad ipv6: clean up anycast when an interface is destroyed
67*2f2c4c7aSAndroid Build Coastguard Worker  """
68*2f2c4c7aSAndroid Build Coastguard Worker  _TEST_NETID = 123
69*2f2c4c7aSAndroid Build Coastguard Worker
70*2f2c4c7aSAndroid Build Coastguard Worker  def AnycastSetsockopt(self, s, is_add, netid, addr):
71*2f2c4c7aSAndroid Build Coastguard Worker    ifindex = self.ifindices[netid]
72*2f2c4c7aSAndroid Build Coastguard Worker    self.assertTrue(ifindex)
73*2f2c4c7aSAndroid Build Coastguard Worker    ipv6mreq = IPv6Mreq((addr, ifindex))
74*2f2c4c7aSAndroid Build Coastguard Worker    option = IPV6_JOIN_ANYCAST if is_add else IPV6_LEAVE_ANYCAST
75*2f2c4c7aSAndroid Build Coastguard Worker    s.setsockopt(IPPROTO_IPV6, option, ipv6mreq.Pack())
76*2f2c4c7aSAndroid Build Coastguard Worker
77*2f2c4c7aSAndroid Build Coastguard Worker  def testAnycastNetdeviceUnregister(self):
78*2f2c4c7aSAndroid Build Coastguard Worker    netid = self._TEST_NETID
79*2f2c4c7aSAndroid Build Coastguard Worker    self.assertNotIn(netid, self.tuns)
80*2f2c4c7aSAndroid Build Coastguard Worker    self.tuns[netid] = self.CreateTunInterface(netid)
81*2f2c4c7aSAndroid Build Coastguard Worker    self.SendRA(netid)
82*2f2c4c7aSAndroid Build Coastguard Worker    iface = self.GetInterfaceName(netid)
83*2f2c4c7aSAndroid Build Coastguard Worker    self.ifindices[netid] = net_test.GetInterfaceIndex(iface)
84*2f2c4c7aSAndroid Build Coastguard Worker
85*2f2c4c7aSAndroid Build Coastguard Worker    s = socket(AF_INET6, SOCK_DGRAM, 0)
86*2f2c4c7aSAndroid Build Coastguard Worker    addr = self.MyAddress(6, netid)
87*2f2c4c7aSAndroid Build Coastguard Worker    self.assertIsNotNone(addr)
88*2f2c4c7aSAndroid Build Coastguard Worker
89*2f2c4c7aSAndroid Build Coastguard Worker    addr = inet_pton(AF_INET6, addr)
90*2f2c4c7aSAndroid Build Coastguard Worker    addr = addr[:8] + os.urandom(8)
91*2f2c4c7aSAndroid Build Coastguard Worker    self.AnycastSetsockopt(s, True, netid, addr)
92*2f2c4c7aSAndroid Build Coastguard Worker
93*2f2c4c7aSAndroid Build Coastguard Worker    # Close the tun fd in the background.
94*2f2c4c7aSAndroid Build Coastguard Worker    # This will hang if the kernel has the bug.
95*2f2c4c7aSAndroid Build Coastguard Worker    thread = CloseFileDescriptorThread(self.tuns[netid])
96*2f2c4c7aSAndroid Build Coastguard Worker    thread.start()
97*2f2c4c7aSAndroid Build Coastguard Worker    # Wait up to 3 seconds for the thread to finish, but
98*2f2c4c7aSAndroid Build Coastguard Worker    # continue and fail the test if the thread hangs.
99*2f2c4c7aSAndroid Build Coastguard Worker
100*2f2c4c7aSAndroid Build Coastguard Worker    # For kernels with MPTCP ported, closing tun interface need more
101*2f2c4c7aSAndroid Build Coastguard Worker    # than 0.5 sec. DAD procedure within MPTCP fullmesh module takes
102*2f2c4c7aSAndroid Build Coastguard Worker    # more time, because duplicate address-timer takes a refcount
103*2f2c4c7aSAndroid Build Coastguard Worker    # on the IPv6-address, preventing it from getting closed.
104*2f2c4c7aSAndroid Build Coastguard Worker    thread.join(3)
105*2f2c4c7aSAndroid Build Coastguard Worker
106*2f2c4c7aSAndroid Build Coastguard Worker    # Make teardown work.
107*2f2c4c7aSAndroid Build Coastguard Worker    del self.tuns[netid]
108*2f2c4c7aSAndroid Build Coastguard Worker    # Check that the interface is gone.
109*2f2c4c7aSAndroid Build Coastguard Worker    try:
110*2f2c4c7aSAndroid Build Coastguard Worker      self.assertIsNone(self.MyAddress(6, netid))
111*2f2c4c7aSAndroid Build Coastguard Worker    finally:
112*2f2c4c7aSAndroid Build Coastguard Worker      # This doesn't seem to help, but still.
113*2f2c4c7aSAndroid Build Coastguard Worker      self.AnycastSetsockopt(s, False, netid, addr)
114*2f2c4c7aSAndroid Build Coastguard Worker    self.assertTrue(thread.finished)
115*2f2c4c7aSAndroid Build Coastguard Worker    s.close()
116*2f2c4c7aSAndroid Build Coastguard Worker
117*2f2c4c7aSAndroid Build Coastguard Worker
118*2f2c4c7aSAndroid Build Coastguard Workerif __name__ == "__main__":
119*2f2c4c7aSAndroid Build Coastguard Worker  unittest.main(exit=False)
120*2f2c4c7aSAndroid Build Coastguard Worker  if _CLOSE_HUNG:
121*2f2c4c7aSAndroid Build Coastguard Worker    time.sleep(3)
122*2f2c4c7aSAndroid Build Coastguard Worker    CauseOops()
123