blob: 3205195c15db5cf99a8ce84a270d2694b835b7b2 [file] [log] [blame]
Yuyang Huangae57be02023-10-16 17:49:31 +09001/*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package android.net.apf
17
Yuyang Huangc11962e2024-02-14 20:37:06 +090018import android.net.apf.ApfCounterTracker.Counter
19import android.net.apf.ApfTestUtils.DROP
Yuyang Huang2fdba242024-02-06 14:52:22 +090020import android.net.apf.ApfTestUtils.MIN_PKT_SIZE
Yuyang Huangc11962e2024-02-14 20:37:06 +090021import android.net.apf.ApfTestUtils.PASS
22import android.net.apf.ApfTestUtils.assertDrop
Yuyang Huang2fdba242024-02-06 14:52:22 +090023import android.net.apf.ApfTestUtils.assertPass
Yuyang Huangc11962e2024-02-14 20:37:06 +090024import android.net.apf.ApfTestUtils.assertVerdict
Yuyang Huang2b402472024-02-13 16:31:55 +090025import android.net.apf.BaseApfGenerator.DROP_LABEL
Yuyang Huangbded8e32024-02-09 13:34:58 +090026import android.net.apf.BaseApfGenerator.IllegalInstructionException
Yuyang Huang12145c92024-02-09 07:20:15 +090027import android.net.apf.BaseApfGenerator.MIN_APF_VERSION
28import android.net.apf.BaseApfGenerator.MIN_APF_VERSION_IN_DEV
Yuyang Huang12145c92024-02-09 07:20:15 +090029import android.net.apf.BaseApfGenerator.Register.R0
30import android.net.apf.BaseApfGenerator.Register.R1
Yuyang Huangae57be02023-10-16 17:49:31 +090031import androidx.test.filters.SmallTest
32import androidx.test.runner.AndroidJUnit4
Yuyang Huangbcfa09b2024-02-20 11:20:47 +090033import com.android.net.module.util.Struct
34import com.android.net.module.util.structs.EthernetHeader
35import com.android.net.module.util.structs.Ipv4Header
36import com.android.net.module.util.structs.UdpHeader
37import java.nio.ByteBuffer
Yuyang Huangae57be02023-10-16 17:49:31 +090038import kotlin.test.assertContentEquals
Yuyang Huangc11962e2024-02-14 20:37:06 +090039import kotlin.test.assertEquals
Yuyang Huangce1493a2023-12-07 15:29:40 +090040import kotlin.test.assertFailsWith
Yuyang Huangae57be02023-10-16 17:49:31 +090041import org.junit.Test
42import org.junit.runner.RunWith
43
44/**
45 * Tests for APFv6 specific instructions.
46 */
47@RunWith(AndroidJUnit4::class)
48@SmallTest
49class ApfV5Test {
50
Yuyang Huang2283be72024-02-08 04:49:08 +090051 private val testPacket = byteArrayOf(1, 2, 3, 4, 5, 6, 7, 8,
52 9, 10, 11, 12, 13, 14, 15, 16)
53
Yuyang Huangae57be02023-10-16 17:49:31 +090054 @Test
Yuyang Huanga112cc82023-12-13 17:55:47 +090055 fun testDataInstructionMustComeFirst() {
Yuyang Huangd89cdbe2024-02-01 09:49:07 +090056 var gen = ApfV6Generator()
Yuyang Huanga112cc82023-12-13 17:55:47 +090057 gen.addAllocateR0()
58 assertFailsWith<IllegalInstructionException> { gen.addData(ByteArray(3) { 0x01 }) }
Yuyang Huang1e5bfaf2023-12-11 00:21:54 +090059 }
60
61 @Test
Yuyang Huang3ac843c2023-12-13 16:40:15 +090062 fun testApfInstructionEncodingSizeCheck() {
Yuyang Huangd89cdbe2024-02-01 09:49:07 +090063 var gen = ApfV6Generator()
Yuyang Huang3ac843c2023-12-13 16:40:15 +090064 assertFailsWith<IllegalArgumentException> { gen.addAllocate(65536) }
65 assertFailsWith<IllegalArgumentException> { gen.addAllocate(-1) }
Yuyang Huang293f7e72023-12-31 14:24:03 +090066 assertFailsWith<IllegalArgumentException> { gen.addDataCopy(-1, 1) }
67 assertFailsWith<IllegalArgumentException> { gen.addPacketCopy(-1, 1) }
68 assertFailsWith<IllegalArgumentException> { gen.addDataCopy(1, 256) }
69 assertFailsWith<IllegalArgumentException> { gen.addPacketCopy(1, 256) }
70 assertFailsWith<IllegalArgumentException> { gen.addDataCopy(1, -1) }
71 assertFailsWith<IllegalArgumentException> { gen.addPacketCopy(1, -1) }
Yuyang Huangd0390612024-01-01 16:21:16 +090072 assertFailsWith<IllegalArgumentException> { gen.addPacketCopyFromR0(256) }
73 assertFailsWith<IllegalArgumentException> { gen.addDataCopyFromR0(256) }
Yuyang Huang96697842024-01-02 21:53:48 +090074 assertFailsWith<IllegalArgumentException> { gen.addPacketCopyFromR0(-1) }
75 assertFailsWith<IllegalArgumentException> { gen.addDataCopyFromR0(-1) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +090076 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsQ(
Yuyang Huangaf0d3722024-01-12 13:38:44 +090077 byteArrayOf(1, 'A'.code.toByte(), 0, 0), 256, ApfV4Generator.DROP_LABEL) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +090078 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsQ(
Yuyang Huangaf0d3722024-01-12 13:38:44 +090079 byteArrayOf(1, 'a'.code.toByte(), 0, 0), 0x0c, ApfV4Generator.DROP_LABEL) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +090080 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsQ(
Yuyang Huangaf0d3722024-01-12 13:38:44 +090081 byteArrayOf(1, '.'.code.toByte(), 0, 0), 0x0c, ApfV4Generator.DROP_LABEL) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +090082 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsQ(
Yuyang Huangaf0d3722024-01-12 13:38:44 +090083 byteArrayOf(0, 0), 0xc0, ApfV4Generator.DROP_LABEL) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +090084 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsQ(
Yuyang Huangaf0d3722024-01-12 13:38:44 +090085 byteArrayOf(1, 'A'.code.toByte()), 0xc0, ApfV4Generator.DROP_LABEL) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +090086 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsQ(
87 byteArrayOf(64) + ByteArray(64) { 'A'.code.toByte() } + byteArrayOf(0, 0),
Yuyang Huangaf0d3722024-01-12 13:38:44 +090088 0xc0, ApfV4Generator.DROP_LABEL) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +090089 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsQ(
90 byteArrayOf(1, 'A'.code.toByte(), 1, 'B'.code.toByte(), 0),
Yuyang Huangaf0d3722024-01-12 13:38:44 +090091 0xc0, ApfV4Generator.DROP_LABEL) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +090092 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsQ(
93 byteArrayOf(1, 'A'.code.toByte(), 1, 'B'.code.toByte()),
Yuyang Huangaf0d3722024-01-12 13:38:44 +090094 0xc0, ApfV4Generator.DROP_LABEL) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +090095 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsQ(
Yuyang Huangaf0d3722024-01-12 13:38:44 +090096 byteArrayOf(1, 'A'.code.toByte(), 0, 0), 256, ApfV4Generator.DROP_LABEL) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +090097 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsQ(
Yuyang Huangaf0d3722024-01-12 13:38:44 +090098 byteArrayOf(1, 'a'.code.toByte(), 0, 0), 0x0c, ApfV4Generator.DROP_LABEL) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +090099 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsQ(
Yuyang Huangaf0d3722024-01-12 13:38:44 +0900100 byteArrayOf(1, '.'.code.toByte(), 0, 0), 0x0c, ApfV4Generator.DROP_LABEL) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900101 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsQ(
Yuyang Huangaf0d3722024-01-12 13:38:44 +0900102 byteArrayOf(0, 0), 0xc0, ApfV4Generator.DROP_LABEL) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900103 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsQ(
Yuyang Huangaf0d3722024-01-12 13:38:44 +0900104 byteArrayOf(1, 'A'.code.toByte()), 0xc0, ApfV4Generator.DROP_LABEL) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900105 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsQ(
106 byteArrayOf(64) + ByteArray(64) { 'A'.code.toByte() } + byteArrayOf(0, 0),
Yuyang Huangaf0d3722024-01-12 13:38:44 +0900107 0xc0, ApfV4Generator.DROP_LABEL) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900108 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsQ(
109 byteArrayOf(1, 'A'.code.toByte(), 1, 'B'.code.toByte(), 0),
Yuyang Huangaf0d3722024-01-12 13:38:44 +0900110 0xc0, ApfV4Generator.DROP_LABEL) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900111 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsQ(
112 byteArrayOf(1, 'A'.code.toByte(), 1, 'B'.code.toByte()),
Yuyang Huangaf0d3722024-01-12 13:38:44 +0900113 0xc0, ApfV4Generator.DROP_LABEL) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900114 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsA(
Yuyang Huangaf0d3722024-01-12 13:38:44 +0900115 byteArrayOf(1, 'a'.code.toByte(), 0, 0), ApfV4Generator.DROP_LABEL) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900116 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsA(
Yuyang Huangaf0d3722024-01-12 13:38:44 +0900117 byteArrayOf(1, '.'.code.toByte(), 0, 0), ApfV4Generator.DROP_LABEL) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900118 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsA(
Yuyang Huangaf0d3722024-01-12 13:38:44 +0900119 byteArrayOf(0, 0), ApfV4Generator.DROP_LABEL) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900120 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsA(
Yuyang Huangaf0d3722024-01-12 13:38:44 +0900121 byteArrayOf(1, 'A'.code.toByte()), ApfV4Generator.DROP_LABEL) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900122 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsA(
123 byteArrayOf(64) + ByteArray(64) { 'A'.code.toByte() } + byteArrayOf(0, 0),
Yuyang Huangaf0d3722024-01-12 13:38:44 +0900124 ApfV4Generator.DROP_LABEL) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900125 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsA(
126 byteArrayOf(1, 'A'.code.toByte(), 1, 'B'.code.toByte(), 0),
Yuyang Huangaf0d3722024-01-12 13:38:44 +0900127 ApfV4Generator.DROP_LABEL) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900128 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsA(
129 byteArrayOf(1, 'A'.code.toByte(), 1, 'B'.code.toByte()),
Yuyang Huangaf0d3722024-01-12 13:38:44 +0900130 ApfV4Generator.DROP_LABEL) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900131 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsA(
Yuyang Huangaf0d3722024-01-12 13:38:44 +0900132 byteArrayOf(1, 'a'.code.toByte(), 0, 0), ApfV4Generator.DROP_LABEL) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900133 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsA(
Yuyang Huangaf0d3722024-01-12 13:38:44 +0900134 byteArrayOf(1, '.'.code.toByte(), 0, 0), ApfV4Generator.DROP_LABEL) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900135 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsA(
Yuyang Huangaf0d3722024-01-12 13:38:44 +0900136 byteArrayOf(0, 0), ApfV4Generator.DROP_LABEL) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900137 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsA(
Yuyang Huangaf0d3722024-01-12 13:38:44 +0900138 byteArrayOf(1, 'A'.code.toByte()), ApfV4Generator.DROP_LABEL) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900139 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsA(
140 byteArrayOf(64) + ByteArray(64) { 'A'.code.toByte() } + byteArrayOf(0, 0),
Yuyang Huangaf0d3722024-01-12 13:38:44 +0900141 ApfV4Generator.DROP_LABEL) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900142 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsA(
143 byteArrayOf(1, 'A'.code.toByte(), 1, 'B'.code.toByte(), 0),
Yuyang Huangaf0d3722024-01-12 13:38:44 +0900144 ApfV4Generator.DROP_LABEL) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900145 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsA(
146 byteArrayOf(1, 'A'.code.toByte(), 1, 'B'.code.toByte()),
Yuyang Huangaf0d3722024-01-12 13:38:44 +0900147 ApfV4Generator.DROP_LABEL) }
Yuyang Huangce1493a2023-12-07 15:29:40 +0900148 }
149
150 @Test
Yuyang Huang2b402472024-02-13 16:31:55 +0900151 fun testValidateDnsNames() {
152 // '%' is a valid label character in mDNS subtype
Yuyang Huangb31cef22024-02-13 16:43:33 +0900153 // byte == 0xff means it is a '*' wildcard, which is a valid encoding.
Yuyang Huang2b402472024-02-13 16:31:55 +0900154 val program = ApfV6Generator().addJumpIfPktAtR0ContainDnsQ(
155 byteArrayOf(1, '%'.code.toByte(), 0, 0),
156 1,
157 DROP_LABEL)
Yuyang Huangb31cef22024-02-13 16:43:33 +0900158 .addJumpIfPktAtR0ContainDnsA(
159 byteArrayOf(0xff.toByte(), 1, 'B'.code.toByte(), 0, 0),
160 DROP_LABEL
161 )
Yuyang Huang2b402472024-02-13 16:31:55 +0900162 .generate()
163 }
164
165 @Test
Yuyang Huangae57be02023-10-16 17:49:31 +0900166 fun testApfInstructionsEncoding() {
Yuyang Huangafe7b652024-02-09 09:45:01 +0900167 val v4gen = ApfV4Generator<ApfV4Generator<BaseApfGenerator>>(MIN_APF_VERSION)
168 v4gen.addPass()
169 var program = v4gen.generate()
Yuyang Huangdcdb4442023-12-07 14:56:21 +0900170 // encoding PASS opcode: opcode=0, imm_len=0, R=0
Yuyang Huang1e5bfaf2023-12-11 00:21:54 +0900171 assertContentEquals(
172 byteArrayOf(encodeInstruction(opcode = 0, immLength = 0, register = 0)), program)
Yuyang Huang98b99f22024-01-29 06:35:27 +0900173 assertContentEquals(
174 listOf("0: pass"),
175 ApfJniUtils.disassembleApf(program).map { it.trim() } )
Yuyang Huangdcdb4442023-12-07 14:56:21 +0900176
Yuyang Huangafe7b652024-02-09 09:45:01 +0900177 var gen = ApfV6Generator()
Yuyang Huangce1493a2023-12-07 15:29:40 +0900178 gen.addDrop()
179 program = gen.generate()
180 // encoding DROP opcode: opcode=0, imm_len=0, R=1
Yuyang Huang1e5bfaf2023-12-11 00:21:54 +0900181 assertContentEquals(
182 byteArrayOf(encodeInstruction(opcode = 0, immLength = 0, register = 1)), program)
Yuyang Huang98b99f22024-01-29 06:35:27 +0900183 assertContentEquals(
184 listOf("0: drop"),
185 ApfJniUtils.disassembleApf(program).map { it.trim() } )
Yuyang Huang1e5bfaf2023-12-11 00:21:54 +0900186
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900187 gen = ApfV6Generator()
Yuyang Huang1e5bfaf2023-12-11 00:21:54 +0900188 gen.addCountAndPass(129)
189 program = gen.generate()
190 // encoding COUNT(PASS) opcode: opcode=0, imm_len=size_of(imm), R=0, imm=counterNumber
191 assertContentEquals(
192 byteArrayOf(encodeInstruction(opcode = 0, immLength = 1, register = 0),
193 0x81.toByte()), program)
Yuyang Huang98b99f22024-01-29 06:35:27 +0900194 assertContentEquals(
195 listOf("0: pass 129"),
196 ApfJniUtils.disassembleApf(program).map { it.trim() } )
Yuyang Huang1e5bfaf2023-12-11 00:21:54 +0900197
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900198 gen = ApfV6Generator()
Yuyang Huang1e5bfaf2023-12-11 00:21:54 +0900199 gen.addCountAndDrop(1000)
200 program = gen.generate()
201 // encoding COUNT(DROP) opcode: opcode=0, imm_len=size_of(imm), R=1, imm=counterNumber
202 assertContentEquals(
203 byteArrayOf(encodeInstruction(opcode = 0, immLength = 2, register = 1),
204 0x03, 0xe8.toByte()), program)
Yuyang Huang98b99f22024-01-29 06:35:27 +0900205 assertContentEquals(
206 listOf("0: drop 1000"),
207 ApfJniUtils.disassembleApf(program).map { it.trim() } )
Yuyang Huangce1493a2023-12-07 15:29:40 +0900208
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900209 gen = ApfV6Generator()
Yuyang Huang3ac843c2023-12-13 16:40:15 +0900210 gen.addAllocateR0()
211 gen.addAllocate(1500)
Yuyang Huangdcdb4442023-12-07 14:56:21 +0900212 program = gen.generate()
Yuyang Huang3ac843c2023-12-13 16:40:15 +0900213 // encoding ALLOC opcode: opcode=21(EXT opcode number), imm=36(TRANS opcode number).
214 // R=0 means length stored in R0. R=1 means the length stored in imm1.
215 assertContentEquals(byteArrayOf(
216 encodeInstruction(opcode = 21, immLength = 1, register = 0), 36,
217 encodeInstruction(opcode = 21, immLength = 1, register = 1), 36, 0x05,
218 0xDC.toByte()),
219 program)
Yuyang Huang626414e2024-01-29 06:52:57 +0900220 assertContentEquals(listOf("0: allocate r0", "2: allocate 1500"),
221 ApfJniUtils.disassembleApf(program).map { it.trim() })
Yuyang Huangae57be02023-10-16 17:49:31 +0900222
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900223 gen = ApfV6Generator()
Yuyang Huangfb803682024-02-20 17:52:27 +0900224 gen.addTransmitWithoutChecksum()
Yuyang Huang738fa6d2024-02-13 22:03:42 +0900225 gen.addTransmitL4(30, 40, 50, 256, true)
Yuyang Huangae57be02023-10-16 17:49:31 +0900226 program = gen.generate()
Maciej Żenczykowskidbf2f972024-02-09 23:01:04 -0800227 // encoding TRANSMIT opcode: opcode=21(EXT opcode number),
228 // imm=37(TRANSMIT opcode number),
Yuyang Huangfd74ce42023-12-12 20:10:45 +0900229 assertContentEquals(byteArrayOf(
Maciej Żenczykowskidbf2f972024-02-09 23:01:04 -0800230 encodeInstruction(opcode = 21, immLength = 1, register = 0),
231 37, 255.toByte(), 255.toByte(),
Yuyang Huang738fa6d2024-02-13 22:03:42 +0900232 encodeInstruction(opcode = 21, immLength = 1, register = 1), 37, 30, 40, 50, 1, 0
Yuyang Huangfd74ce42023-12-12 20:10:45 +0900233 ), program)
Yuyang Huang738fa6d2024-02-13 22:03:42 +0900234 assertContentEquals(listOf(
235 "0: transmit ip_ofs=255",
236 "4: transmitudp ip_ofs=30, csum_ofs=40, csum_start=50, partial_csum=0x0100",
237 ), ApfJniUtils.disassembleApf(program).map { it.trim() })
Yuyang Huang73c6d2d2023-10-19 13:32:37 +0900238
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900239 gen = ApfV6Generator()
Yuyang Huanga112cc82023-12-13 17:55:47 +0900240 val largeByteArray = ByteArray(256) { 0x01 }
241 gen.addData(largeByteArray)
242 program = gen.generate()
243 // encoding DATA opcode: opcode=14(JMP), R=1
244 assertContentEquals(byteArrayOf(
245 encodeInstruction(opcode = 14, immLength = 2, register = 1), 0x01, 0x00) +
246 largeByteArray, program)
Yuyang Huang937ba492024-02-04 07:20:32 +0900247 assertContentEquals(listOf("0: data 256, " + "01".repeat(256) ),
Yuyang Huangf97b28a2024-01-29 09:36:25 +0900248 ApfJniUtils.disassembleApf(program).map { it.trim() })
Yuyang Huanga112cc82023-12-13 17:55:47 +0900249
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900250 gen = ApfV6Generator()
Yuyang Huangadf69672024-01-02 10:18:11 +0900251 gen.addWriteU8(0x01)
252 gen.addWriteU16(0x0102)
253 gen.addWriteU32(0x01020304)
254 gen.addWriteU8(0x00)
255 gen.addWriteU8(0x80)
256 gen.addWriteU16(0x0000)
257 gen.addWriteU16(0x8000)
258 gen.addWriteU32(0x00000000)
259 gen.addWriteU32(0x80000000)
Yuyang Huang4ac891f2023-12-20 11:49:11 +0900260 program = gen.generate()
261 assertContentEquals(byteArrayOf(
262 encodeInstruction(24, 1, 0), 0x01,
263 encodeInstruction(24, 2, 0), 0x01, 0x02,
264 encodeInstruction(24, 4, 0), 0x01, 0x02, 0x03, 0x04,
265 encodeInstruction(24, 1, 0), 0x00,
266 encodeInstruction(24, 1, 0), 0x80.toByte(),
267 encodeInstruction(24, 2, 0), 0x00, 0x00,
268 encodeInstruction(24, 2, 0), 0x80.toByte(), 0x00,
269 encodeInstruction(24, 4, 0), 0x00, 0x00, 0x00, 0x00,
270 encodeInstruction(24, 4, 0), 0x80.toByte(), 0x00, 0x00,
271 0x00), program)
Yuyang Huang7affd672024-01-29 13:04:43 +0900272 assertContentEquals(listOf(
273 "0: write 0x01",
274 "2: write 0x0102",
275 "5: write 0x01020304",
276 "10: write 0x00",
277 "12: write 0x80",
278 "14: write 0x0000",
279 "17: write 0x8000",
280 "20: write 0x00000000",
281 "25: write 0x80000000"
Yuyang Huang15b45782024-01-18 07:19:11 +0900282 ),
Yuyang Huang7affd672024-01-29 13:04:43 +0900283 ApfJniUtils.disassembleApf(program).map { it.trim() })
Yuyang Huange84a9692024-01-01 11:49:49 +0900284
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900285 gen = ApfV6Generator()
Yuyang Huange84a9692024-01-01 11:49:49 +0900286 gen.addWriteU8(R0)
287 gen.addWriteU16(R0)
288 gen.addWriteU32(R0)
289 gen.addWriteU8(R1)
290 gen.addWriteU16(R1)
291 gen.addWriteU32(R1)
292 program = gen.generate()
293 assertContentEquals(byteArrayOf(
294 encodeInstruction(21, 1, 0), 38,
295 encodeInstruction(21, 1, 0), 39,
296 encodeInstruction(21, 1, 0), 40,
297 encodeInstruction(21, 1, 1), 38,
298 encodeInstruction(21, 1, 1), 39,
299 encodeInstruction(21, 1, 1), 40
300 ), program)
Yuyang Huangf0b46cb2024-01-30 03:37:17 +0900301 assertContentEquals(listOf(
302 "0: ewrite1 r0",
303 "2: ewrite2 r0",
304 "4: ewrite4 r0",
305 "6: ewrite1 r1",
306 "8: ewrite2 r1",
307 "10: ewrite4 r1"), ApfJniUtils.disassembleApf(program).map { it.trim() })
Yuyang Huang73c6d2d2023-10-19 13:32:37 +0900308
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900309 gen = ApfV6Generator()
Yuyang Huang293f7e72023-12-31 14:24:03 +0900310 gen.addDataCopy(0, 10)
311 gen.addDataCopy(1, 5)
312 gen.addPacketCopy(1000, 255)
313 program = gen.generate()
314 assertContentEquals(byteArrayOf(
315 encodeInstruction(25, 0, 1), 10,
316 encodeInstruction(25, 1, 1), 1, 5,
317 encodeInstruction(25, 2, 0),
318 0x03.toByte(), 0xe8.toByte(), 0xff.toByte(),
319 ), program)
Yuyang Huange8003982024-01-30 04:06:18 +0900320 assertContentEquals(listOf(
Yuyang Huangb2a93342024-02-07 06:32:00 +0900321 "0: datacopy src=0, len=10",
322 "2: datacopy src=1, len=5",
323 "5: pktcopy src=1000, len=255"
Yuyang Huanga699e542024-02-06 12:50:03 +0900324 ),
325 ApfJniUtils.disassembleApf(program).map { it.trim() })
Yuyang Huang293f7e72023-12-31 14:24:03 +0900326
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900327 gen = ApfV6Generator()
Yuyang Huangbed904a2024-01-30 11:22:49 +0900328 gen.addDataCopyFromR0(5)
Yuyang Huangd0390612024-01-01 16:21:16 +0900329 gen.addPacketCopyFromR0(5)
330 gen.addDataCopyFromR0LenR1()
Yuyang Huangbed904a2024-01-30 11:22:49 +0900331 gen.addPacketCopyFromR0LenR1()
Yuyang Huangd0390612024-01-01 16:21:16 +0900332 program = gen.generate()
333 assertContentEquals(byteArrayOf(
Yuyang Huangbed904a2024-01-30 11:22:49 +0900334 encodeInstruction(21, 1, 1), 41, 5,
Yuyang Huangd0390612024-01-01 16:21:16 +0900335 encodeInstruction(21, 1, 0), 41, 5,
336 encodeInstruction(21, 1, 1), 42,
Yuyang Huangbed904a2024-01-30 11:22:49 +0900337 encodeInstruction(21, 1, 0), 42,
Yuyang Huangd0390612024-01-01 16:21:16 +0900338 ), program)
Yuyang Huangbed904a2024-01-30 11:22:49 +0900339 assertContentEquals(listOf(
Yuyang Huanga699e542024-02-06 12:50:03 +0900340 "0: edatacopy src=r0, len=5",
341 "3: epktcopy src=r0, len=5",
342 "6: edatacopy src=r0, len=r1",
343 "8: epktcopy src=r0, len=r1"), ApfJniUtils.disassembleApf(program).map{ it.trim() })
Yuyang Huang0f49d0a2024-01-04 19:14:22 +0900344
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900345 gen = ApfV6Generator()
Yuyang Huangaf0d3722024-01-12 13:38:44 +0900346 gen.addJumpIfBytesAtR0Equal(byteArrayOf('a'.code.toByte()), ApfV4Generator.DROP_LABEL)
Yuyang Huang0f49d0a2024-01-04 19:14:22 +0900347 program = gen.generate()
348 assertContentEquals(
349 byteArrayOf(encodeInstruction(opcode = 20, immLength = 1, register = 1),
350 1, 1, 'a'.code.toByte()), program)
Yuyang Huangbffcf262024-02-04 07:52:48 +0900351 assertContentEquals(listOf(
Yuyang Huangb61b7342024-02-06 05:44:24 +0900352 "0: jbseq r0, 0x1, DROP, 61"),
Yuyang Huangbffcf262024-02-04 07:52:48 +0900353 ApfJniUtils.disassembleApf(program).map{ it.trim() })
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900354
355 val qnames = byteArrayOf(1, 'A'.code.toByte(), 1, 'B'.code.toByte(), 0, 0)
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900356 gen = ApfV6Generator()
Yuyang Huangaf0d3722024-01-12 13:38:44 +0900357 gen.addJumpIfPktAtR0DoesNotContainDnsQ(qnames, 0x0c, ApfV4Generator.DROP_LABEL)
358 gen.addJumpIfPktAtR0ContainDnsQ(qnames, 0x0c, ApfV4Generator.DROP_LABEL)
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900359 program = gen.generate()
360 assertContentEquals(byteArrayOf(
Yuyang Huang823351f2024-01-08 14:28:42 +0900361 encodeInstruction(21, 1, 0), 43, 11, 0x0c.toByte(),
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900362 ) + qnames + byteArrayOf(
Yuyang Huang823351f2024-01-08 14:28:42 +0900363 encodeInstruction(21, 1, 1), 43, 1, 0x0c.toByte(),
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900364 ) + qnames, program)
Yuyang Huang49ab8822024-02-04 09:39:00 +0900365 assertContentEquals(listOf(
Yuyang Huang1efe2fc2024-02-07 04:02:07 +0900366 "0: jdnsqne r0, DROP, 12, (1)A(1)B(0)(0)",
367 "10: jdnsqeq r0, DROP, 12, (1)A(1)B(0)(0)"),
Yuyang Huang49ab8822024-02-04 09:39:00 +0900368 ApfJniUtils.disassembleApf(program).map{ it.trim() })
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900369
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900370 gen = ApfV6Generator()
Yuyang Huang365fc3a2024-02-14 21:47:37 +0900371 gen.addJumpIfPktAtR0DoesNotContainDnsQSafe(qnames, 0x0c, ApfV4Generator.DROP_LABEL)
372 gen.addJumpIfPktAtR0ContainDnsQSafe(qnames, 0x0c, ApfV4Generator.DROP_LABEL)
373 program = gen.generate()
374 assertContentEquals(byteArrayOf(
375 encodeInstruction(21, 1, 0), 45, 11, 0x0c.toByte(),
376 ) + qnames + byteArrayOf(
377 encodeInstruction(21, 1, 1), 45, 1, 0x0c.toByte(),
378 ) + qnames, program)
379 assertContentEquals(listOf(
380 "0: jdnsqnesafe r0, DROP, 12, (1)A(1)B(0)(0)",
381 "10: jdnsqeqsafe r0, DROP, 12, (1)A(1)B(0)(0)"),
382 ApfJniUtils.disassembleApf(program).map{ it.trim() })
383
384 gen = ApfV6Generator()
Yuyang Huangaf0d3722024-01-12 13:38:44 +0900385 gen.addJumpIfPktAtR0DoesNotContainDnsA(qnames, ApfV4Generator.DROP_LABEL)
386 gen.addJumpIfPktAtR0ContainDnsA(qnames, ApfV4Generator.DROP_LABEL)
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900387 program = gen.generate()
388 assertContentEquals(byteArrayOf(
389 encodeInstruction(21, 1, 0), 44, 10,
390 ) + qnames + byteArrayOf(
391 encodeInstruction(21, 1, 1), 44, 1,
392 ) + qnames, program)
Yuyang Huang1efe2fc2024-02-07 04:02:07 +0900393 assertContentEquals(listOf(
394 "0: jdnsane r0, DROP, (1)A(1)B(0)(0)",
395 "9: jdnsaeq r0, DROP, (1)A(1)B(0)(0)"),
396 ApfJniUtils.disassembleApf(program).map{ it.trim() })
Yuyang Huang365fc3a2024-02-14 21:47:37 +0900397
398 gen = ApfV6Generator()
399 gen.addJumpIfPktAtR0DoesNotContainDnsASafe(qnames, ApfV4Generator.DROP_LABEL)
400 gen.addJumpIfPktAtR0ContainDnsASafe(qnames, ApfV4Generator.DROP_LABEL)
401 program = gen.generate()
402 assertContentEquals(byteArrayOf(
403 encodeInstruction(21, 1, 0), 46, 10,
404 ) + qnames + byteArrayOf(
405 encodeInstruction(21, 1, 1), 46, 1,
406 ) + qnames, program)
407 assertContentEquals(listOf(
408 "0: jdnsanesafe r0, DROP, (1)A(1)B(0)(0)",
409 "9: jdnsaeqsafe r0, DROP, (1)A(1)B(0)(0)"),
410 ApfJniUtils.disassembleApf(program).map{ it.trim() })
Yuyang Huangae57be02023-10-16 17:49:31 +0900411 }
412
Yuyang Huang2fdba242024-02-06 14:52:22 +0900413 @Test
414 fun testWriteToTxBuffer() {
Yuyang Huangbded8e32024-02-09 13:34:58 +0900415 var program = ApfV6Generator()
Yuyang Huang3fa07a72024-02-20 19:13:33 +0900416 .addAllocate(14)
Yuyang Huangb97aa962024-02-08 08:13:56 +0900417 .addWriteU8(0x01)
Yuyang Huang3fa07a72024-02-20 19:13:33 +0900418 .addWriteU16(0x0203)
419 .addWriteU32(0x04050607)
Yuyang Huangbded8e32024-02-09 13:34:58 +0900420 .addLoadImmediate(R0, 1)
421 .addWriteU8(R0)
422 .addLoadImmediate(R0, 0x0203)
423 .addWriteU16(R0)
424 .addLoadImmediate(R1, 0x04050607)
425 .addWriteU32(R1)
Yuyang Huangfb803682024-02-20 17:52:27 +0900426 .addTransmitWithoutChecksum()
Yuyang Huangbded8e32024-02-09 13:34:58 +0900427 .generate()
428 assertPass(MIN_APF_VERSION_IN_DEV, program, ByteArray(MIN_PKT_SIZE))
Yuyang Huang3fa07a72024-02-20 19:13:33 +0900429 assertContentEquals(byteArrayOf(0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x01, 0x02, 0x03,
430 0x04, 0x05, 0x06, 0x07), ApfJniUtils.getTransmittedPacket())
Yuyang Huang2fdba242024-02-06 14:52:22 +0900431 }
432
Yuyang Huang2283be72024-02-08 04:49:08 +0900433 @Test
434 fun testCopyToTxBuffer() {
Yuyang Huang10598932024-02-14 10:00:59 +0900435 var program = ApfV6Generator()
Yuyang Huang2283be72024-02-08 04:49:08 +0900436 .addData(byteArrayOf(33, 34, 35))
Yuyang Huang3fa07a72024-02-20 19:13:33 +0900437 .addAllocate(14)
438 .addDataCopy(2 /* src */, 2 /* len */)
439 .addDataCopy(4 /* src */, 1 /* len */)
440 .addPacketCopy(0 /* src */, 1 /* len */)
441 .addPacketCopy(1 /* src */, 3 /* len */)
442 .addLoadImmediate(R0, 2) // data copy offset
443 .addDataCopyFromR0(2 /* len */)
444 .addLoadImmediate(R0, 4) // data copy offset
445 .addLoadImmediate(R1, 1) // len
446 .addDataCopyFromR0LenR1()
447 .addLoadImmediate(R0, 0) // packet copy offset
448 .addPacketCopyFromR0(1 /* len */)
449 .addLoadImmediate(R0, 1) // packet copy offset
450 .addLoadImmediate(R1, 3) // len
451 .addPacketCopyFromR0LenR1()
Yuyang Huangfb803682024-02-20 17:52:27 +0900452 .addTransmitWithoutChecksum()
Yuyang Huang2283be72024-02-08 04:49:08 +0900453 .generate()
454 assertPass(MIN_APF_VERSION_IN_DEV, program, testPacket)
Yuyang Huang3fa07a72024-02-20 19:13:33 +0900455 assertContentEquals(byteArrayOf(33, 34, 35, 1, 2, 3, 4, 33, 34, 35, 1, 2, 3, 4),
456 ApfJniUtils.getTransmittedPacket())
Yuyang Huang2283be72024-02-08 04:49:08 +0900457 }
458
Yuyang Huangc11962e2024-02-14 20:37:06 +0900459 @Test
460 fun testPassDrop() {
461 var program = ApfV6Generator()
462 .addDrop()
463 .addPass()
464 .generate()
465 assertDrop(MIN_APF_VERSION_IN_DEV, program, testPacket)
466
467 var dataRegion = ByteArray(Counter.totalSize()) { 0 }
468 program = ApfV6Generator()
469 .addData(byteArrayOf())
470 .addCountAndDrop(Counter.DROPPED_ETH_BROADCAST.value())
471 .generate()
472 assertVerdict(MIN_APF_VERSION_IN_DEV, DROP, program, testPacket, dataRegion)
473 var counterMap = decodeCountersIntoMap(dataRegion)
474 assertEquals(mapOf<Counter, Long>(
475 Counter.TOTAL_PACKETS to 1,
476 Counter.DROPPED_ETH_BROADCAST to 1), counterMap)
477
478 dataRegion = ByteArray(Counter.totalSize()) { 0 }
479 program = ApfV6Generator()
480 .addData(byteArrayOf())
481 .addCountAndPass(Counter.PASSED_ARP.value())
482 .generate()
483 assertVerdict(MIN_APF_VERSION_IN_DEV, PASS, program, testPacket, dataRegion)
484 counterMap = decodeCountersIntoMap(dataRegion)
485 assertEquals(mapOf<Counter, Long>(
486 Counter.TOTAL_PACKETS to 1,
487 Counter.PASSED_ARP to 1), counterMap)
488 }
489
Yuyang Huang0e3b4cb2024-02-19 16:20:26 +0900490 @Test
491 fun testAllocateFailure() {
492 val program = ApfV6Generator()
493 .addData(byteArrayOf())
494 // allocate size: 65535 > sizeof(apf_test_buffer): 1514, trigger allocate failure.
495 .addAllocate(65535)
496 .addDrop()
497 .generate()
498 val dataRegion = ByteArray(Counter.totalSize()) { 0 }
499 assertVerdict(MIN_APF_VERSION_IN_DEV, PASS, program, testPacket, dataRegion)
500 val counterMap = decodeCountersIntoMap(dataRegion)
501 assertEquals(mapOf<Counter, Long>(
502 Counter.TOTAL_PACKETS to 1,
503 Counter.PASSED_ALLOCATE_FAILURE to 1), counterMap)
504 }
505
Yuyang Huang19df0482024-02-19 16:38:45 +0900506 @Test
507 fun testTransmitFailure() {
508 val program = ApfV6Generator()
509 .addData(byteArrayOf())
510 .addAllocate(14)
511 // len: 13 is less than ETH_HLEN, trigger transmit failure.
512 .addLoadImmediate(R0, 13)
513 .addStoreToMemory(R0, 10)
514 .addTransmitWithoutChecksum()
515 .addDrop()
516 .generate()
517 val dataRegion = ByteArray(Counter.totalSize()) { 0 }
518 assertVerdict(MIN_APF_VERSION_IN_DEV, PASS, program, testPacket, dataRegion)
519 val counterMap = decodeCountersIntoMap(dataRegion)
520 assertEquals(mapOf<Counter, Long>(
521 Counter.TOTAL_PACKETS to 1,
522 Counter.PASSED_TRANSMIT_FAILURE to 1), counterMap)
523 }
524
Yuyang Huangbcfa09b2024-02-20 11:20:47 +0900525 @Test
526 fun testTransmitL4() {
527 val etherIpv4UdpPacket = intArrayOf(
528 0x01, 0x00, 0x5e, 0x00, 0x00, 0xfb,
529 0x38, 0xca, 0x84, 0xb7, 0x7f, 0x16,
530 0x08, 0x00, // end of ethernet header
531 0x45,
532 0x04,
533 0x00, 0x3f,
534 0x43, 0xcd,
535 0x40, 0x00,
536 0xff,
537 0x11,
538 0x00, 0x00, // ipv4 checksum set to 0
539 0xc0, 0xa8, 0x01, 0x03,
540 0xe0, 0x00, 0x00, 0xfb, // end of ipv4 header
541 0x14, 0xe9,
542 0x14, 0xe9,
543 0x00, 0x2b,
544 0x00, 0x2b, // end of udp header. udp checksum set to udp (header + payload) size
545 0x00, 0x00, 0x84, 0x00, 0x00, 0x00,
546 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x62, 0x05, 0x6c, 0x6f, 0x63, 0x61, 0x6c,
547 0x00, 0x00, 0x01, 0x80, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x04, 0xc0, 0xa8, 0x01,
548 0x09,
549 ).map { it.toByte() }.toByteArray()
550 val program = ApfV6Generator()
551 .addData(etherIpv4UdpPacket)
552 .addAllocate(etherIpv4UdpPacket.size)
553 .addDataCopy(2 /* src */, etherIpv4UdpPacket.size /* len */)
554 .addTransmitL4(ETH_HLEN /* ipOfs */,
555 ETH_HLEN + IPV4_HLEN + 6 /* csumOfs */,
556 ETH_HLEN + IPV4_HLEN - 8 /* csumStart */,
557 IPPROTO_UDP /* partialCsum */,
558 true /* isUdp */)
559 .generate()
560 assertPass(MIN_APF_VERSION_IN_DEV, program, testPacket)
561 val txBuf = ByteBuffer.wrap(ApfJniUtils.getTransmittedPacket())
562 Struct.parse(EthernetHeader::class.java, txBuf)
563 val ipv4Hdr = Struct.parse(Ipv4Header::class.java, txBuf)
564 val udpHdr = Struct.parse(UdpHeader::class.java, txBuf)
565 assertEquals(0x9535.toShort(), ipv4Hdr.checksum)
566 assertEquals(0xa73d.toShort(), udpHdr.checksum)
567 }
568
Yuyang Huangc11962e2024-02-14 20:37:06 +0900569 private fun decodeCountersIntoMap(counterBytes: ByteArray): Map<Counter, Long> {
570 val counters = Counter::class.java.enumConstants
571 val ret = HashMap<Counter, Long>()
572 // starting from index 2 to skip the endianness mark
573 for (c in listOf(*counters).subList(2, counters.size)) {
574 val value = ApfCounterTracker.getCounterValue(counterBytes, c)
575 if (value != 0L) {
576 ret[c] = value
577 }
578 }
579 return ret
580 }
581
Yuyang Huangae57be02023-10-16 17:49:31 +0900582 private fun encodeInstruction(opcode: Int, immLength: Int, register: Int): Byte {
Yuyang Huang73c6d2d2023-10-19 13:32:37 +0900583 val immLengthEncoding = if (immLength == 4) 3 else immLength
584 return opcode.shl(3).or(immLengthEncoding.shl(1)).or(register).toByte()
Yuyang Huangae57be02023-10-16 17:49:31 +0900585 }
Yuyang Huangbcfa09b2024-02-20 11:20:47 +0900586
587 companion object {
588 const val ETH_HLEN = 14
589 const val IPV4_HLEN = 20
590 const val IPPROTO_UDP = 17
591 }
Yuyang Huangae57be02023-10-16 17:49:31 +0900592}