blob: 2b68f9ead39418e1c0a8a1bea15cb903bd957696 [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 Huang4057de52024-03-13 21:24:46 +090025import android.net.apf.BaseApfGenerator.APF_VERSION_4
Yuyang Huang2b402472024-02-13 16:31:55 +090026import android.net.apf.BaseApfGenerator.DROP_LABEL
Yuyang Huangbded8e32024-02-09 13:34:58 +090027import android.net.apf.BaseApfGenerator.IllegalInstructionException
Yuyang Huang12145c92024-02-09 07:20:15 +090028import android.net.apf.BaseApfGenerator.MIN_APF_VERSION
29import android.net.apf.BaseApfGenerator.MIN_APF_VERSION_IN_DEV
Yuyang Huang12145c92024-02-09 07:20:15 +090030import android.net.apf.BaseApfGenerator.Register.R0
31import android.net.apf.BaseApfGenerator.Register.R1
Yuyang Huangae57be02023-10-16 17:49:31 +090032import androidx.test.filters.SmallTest
33import androidx.test.runner.AndroidJUnit4
Yuyang Huangbcfa09b2024-02-20 11:20:47 +090034import com.android.net.module.util.Struct
35import com.android.net.module.util.structs.EthernetHeader
36import com.android.net.module.util.structs.Ipv4Header
37import com.android.net.module.util.structs.UdpHeader
38import java.nio.ByteBuffer
Yuyang Huangae57be02023-10-16 17:49:31 +090039import kotlin.test.assertContentEquals
Yuyang Huangc11962e2024-02-14 20:37:06 +090040import kotlin.test.assertEquals
Yuyang Huangce1493a2023-12-07 15:29:40 +090041import kotlin.test.assertFailsWith
Yuyang Huang4f849692024-03-20 00:29:58 +090042import org.junit.After
Yuyang Huangae57be02023-10-16 17:49:31 +090043import org.junit.Test
44import org.junit.runner.RunWith
45
46/**
47 * Tests for APFv6 specific instructions.
48 */
49@RunWith(AndroidJUnit4::class)
50@SmallTest
51class ApfV5Test {
52
Yuyang Huang2283be72024-02-08 04:49:08 +090053 private val testPacket = byteArrayOf(1, 2, 3, 4, 5, 6, 7, 8,
54 9, 10, 11, 12, 13, 14, 15, 16)
55
Yuyang Huang4f849692024-03-20 00:29:58 +090056 @After
57 fun tearDown() {
58 ApfJniUtils.resetTransmittedPacketMemory()
59 }
60
Yuyang Huangae57be02023-10-16 17:49:31 +090061 @Test
Yuyang Huanga112cc82023-12-13 17:55:47 +090062 fun testDataInstructionMustComeFirst() {
Yuyang Huangd89cdbe2024-02-01 09:49:07 +090063 var gen = ApfV6Generator()
Yuyang Huanga112cc82023-12-13 17:55:47 +090064 gen.addAllocateR0()
65 assertFailsWith<IllegalInstructionException> { gen.addData(ByteArray(3) { 0x01 }) }
Yuyang Huang1e5bfaf2023-12-11 00:21:54 +090066 }
67
68 @Test
Yuyang Huang3ac843c2023-12-13 16:40:15 +090069 fun testApfInstructionEncodingSizeCheck() {
Yuyang Huangd89cdbe2024-02-01 09:49:07 +090070 var gen = ApfV6Generator()
Yuyang Huangf663ccb2024-03-21 23:16:12 +090071 assertFailsWith<IllegalArgumentException> { gen.addData(ByteArray(65536) { 0x01 }) }
Yuyang Huang3ac843c2023-12-13 16:40:15 +090072 assertFailsWith<IllegalArgumentException> { gen.addAllocate(65536) }
73 assertFailsWith<IllegalArgumentException> { gen.addAllocate(-1) }
Yuyang Huang293f7e72023-12-31 14:24:03 +090074 assertFailsWith<IllegalArgumentException> { gen.addDataCopy(-1, 1) }
75 assertFailsWith<IllegalArgumentException> { gen.addPacketCopy(-1, 1) }
76 assertFailsWith<IllegalArgumentException> { gen.addDataCopy(1, 256) }
77 assertFailsWith<IllegalArgumentException> { gen.addPacketCopy(1, 256) }
78 assertFailsWith<IllegalArgumentException> { gen.addDataCopy(1, -1) }
79 assertFailsWith<IllegalArgumentException> { gen.addPacketCopy(1, -1) }
Yuyang Huangd0390612024-01-01 16:21:16 +090080 assertFailsWith<IllegalArgumentException> { gen.addPacketCopyFromR0(256) }
81 assertFailsWith<IllegalArgumentException> { gen.addDataCopyFromR0(256) }
Yuyang Huang96697842024-01-02 21:53:48 +090082 assertFailsWith<IllegalArgumentException> { gen.addPacketCopyFromR0(-1) }
83 assertFailsWith<IllegalArgumentException> { gen.addDataCopyFromR0(-1) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +090084 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsQ(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +090085 byteArrayOf(1, 'A'.code.toByte(), 0, 0),
86 256,
87 ApfV4Generator.DROP_LABEL
88 ) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +090089 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsQ(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +090090 byteArrayOf(1, 'a'.code.toByte(), 0, 0),
91 0x0c,
92 ApfV4Generator.DROP_LABEL
93 ) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +090094 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsQ(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +090095 byteArrayOf(1, '.'.code.toByte(), 0, 0),
96 0x0c,
97 ApfV4Generator.DROP_LABEL
98 ) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +090099 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsQ(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900100 byteArrayOf(0, 0),
101 0xc0,
102 ApfV4Generator.DROP_LABEL
103 ) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900104 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsQ(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900105 byteArrayOf(1, 'A'.code.toByte()),
106 0xc0,
107 ApfV4Generator.DROP_LABEL
108 ) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900109 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsQ(
110 byteArrayOf(64) + ByteArray(64) { 'A'.code.toByte() } + byteArrayOf(0, 0),
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900111 0xc0,
112 ApfV4Generator.DROP_LABEL
113 ) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900114 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsQ(
115 byteArrayOf(1, 'A'.code.toByte(), 1, 'B'.code.toByte(), 0),
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900116 0xc0,
117 ApfV4Generator.DROP_LABEL
118 ) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900119 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsQ(
120 byteArrayOf(1, 'A'.code.toByte(), 1, 'B'.code.toByte()),
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900121 0xc0,
122 ApfV4Generator.DROP_LABEL
123 ) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900124 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsQ(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900125 byteArrayOf(1, 'A'.code.toByte(), 0, 0),
126 256,
127 ApfV4Generator.DROP_LABEL
128 ) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900129 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsQ(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900130 byteArrayOf(1, 'a'.code.toByte(), 0, 0),
131 0x0c,
132 ApfV4Generator.DROP_LABEL
133 ) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900134 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsQ(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900135 byteArrayOf(1, '.'.code.toByte(), 0, 0),
136 0x0c,
137 ApfV4Generator.DROP_LABEL
138 ) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900139 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsQ(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900140 byteArrayOf(0, 0),
141 0xc0,
142 ApfV4Generator.DROP_LABEL
143 ) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900144 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsQ(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900145 byteArrayOf(1, 'A'.code.toByte()),
146 0xc0,
147 ApfV4Generator.DROP_LABEL
148 ) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900149 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsQ(
150 byteArrayOf(64) + ByteArray(64) { 'A'.code.toByte() } + byteArrayOf(0, 0),
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900151 0xc0,
152 ApfV4Generator.DROP_LABEL
153 ) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900154 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsQ(
155 byteArrayOf(1, 'A'.code.toByte(), 1, 'B'.code.toByte(), 0),
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900156 0xc0,
157 ApfV4Generator.DROP_LABEL
158 ) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900159 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsQ(
160 byteArrayOf(1, 'A'.code.toByte(), 1, 'B'.code.toByte()),
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900161 0xc0,
162 ApfV4Generator.DROP_LABEL
163 ) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900164 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsA(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900165 byteArrayOf(1, 'a'.code.toByte(), 0, 0),
166 ApfV4Generator.DROP_LABEL
167 ) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900168 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsA(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900169 byteArrayOf(1, '.'.code.toByte(), 0, 0),
170 ApfV4Generator.DROP_LABEL
171 ) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900172 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsA(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900173 byteArrayOf(0, 0),
174 ApfV4Generator.DROP_LABEL
175 ) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900176 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsA(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900177 byteArrayOf(1, 'A'.code.toByte()),
178 ApfV4Generator.DROP_LABEL
179 ) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900180 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsA(
181 byteArrayOf(64) + ByteArray(64) { 'A'.code.toByte() } + byteArrayOf(0, 0),
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900182 ApfV4Generator.DROP_LABEL
183 ) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900184 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsA(
185 byteArrayOf(1, 'A'.code.toByte(), 1, 'B'.code.toByte(), 0),
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900186 ApfV4Generator.DROP_LABEL
187 ) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900188 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsA(
189 byteArrayOf(1, 'A'.code.toByte(), 1, 'B'.code.toByte()),
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900190 ApfV4Generator.DROP_LABEL
191 ) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900192 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsA(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900193 byteArrayOf(1, 'a'.code.toByte(), 0, 0),
194 ApfV4Generator.DROP_LABEL
195 ) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900196 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsA(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900197 byteArrayOf(1, '.'.code.toByte(), 0, 0),
198 ApfV4Generator.DROP_LABEL
199 ) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900200 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsA(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900201 byteArrayOf(0, 0),
202 ApfV4Generator.DROP_LABEL
203 ) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900204 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsA(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900205 byteArrayOf(1, 'A'.code.toByte()),
206 ApfV4Generator.DROP_LABEL
207 ) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900208 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsA(
209 byteArrayOf(64) + ByteArray(64) { 'A'.code.toByte() } + byteArrayOf(0, 0),
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900210 ApfV4Generator.DROP_LABEL
211 ) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900212 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsA(
213 byteArrayOf(1, 'A'.code.toByte(), 1, 'B'.code.toByte(), 0),
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900214 ApfV4Generator.DROP_LABEL
215 ) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900216 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsA(
217 byteArrayOf(1, 'A'.code.toByte(), 1, 'B'.code.toByte()),
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900218 ApfV4Generator.DROP_LABEL
219 ) }
Yuyang Huangce1493a2023-12-07 15:29:40 +0900220 }
221
222 @Test
Yuyang Huang2b402472024-02-13 16:31:55 +0900223 fun testValidateDnsNames() {
224 // '%' is a valid label character in mDNS subtype
Yuyang Huangb31cef22024-02-13 16:43:33 +0900225 // byte == 0xff means it is a '*' wildcard, which is a valid encoding.
Yuyang Huang2b402472024-02-13 16:31:55 +0900226 val program = ApfV6Generator().addJumpIfPktAtR0ContainDnsQ(
227 byteArrayOf(1, '%'.code.toByte(), 0, 0),
228 1,
Yuyang Huang22c76a82024-03-21 19:11:43 +0900229 DROP_LABEL
230 ).addJumpIfPktAtR0ContainDnsA(
231 byteArrayOf(0xff.toByte(), 1, 'B'.code.toByte(), 0, 0),
232 DROP_LABEL
233 ).generate()
Yuyang Huang2b402472024-02-13 16:31:55 +0900234 }
235
236 @Test
Yuyang Huangae57be02023-10-16 17:49:31 +0900237 fun testApfInstructionsEncoding() {
Yuyang Huang9b6be762024-02-22 17:06:51 +0900238 val v4gen = ApfV4Generator(MIN_APF_VERSION)
Yuyang Huangafe7b652024-02-09 09:45:01 +0900239 v4gen.addPass()
240 var program = v4gen.generate()
Yuyang Huangdcdb4442023-12-07 14:56:21 +0900241 // encoding PASS opcode: opcode=0, imm_len=0, R=0
Yuyang Huang1e5bfaf2023-12-11 00:21:54 +0900242 assertContentEquals(
Yuyang Huanged30e492024-03-21 19:17:40 +0900243 byteArrayOf(encodeInstruction(opcode = 0, immLength = 0, register = 0)),
244 program
245 )
Yuyang Huang98b99f22024-01-29 06:35:27 +0900246 assertContentEquals(
Yuyang Huanged30e492024-03-21 19:17:40 +0900247 listOf("0: pass"),
248 ApfJniUtils.disassembleApf(program).map { it.trim() }
249 )
Yuyang Huangdcdb4442023-12-07 14:56:21 +0900250
Yuyang Huangafe7b652024-02-09 09:45:01 +0900251 var gen = ApfV6Generator()
Yuyang Huangce1493a2023-12-07 15:29:40 +0900252 gen.addDrop()
253 program = gen.generate()
254 // encoding DROP opcode: opcode=0, imm_len=0, R=1
Yuyang Huang1e5bfaf2023-12-11 00:21:54 +0900255 assertContentEquals(
Yuyang Huanged30e492024-03-21 19:17:40 +0900256 byteArrayOf(encodeInstruction(opcode = 0, immLength = 0, register = 1)),
257 program
258 )
Yuyang Huang98b99f22024-01-29 06:35:27 +0900259 assertContentEquals(
Yuyang Huanged30e492024-03-21 19:17:40 +0900260 listOf("0: drop"),
261 ApfJniUtils.disassembleApf(program).map { it.trim() }
262 )
Yuyang Huang1e5bfaf2023-12-11 00:21:54 +0900263
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900264 gen = ApfV6Generator()
Yuyang Huang1e5bfaf2023-12-11 00:21:54 +0900265 gen.addCountAndPass(129)
266 program = gen.generate()
267 // encoding COUNT(PASS) opcode: opcode=0, imm_len=size_of(imm), R=0, imm=counterNumber
268 assertContentEquals(
Yuyang Huanged30e492024-03-21 19:17:40 +0900269 byteArrayOf(
270 encodeInstruction(opcode = 0, immLength = 1, register = 0),
271 0x81.toByte()
272 ),
273 program
274 )
Yuyang Huang98b99f22024-01-29 06:35:27 +0900275 assertContentEquals(
Yuyang Huang4057de52024-03-13 21:24:46 +0900276 listOf("0: pass 129"),
Yuyang Huanged30e492024-03-21 19:17:40 +0900277 ApfJniUtils.disassembleApf(program).map { it.trim() }
278 )
Yuyang Huang1e5bfaf2023-12-11 00:21:54 +0900279
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900280 gen = ApfV6Generator()
Yuyang Huang1e5bfaf2023-12-11 00:21:54 +0900281 gen.addCountAndDrop(1000)
282 program = gen.generate()
283 // encoding COUNT(DROP) opcode: opcode=0, imm_len=size_of(imm), R=1, imm=counterNumber
284 assertContentEquals(
Yuyang Huanged30e492024-03-21 19:17:40 +0900285 byteArrayOf(
286 encodeInstruction(opcode = 0, immLength = 2, register = 1),
287 0x03,
288 0xe8.toByte()
289 ),
290 program
291 )
Yuyang Huang98b99f22024-01-29 06:35:27 +0900292 assertContentEquals(
Yuyang Huang4057de52024-03-13 21:24:46 +0900293 listOf("0: drop 1000"),
Yuyang Huanged30e492024-03-21 19:17:40 +0900294 ApfJniUtils.disassembleApf(program).map { it.trim() }
295 )
Yuyang Huang4057de52024-03-13 21:24:46 +0900296
297 gen = ApfV6Generator()
298 gen.addCountAndPass(Counter.TOTAL_PACKETS)
299 program = gen.generate()
300 // encoding COUNT(PASS) opcode: opcode=0, imm_len=size_of(imm), R=0, imm=counterNumber
301 assertContentEquals(
Yuyang Huanged30e492024-03-21 19:17:40 +0900302 byteArrayOf(
303 encodeInstruction(opcode = 0, immLength = 1, register = 0),
304 0x02
305 ),
306 program
307 )
Yuyang Huang4057de52024-03-13 21:24:46 +0900308 assertContentEquals(
Yuyang Huanged30e492024-03-21 19:17:40 +0900309 listOf("0: pass 2"),
310 ApfJniUtils.disassembleApf(program).map { it.trim() }
311 )
Yuyang Huang4057de52024-03-13 21:24:46 +0900312
313 gen = ApfV6Generator()
314 gen.addCountAndDrop(Counter.PASSED_ALLOCATE_FAILURE)
315 program = gen.generate()
316 // encoding COUNT(DROP) opcode: opcode=0, imm_len=size_of(imm), R=1, imm=counterNumber
317 assertContentEquals(
Yuyang Huanged30e492024-03-21 19:17:40 +0900318 byteArrayOf(
319 encodeInstruction(opcode = 0, immLength = 1, register = 1),
320 0x03
321 ),
322 program
323 )
Yuyang Huang4057de52024-03-13 21:24:46 +0900324 assertContentEquals(
Yuyang Huanged30e492024-03-21 19:17:40 +0900325 listOf("0: drop 3"),
326 ApfJniUtils.disassembleApf(program).map { it.trim() }
327 )
Yuyang Huangce1493a2023-12-07 15:29:40 +0900328
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900329 gen = ApfV6Generator()
Yuyang Huang3ac843c2023-12-13 16:40:15 +0900330 gen.addAllocateR0()
331 gen.addAllocate(1500)
Yuyang Huangdcdb4442023-12-07 14:56:21 +0900332 program = gen.generate()
Yuyang Huang3ac843c2023-12-13 16:40:15 +0900333 // encoding ALLOC opcode: opcode=21(EXT opcode number), imm=36(TRANS opcode number).
334 // R=0 means length stored in R0. R=1 means the length stored in imm1.
Yuyang Huanged30e492024-03-21 19:17:40 +0900335 assertContentEquals(
336 byteArrayOf(
337 encodeInstruction(opcode = 21, immLength = 1, register = 0),
338 36,
339 encodeInstruction(opcode = 21, immLength = 1, register = 1),
340 36,
341 0x05,
342 0xDC.toByte()
343 ),
344 program
345 )
346 assertContentEquals(listOf(
347 "0: allocate r0",
348 "2: allocate 1500"
349 ), ApfJniUtils.disassembleApf(program).map { it.trim() })
Yuyang Huangae57be02023-10-16 17:49:31 +0900350
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900351 gen = ApfV6Generator()
Yuyang Huangfb803682024-02-20 17:52:27 +0900352 gen.addTransmitWithoutChecksum()
Yuyang Huang738fa6d2024-02-13 22:03:42 +0900353 gen.addTransmitL4(30, 40, 50, 256, true)
Yuyang Huangae57be02023-10-16 17:49:31 +0900354 program = gen.generate()
Maciej Żenczykowskidbf2f972024-02-09 23:01:04 -0800355 // encoding TRANSMIT opcode: opcode=21(EXT opcode number),
356 // imm=37(TRANSMIT opcode number),
Yuyang Huangfd74ce42023-12-12 20:10:45 +0900357 assertContentEquals(byteArrayOf(
Maciej Żenczykowskidbf2f972024-02-09 23:01:04 -0800358 encodeInstruction(opcode = 21, immLength = 1, register = 0),
359 37, 255.toByte(), 255.toByte(),
Yuyang Huang738fa6d2024-02-13 22:03:42 +0900360 encodeInstruction(opcode = 21, immLength = 1, register = 1), 37, 30, 40, 50, 1, 0
Yuyang Huangfd74ce42023-12-12 20:10:45 +0900361 ), program)
Yuyang Huanged30e492024-03-21 19:17:40 +0900362 assertContentEquals(listOf(
363 "0: transmit ip_ofs=255",
364 "4: transmitudp ip_ofs=30, csum_ofs=40, csum_start=50, partial_csum=0x0100",
365 ), ApfJniUtils.disassembleApf(program).map { it.trim() })
Yuyang Huang73c6d2d2023-10-19 13:32:37 +0900366
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900367 gen = ApfV6Generator()
Yuyang Huanga112cc82023-12-13 17:55:47 +0900368 val largeByteArray = ByteArray(256) { 0x01 }
369 gen.addData(largeByteArray)
370 program = gen.generate()
371 // encoding DATA opcode: opcode=14(JMP), R=1
Yuyang Huanged30e492024-03-21 19:17:40 +0900372 assertContentEquals(
373 byteArrayOf(
374 encodeInstruction(opcode = 14, immLength = 2, register = 1),
375 0x01,
376 0x00
377 ) + largeByteArray,
378 program
379 )
380 assertContentEquals(
381 listOf("0: data 256, " + "01".repeat(256) ),
382 ApfJniUtils.disassembleApf(program).map { it.trim() }
383 )
Yuyang Huanga112cc82023-12-13 17:55:47 +0900384
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900385 gen = ApfV6Generator()
Yuyang Huangadf69672024-01-02 10:18:11 +0900386 gen.addWriteU8(0x01)
387 gen.addWriteU16(0x0102)
388 gen.addWriteU32(0x01020304)
389 gen.addWriteU8(0x00)
390 gen.addWriteU8(0x80)
391 gen.addWriteU16(0x0000)
392 gen.addWriteU16(0x8000)
393 gen.addWriteU32(0x00000000)
394 gen.addWriteU32(0x80000000)
Yuyang Huang4ac891f2023-12-20 11:49:11 +0900395 program = gen.generate()
396 assertContentEquals(byteArrayOf(
397 encodeInstruction(24, 1, 0), 0x01,
398 encodeInstruction(24, 2, 0), 0x01, 0x02,
399 encodeInstruction(24, 4, 0), 0x01, 0x02, 0x03, 0x04,
400 encodeInstruction(24, 1, 0), 0x00,
401 encodeInstruction(24, 1, 0), 0x80.toByte(),
402 encodeInstruction(24, 2, 0), 0x00, 0x00,
403 encodeInstruction(24, 2, 0), 0x80.toByte(), 0x00,
404 encodeInstruction(24, 4, 0), 0x00, 0x00, 0x00, 0x00,
405 encodeInstruction(24, 4, 0), 0x80.toByte(), 0x00, 0x00,
406 0x00), program)
Yuyang Huang7affd672024-01-29 13:04:43 +0900407 assertContentEquals(listOf(
Yuyang Huanged30e492024-03-21 19:17:40 +0900408 "0: write 0x01",
409 "2: write 0x0102",
410 "5: write 0x01020304",
411 "10: write 0x00",
412 "12: write 0x80",
413 "14: write 0x0000",
414 "17: write 0x8000",
415 "20: write 0x00000000",
416 "25: write 0x80000000"
417 ), ApfJniUtils.disassembleApf(program).map { it.trim() })
Yuyang Huange84a9692024-01-01 11:49:49 +0900418
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900419 gen = ApfV6Generator()
Yuyang Huange84a9692024-01-01 11:49:49 +0900420 gen.addWriteU8(R0)
421 gen.addWriteU16(R0)
422 gen.addWriteU32(R0)
423 gen.addWriteU8(R1)
424 gen.addWriteU16(R1)
425 gen.addWriteU32(R1)
426 program = gen.generate()
427 assertContentEquals(byteArrayOf(
428 encodeInstruction(21, 1, 0), 38,
429 encodeInstruction(21, 1, 0), 39,
430 encodeInstruction(21, 1, 0), 40,
431 encodeInstruction(21, 1, 1), 38,
432 encodeInstruction(21, 1, 1), 39,
433 encodeInstruction(21, 1, 1), 40
434 ), program)
Yuyang Huangf0b46cb2024-01-30 03:37:17 +0900435 assertContentEquals(listOf(
436 "0: ewrite1 r0",
437 "2: ewrite2 r0",
438 "4: ewrite4 r0",
439 "6: ewrite1 r1",
440 "8: ewrite2 r1",
Yuyang Huanged30e492024-03-21 19:17:40 +0900441 "10: ewrite4 r1"
442 ), ApfJniUtils.disassembleApf(program).map { it.trim() })
Yuyang Huang73c6d2d2023-10-19 13:32:37 +0900443
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900444 gen = ApfV6Generator()
Yuyang Huang293f7e72023-12-31 14:24:03 +0900445 gen.addDataCopy(0, 10)
446 gen.addDataCopy(1, 5)
447 gen.addPacketCopy(1000, 255)
448 program = gen.generate()
449 assertContentEquals(byteArrayOf(
450 encodeInstruction(25, 0, 1), 10,
451 encodeInstruction(25, 1, 1), 1, 5,
452 encodeInstruction(25, 2, 0),
453 0x03.toByte(), 0xe8.toByte(), 0xff.toByte(),
454 ), program)
Yuyang Huange8003982024-01-30 04:06:18 +0900455 assertContentEquals(listOf(
Yuyang Huangb2a93342024-02-07 06:32:00 +0900456 "0: datacopy src=0, len=10",
457 "2: datacopy src=1, len=5",
458 "5: pktcopy src=1000, len=255"
Yuyang Huanged30e492024-03-21 19:17:40 +0900459 ), ApfJniUtils.disassembleApf(program).map { it.trim() })
Yuyang Huang293f7e72023-12-31 14:24:03 +0900460
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900461 gen = ApfV6Generator()
Yuyang Huangbed904a2024-01-30 11:22:49 +0900462 gen.addDataCopyFromR0(5)
Yuyang Huangd0390612024-01-01 16:21:16 +0900463 gen.addPacketCopyFromR0(5)
464 gen.addDataCopyFromR0LenR1()
Yuyang Huangbed904a2024-01-30 11:22:49 +0900465 gen.addPacketCopyFromR0LenR1()
Yuyang Huangd0390612024-01-01 16:21:16 +0900466 program = gen.generate()
467 assertContentEquals(byteArrayOf(
Yuyang Huangbed904a2024-01-30 11:22:49 +0900468 encodeInstruction(21, 1, 1), 41, 5,
Yuyang Huangd0390612024-01-01 16:21:16 +0900469 encodeInstruction(21, 1, 0), 41, 5,
470 encodeInstruction(21, 1, 1), 42,
Yuyang Huangbed904a2024-01-30 11:22:49 +0900471 encodeInstruction(21, 1, 0), 42,
Yuyang Huangd0390612024-01-01 16:21:16 +0900472 ), program)
Yuyang Huangbed904a2024-01-30 11:22:49 +0900473 assertContentEquals(listOf(
Yuyang Huanged30e492024-03-21 19:17:40 +0900474 "0: edatacopy src=r0, len=5",
475 "3: epktcopy src=r0, len=5",
476 "6: edatacopy src=r0, len=r1",
477 "8: epktcopy src=r0, len=r1"
478 ), ApfJniUtils.disassembleApf(program).map{ it.trim() })
Yuyang Huang0f49d0a2024-01-04 19:14:22 +0900479
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900480 gen = ApfV6Generator()
Yuyang Huangaf0d3722024-01-12 13:38:44 +0900481 gen.addJumpIfBytesAtR0Equal(byteArrayOf('a'.code.toByte()), ApfV4Generator.DROP_LABEL)
Yuyang Huang0f49d0a2024-01-04 19:14:22 +0900482 program = gen.generate()
Yuyang Huanged30e492024-03-21 19:17:40 +0900483 assertContentEquals(byteArrayOf(
484 encodeInstruction(opcode = 20, immLength = 1, register = 1),
485 1,
486 1,
487 'a'.code.toByte()
488 ), program)
Yuyang Huangbffcf262024-02-04 07:52:48 +0900489 assertContentEquals(listOf(
Yuyang Huanged30e492024-03-21 19:17:40 +0900490 "0: jbseq r0, 0x1, DROP, 61"
491 ), ApfJniUtils.disassembleApf(program).map{ it.trim() })
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900492
493 val qnames = byteArrayOf(1, 'A'.code.toByte(), 1, 'B'.code.toByte(), 0, 0)
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900494 gen = ApfV6Generator()
Yuyang Huangaf0d3722024-01-12 13:38:44 +0900495 gen.addJumpIfPktAtR0DoesNotContainDnsQ(qnames, 0x0c, ApfV4Generator.DROP_LABEL)
496 gen.addJumpIfPktAtR0ContainDnsQ(qnames, 0x0c, ApfV4Generator.DROP_LABEL)
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900497 program = gen.generate()
498 assertContentEquals(byteArrayOf(
Yuyang Huang823351f2024-01-08 14:28:42 +0900499 encodeInstruction(21, 1, 0), 43, 11, 0x0c.toByte(),
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900500 ) + qnames + byteArrayOf(
Yuyang Huang823351f2024-01-08 14:28:42 +0900501 encodeInstruction(21, 1, 1), 43, 1, 0x0c.toByte(),
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900502 ) + qnames, program)
Yuyang Huang49ab8822024-02-04 09:39:00 +0900503 assertContentEquals(listOf(
Yuyang Huanged30e492024-03-21 19:17:40 +0900504 "0: jdnsqne r0, DROP, 12, (1)A(1)B(0)(0)",
505 "10: jdnsqeq r0, DROP, 12, (1)A(1)B(0)(0)"
506 ), ApfJniUtils.disassembleApf(program).map{ it.trim() })
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900507
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900508 gen = ApfV6Generator()
Yuyang Huang365fc3a2024-02-14 21:47:37 +0900509 gen.addJumpIfPktAtR0DoesNotContainDnsQSafe(qnames, 0x0c, ApfV4Generator.DROP_LABEL)
510 gen.addJumpIfPktAtR0ContainDnsQSafe(qnames, 0x0c, ApfV4Generator.DROP_LABEL)
511 program = gen.generate()
512 assertContentEquals(byteArrayOf(
513 encodeInstruction(21, 1, 0), 45, 11, 0x0c.toByte(),
514 ) + qnames + byteArrayOf(
515 encodeInstruction(21, 1, 1), 45, 1, 0x0c.toByte(),
516 ) + qnames, program)
517 assertContentEquals(listOf(
518 "0: jdnsqnesafe r0, DROP, 12, (1)A(1)B(0)(0)",
Yuyang Huanged30e492024-03-21 19:17:40 +0900519 "10: jdnsqeqsafe r0, DROP, 12, (1)A(1)B(0)(0)"
520 ), ApfJniUtils.disassembleApf(program).map{ it.trim() })
Yuyang Huang365fc3a2024-02-14 21:47:37 +0900521
522 gen = ApfV6Generator()
Yuyang Huangaf0d3722024-01-12 13:38:44 +0900523 gen.addJumpIfPktAtR0DoesNotContainDnsA(qnames, ApfV4Generator.DROP_LABEL)
524 gen.addJumpIfPktAtR0ContainDnsA(qnames, ApfV4Generator.DROP_LABEL)
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900525 program = gen.generate()
526 assertContentEquals(byteArrayOf(
527 encodeInstruction(21, 1, 0), 44, 10,
528 ) + qnames + byteArrayOf(
529 encodeInstruction(21, 1, 1), 44, 1,
530 ) + qnames, program)
Yuyang Huang1efe2fc2024-02-07 04:02:07 +0900531 assertContentEquals(listOf(
Yuyang Huanged30e492024-03-21 19:17:40 +0900532 "0: jdnsane r0, DROP, (1)A(1)B(0)(0)",
533 "9: jdnsaeq r0, DROP, (1)A(1)B(0)(0)"
534 ), ApfJniUtils.disassembleApf(program).map{ it.trim() })
Yuyang Huang365fc3a2024-02-14 21:47:37 +0900535
536 gen = ApfV6Generator()
537 gen.addJumpIfPktAtR0DoesNotContainDnsASafe(qnames, ApfV4Generator.DROP_LABEL)
538 gen.addJumpIfPktAtR0ContainDnsASafe(qnames, ApfV4Generator.DROP_LABEL)
539 program = gen.generate()
540 assertContentEquals(byteArrayOf(
541 encodeInstruction(21, 1, 0), 46, 10,
542 ) + qnames + byteArrayOf(
543 encodeInstruction(21, 1, 1), 46, 1,
544 ) + qnames, program)
545 assertContentEquals(listOf(
546 "0: jdnsanesafe r0, DROP, (1)A(1)B(0)(0)",
Yuyang Huanged30e492024-03-21 19:17:40 +0900547 "9: jdnsaeqsafe r0, DROP, (1)A(1)B(0)(0)"
548 ), ApfJniUtils.disassembleApf(program).map{ it.trim() })
Yuyang Huangae57be02023-10-16 17:49:31 +0900549 }
550
Yuyang Huang2fdba242024-02-06 14:52:22 +0900551 @Test
552 fun testWriteToTxBuffer() {
Yuyang Huangbded8e32024-02-09 13:34:58 +0900553 var program = ApfV6Generator()
Yuyang Huang3fa07a72024-02-20 19:13:33 +0900554 .addAllocate(14)
Yuyang Huangb97aa962024-02-08 08:13:56 +0900555 .addWriteU8(0x01)
Yuyang Huang3fa07a72024-02-20 19:13:33 +0900556 .addWriteU16(0x0203)
557 .addWriteU32(0x04050607)
Yuyang Huangbded8e32024-02-09 13:34:58 +0900558 .addLoadImmediate(R0, 1)
559 .addWriteU8(R0)
560 .addLoadImmediate(R0, 0x0203)
561 .addWriteU16(R0)
562 .addLoadImmediate(R1, 0x04050607)
563 .addWriteU32(R1)
Yuyang Huangfb803682024-02-20 17:52:27 +0900564 .addTransmitWithoutChecksum()
Yuyang Huangbded8e32024-02-09 13:34:58 +0900565 .generate()
566 assertPass(MIN_APF_VERSION_IN_DEV, program, ByteArray(MIN_PKT_SIZE))
Yuyang Huang3fa07a72024-02-20 19:13:33 +0900567 assertContentEquals(byteArrayOf(0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x01, 0x02, 0x03,
568 0x04, 0x05, 0x06, 0x07), ApfJniUtils.getTransmittedPacket())
Yuyang Huang2fdba242024-02-06 14:52:22 +0900569 }
570
Yuyang Huang2283be72024-02-08 04:49:08 +0900571 @Test
572 fun testCopyToTxBuffer() {
Yuyang Huang10598932024-02-14 10:00:59 +0900573 var program = ApfV6Generator()
Yuyang Huang87750392024-03-22 10:40:06 +0900574 .addData(byteArrayOf(33, 34, 35))
575 .addAllocate(14)
576 .addDataCopy(3, 2) // arg1=src, arg2=len
577 .addDataCopy(5, 1) // arg1=src, arg2=len
578 .addPacketCopy(0, 1) // arg1=src, arg2=len
579 .addPacketCopy(1, 3) // arg1=src, arg2=len
580 .addLoadImmediate(R0, 3) // data copy offset
581 .addDataCopyFromR0(2) // len
582 .addLoadImmediate(R0, 5) // data copy offset
583 .addLoadImmediate(R1, 1) // len
584 .addDataCopyFromR0LenR1()
585 .addLoadImmediate(R0, 0) // packet copy offset
586 .addPacketCopyFromR0(1) // len
587 .addLoadImmediate(R0, 1) // packet copy offset
588 .addLoadImmediate(R1, 3) // len
589 .addPacketCopyFromR0LenR1()
590 .addTransmitWithoutChecksum()
591 .generate()
Yuyang Huang2283be72024-02-08 04:49:08 +0900592 assertPass(MIN_APF_VERSION_IN_DEV, program, testPacket)
Yuyang Huang87750392024-03-22 10:40:06 +0900593 assertContentEquals(
594 byteArrayOf(33, 34, 35, 1, 2, 3, 4, 33, 34, 35, 1, 2, 3, 4),
595 ApfJniUtils.getTransmittedPacket()
596 )
Yuyang Huang2283be72024-02-08 04:49:08 +0900597 }
598
Yuyang Huangc11962e2024-02-14 20:37:06 +0900599 @Test
600 fun testPassDrop() {
601 var program = ApfV6Generator()
602 .addDrop()
603 .addPass()
604 .generate()
605 assertDrop(MIN_APF_VERSION_IN_DEV, program, testPacket)
606
607 var dataRegion = ByteArray(Counter.totalSize()) { 0 }
608 program = ApfV6Generator()
609 .addData(byteArrayOf())
Yuyang Huang4057de52024-03-13 21:24:46 +0900610 .addCountAndDrop(Counter.DROPPED_ETH_BROADCAST)
Yuyang Huangc11962e2024-02-14 20:37:06 +0900611 .generate()
612 assertVerdict(MIN_APF_VERSION_IN_DEV, DROP, program, testPacket, dataRegion)
613 var counterMap = decodeCountersIntoMap(dataRegion)
614 assertEquals(mapOf<Counter, Long>(
615 Counter.TOTAL_PACKETS to 1,
Yuyang Huangd6eb4fc2024-03-22 10:50:25 +0900616 Counter.DROPPED_ETH_BROADCAST to 1
617 ), counterMap)
Yuyang Huangc11962e2024-02-14 20:37:06 +0900618
619 dataRegion = ByteArray(Counter.totalSize()) { 0 }
620 program = ApfV6Generator()
621 .addData(byteArrayOf())
Yuyang Huang4057de52024-03-13 21:24:46 +0900622 .addCountAndPass(Counter.PASSED_ARP)
Yuyang Huangc11962e2024-02-14 20:37:06 +0900623 .generate()
624 assertVerdict(MIN_APF_VERSION_IN_DEV, PASS, program, testPacket, dataRegion)
625 counterMap = decodeCountersIntoMap(dataRegion)
626 assertEquals(mapOf<Counter, Long>(
627 Counter.TOTAL_PACKETS to 1,
Yuyang Huangd6eb4fc2024-03-22 10:50:25 +0900628 Counter.PASSED_ARP to 1
629 ), counterMap)
Yuyang Huangc11962e2024-02-14 20:37:06 +0900630 }
631
Yuyang Huang0e3b4cb2024-02-19 16:20:26 +0900632 @Test
Yuyang Huang4057de52024-03-13 21:24:46 +0900633 fun testV4CountAndPassDrop() {
634 var program = ApfV4Generator(APF_VERSION_4)
635 .addCountAndDrop(Counter.DROPPED_ETH_BROADCAST)
636 .addCountTrampoline()
637 .generate()
638 var dataRegion = ByteArray(Counter.totalSize()) { 0 }
639 assertVerdict(MIN_APF_VERSION_IN_DEV, DROP, program, testPacket, dataRegion)
640 var counterMap = decodeCountersIntoMap(dataRegion)
641 assertEquals(mapOf<Counter, Long>(
Yuyang Huangd6eb4fc2024-03-22 10:50:25 +0900642 Counter.DROPPED_ETH_BROADCAST to 1
643 ), counterMap)
Yuyang Huang4057de52024-03-13 21:24:46 +0900644
645 program = ApfV4Generator(APF_VERSION_4)
646 .addCountAndPass(Counter.PASSED_ARP)
647 .addCountTrampoline()
648 .generate()
649 dataRegion = ByteArray(Counter.totalSize()) { 0 }
650 assertVerdict(MIN_APF_VERSION_IN_DEV, PASS, program, testPacket, dataRegion)
651 counterMap = decodeCountersIntoMap(dataRegion)
652 assertEquals(mapOf<Counter, Long>(
Yuyang Huangd6eb4fc2024-03-22 10:50:25 +0900653 Counter.PASSED_ARP to 1
654 ), counterMap)
Yuyang Huang4057de52024-03-13 21:24:46 +0900655 }
656
657 @Test
Yuyang Huang6ff913f2024-03-20 13:31:58 +0900658 fun testV2CountAndPassDrop() {
Yuyang Huang4057de52024-03-13 21:24:46 +0900659 var program = ApfV4Generator(MIN_APF_VERSION)
660 .addCountAndDrop(Counter.DROPPED_ETH_BROADCAST)
661 .addCountTrampoline()
662 .generate()
663 var dataRegion = ByteArray(Counter.totalSize()) { 0 }
664 assertVerdict(MIN_APF_VERSION_IN_DEV, DROP, program, testPacket, dataRegion)
665 assertContentEquals(ByteArray(Counter.totalSize()) { 0 }, dataRegion)
666
667 program = ApfV4Generator(MIN_APF_VERSION)
668 .addCountAndPass(Counter.DROPPED_ETH_BROADCAST)
669 .addCountTrampoline()
670 .generate()
671 dataRegion = ByteArray(Counter.totalSize()) { 0 }
672 assertVerdict(MIN_APF_VERSION_IN_DEV, PASS, program, testPacket, dataRegion)
673 assertContentEquals(ByteArray(Counter.totalSize()) { 0 }, dataRegion)
674 }
675
676 @Test
Yuyang Huang0e3b4cb2024-02-19 16:20:26 +0900677 fun testAllocateFailure() {
678 val program = ApfV6Generator()
679 .addData(byteArrayOf())
680 // allocate size: 65535 > sizeof(apf_test_buffer): 1514, trigger allocate failure.
681 .addAllocate(65535)
682 .addDrop()
683 .generate()
684 val dataRegion = ByteArray(Counter.totalSize()) { 0 }
685 assertVerdict(MIN_APF_VERSION_IN_DEV, PASS, program, testPacket, dataRegion)
686 val counterMap = decodeCountersIntoMap(dataRegion)
687 assertEquals(mapOf<Counter, Long>(
688 Counter.TOTAL_PACKETS to 1,
Yuyang Huangd6eb4fc2024-03-22 10:50:25 +0900689 Counter.PASSED_ALLOCATE_FAILURE to 1
690 ), counterMap)
Yuyang Huang0e3b4cb2024-02-19 16:20:26 +0900691 }
692
Yuyang Huang19df0482024-02-19 16:38:45 +0900693 @Test
694 fun testTransmitFailure() {
695 val program = ApfV6Generator()
696 .addData(byteArrayOf())
697 .addAllocate(14)
698 // len: 13 is less than ETH_HLEN, trigger transmit failure.
699 .addLoadImmediate(R0, 13)
700 .addStoreToMemory(R0, 10)
701 .addTransmitWithoutChecksum()
702 .addDrop()
703 .generate()
704 val dataRegion = ByteArray(Counter.totalSize()) { 0 }
705 assertVerdict(MIN_APF_VERSION_IN_DEV, PASS, program, testPacket, dataRegion)
706 val counterMap = decodeCountersIntoMap(dataRegion)
707 assertEquals(mapOf<Counter, Long>(
708 Counter.TOTAL_PACKETS to 1,
Yuyang Huangd6eb4fc2024-03-22 10:50:25 +0900709 Counter.PASSED_TRANSMIT_FAILURE to 1
710 ), counterMap)
Yuyang Huang19df0482024-02-19 16:38:45 +0900711 }
712
Yuyang Huangbcfa09b2024-02-20 11:20:47 +0900713 @Test
714 fun testTransmitL4() {
715 val etherIpv4UdpPacket = intArrayOf(
Yuyang Huanga6f38f32024-03-22 11:00:43 +0900716 0x01, 0x00, 0x5e, 0x00, 0x00, 0xfb,
717 0x38, 0xca, 0x84, 0xb7, 0x7f, 0x16,
718 0x08, 0x00, // end of ethernet header
719 0x45,
720 0x04,
721 0x00, 0x3f,
722 0x43, 0xcd,
723 0x40, 0x00,
724 0xff,
725 0x11,
726 0x00, 0x00, // ipv4 checksum set to 0
727 0xc0, 0xa8, 0x01, 0x03,
728 0xe0, 0x00, 0x00, 0xfb, // end of ipv4 header
729 0x14, 0xe9,
730 0x14, 0xe9,
731 0x00, 0x2b,
732 0x00, 0x2b, // end of udp header. udp checksum set to udp (header + payload) size
733 0x00, 0x00, 0x84, 0x00, 0x00, 0x00,
734 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x62, 0x05, 0x6c, 0x6f, 0x63, 0x61, 0x6c,
735 0x00, 0x00, 0x01, 0x80, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x04, 0xc0, 0xa8, 0x01,
736 0x09,
Yuyang Huangbcfa09b2024-02-20 11:20:47 +0900737 ).map { it.toByte() }.toByteArray()
738 val program = ApfV6Generator()
739 .addData(etherIpv4UdpPacket)
740 .addAllocate(etherIpv4UdpPacket.size)
Yuyang Huanga6f38f32024-03-22 11:00:43 +0900741 .addDataCopy(3, etherIpv4UdpPacket.size) // arg1=src, arg2=len
742 .addTransmitL4(
743 ETH_HLEN, // ipOfs,
744 ETH_HLEN + IPV4_HLEN + 6, // csumOfs
745 ETH_HLEN + IPV4_HLEN - 8, // csumStart
746 IPPROTO_UDP, // partialCsum
747 true // isUdp
748 )
Yuyang Huangbcfa09b2024-02-20 11:20:47 +0900749 .generate()
750 assertPass(MIN_APF_VERSION_IN_DEV, program, testPacket)
751 val txBuf = ByteBuffer.wrap(ApfJniUtils.getTransmittedPacket())
752 Struct.parse(EthernetHeader::class.java, txBuf)
753 val ipv4Hdr = Struct.parse(Ipv4Header::class.java, txBuf)
754 val udpHdr = Struct.parse(UdpHeader::class.java, txBuf)
755 assertEquals(0x9535.toShort(), ipv4Hdr.checksum)
756 assertEquals(0xa73d.toShort(), udpHdr.checksum)
757 }
758
Yuyang Huangebd52752024-02-20 17:08:55 +0900759 @Test
760 fun testDnsQuestionMatch() {
761 // needles = { A, B.LOCAL }
762 val needlesMatch = intArrayOf(
763 0x01, 'A'.code,
764 0x00,
765 0x01, 'B'.code,
766 0x05, 'L'.code, 'O'.code, 'C'.code, 'A'.code, 'L'.code,
767 0x00,
768 0x00
769 ).map { it.toByte() }.toByteArray()
770 val udpPayload = intArrayOf(
771 0x00, 0x00, 0x00, 0x00, // tid = 0x00, flags = 0x00,
772 0x00, 0x02, // qdcount = 2
773 0x00, 0x00, // ancount = 0
774 0x00, 0x00, // nscount = 0
775 0x00, 0x00, // arcount = 0
776 0x01, 'a'.code,
777 0x01, 'b'.code,
778 0x05, 'l'.code, 'o'.code, 'c'.code, 'a'.code, 'l'.code,
779 0x00, // qname1 = a.b.local
780 0x00, 0x01, 0x00, 0x01, // type = A, class = 0x0001
781 0xc0, 0x0e, // qname2 = b.local (name compression)
782 0x00, 0x01, 0x00, 0x01 // type = A, class = 0x0001
783 ).map { it.toByte() }.toByteArray()
784
785 var program = ApfV6Generator()
786 .addData(byteArrayOf())
787 .addLoadImmediate(R0, 0)
788 .addJumpIfPktAtR0ContainDnsQ(needlesMatch, 0x01 /* qtype */, DROP_LABEL)
789 .addPass()
790 .generate()
791 assertDrop(MIN_APF_VERSION_IN_DEV, program, udpPayload)
792
793 program = ApfV6Generator()
794 .addData(byteArrayOf())
795 .addLoadImmediate(R0, 0)
796 .addJumpIfPktAtR0ContainDnsQSafe(needlesMatch, 0x01 /* qtype */, DROP_LABEL)
797 .addPass()
798 .generate()
799 assertDrop(MIN_APF_VERSION_IN_DEV, program, udpPayload)
800
801 program = ApfV6Generator()
802 .addData(byteArrayOf())
803 .addLoadImmediate(R0, 0)
804 .addJumpIfPktAtR0DoesNotContainDnsQ(needlesMatch, 0x01 /* qtype */, DROP_LABEL)
805 .addPass()
806 .generate()
807 assertPass(MIN_APF_VERSION_IN_DEV, program, udpPayload)
808
809 program = ApfV6Generator()
810 .addData(byteArrayOf())
811 .addLoadImmediate(R0, 0)
812 .addJumpIfPktAtR0DoesNotContainDnsQSafe(needlesMatch, 0x01 /* qtype */, DROP_LABEL)
813 .addPass()
814 .generate()
815 assertPass(MIN_APF_VERSION_IN_DEV, program, udpPayload)
816
817 val badUdpPayload = intArrayOf(
818 0x00, 0x00, 0x00, 0x00, // tid = 0x00, flags = 0x00,
819 0x00, 0x02, // qdcount = 2
820 0x00, 0x00, // ancount = 0
821 0x00, 0x00, // nscount = 0
822 0x00, 0x00, // arcount = 0
823 0x01, 'a'.code,
824 0x01, 'b'.code,
825 0x05, 'l'.code, 'o'.code, 'c'.code, 'a'.code, 'l'.code,
826 0x00, // qname1 = a.b.local
827 0x00, 0x01, 0x00, 0x01, // type = A, class = 0x0001
828 0xc0, 0x1b, // corrupted pointer cause infinite loop
829 0x00, 0x01, 0x00, 0x01 // type = A, class = 0x0001
830 ).map { it.toByte() }.toByteArray()
831
832 program = ApfV6Generator()
833 .addData(byteArrayOf())
834 .addLoadImmediate(R0, 0)
835 .addJumpIfPktAtR0ContainDnsQ(needlesMatch, 0x01 /* qtype */, DROP_LABEL)
836 .addPass()
837 .generate()
838 var dataRegion = ByteArray(Counter.totalSize()) { 0 }
839 assertVerdict(MIN_APF_VERSION_IN_DEV, DROP, program, badUdpPayload, dataRegion)
840 var counterMap = decodeCountersIntoMap(dataRegion)
841 assertEquals(mapOf<Counter, Long>(
842 Counter.TOTAL_PACKETS to 1,
843 Counter.CORRUPT_DNS_PACKET to 1), counterMap)
844
845 program = ApfV6Generator()
846 .addData(byteArrayOf())
847 .addLoadImmediate(R0, 0)
848 .addJumpIfPktAtR0ContainDnsQSafe(needlesMatch, 0x01 /* qtype */, DROP_LABEL)
849 .addPass()
850 .generate()
851 dataRegion = ByteArray(Counter.totalSize()) { 0 }
852 assertVerdict(MIN_APF_VERSION_IN_DEV, PASS, program, badUdpPayload, dataRegion)
853 counterMap = decodeCountersIntoMap(dataRegion)
854 assertEquals(mapOf<Counter, Long>(
855 Counter.TOTAL_PACKETS to 1,
856 Counter.CORRUPT_DNS_PACKET to 1), counterMap)
857 }
858
859 @Test
860 fun testDnsAnswerMatch() {
861 // needles = { A, B.LOCAL }
862 val needlesMatch = intArrayOf(
863 0x01, 'A'.code,
864 0x00,
865 0x01, 'B'.code,
866 0x05, 'L'.code, 'O'.code, 'C'.code, 'A'.code, 'L'.code,
867 0x00,
868 0x00
869 ).map { it.toByte() }.toByteArray()
870
871 val udpPayload = intArrayOf(
872 0x00, 0x00, 0x84, 0x00, // tid = 0x00, flags = 0x8400,
873 0x00, 0x00, // qdcount = 0
874 0x00, 0x02, // ancount = 2
875 0x00, 0x00, // nscount = 0
876 0x00, 0x00, // arcount = 0
877 0x01, 'a'.code,
878 0x01, 'b'.code,
879 0x05, 'l'.code, 'o'.code, 'c'.code, 'a'.code, 'l'.code,
880 0x00, // name1 = a.b.local
881 0x00, 0x01, 0x80, 0x01, // type = A, class = 0x8001
882 0x00, 0x00, 0x00, 0x78, // ttl = 120
883 0x00, 0x04, 0xc0, 0xa8, 0x01, 0x09, // rdlengh = 4, rdata = 192.168.1.9
884 0xc0, 0x0e, // name2 = b.local (name compression)
885 0x00, 0x01, 0x80, 0x01, // type = A, class = 0x8001
886 0x00, 0x00, 0x00, 0x78, // ttl = 120
887 0x00, 0x04, 0xc0, 0xa8, 0x01, 0x09 // rdlengh = 4, rdata = 192.168.1.9
888 ).map { it.toByte() }.toByteArray()
889
890 var program = ApfV6Generator()
891 .addData(byteArrayOf())
892 .addLoadImmediate(R0, 0)
893 .addJumpIfPktAtR0ContainDnsA(needlesMatch, DROP_LABEL)
894 .addPass()
895 .generate()
896 assertDrop(MIN_APF_VERSION_IN_DEV, program, udpPayload)
897
898 program = ApfV6Generator()
899 .addData(byteArrayOf())
900 .addLoadImmediate(R0, 0)
901 .addJumpIfPktAtR0ContainDnsASafe(needlesMatch, DROP_LABEL)
902 .addPass()
903 .generate()
904 assertDrop(MIN_APF_VERSION_IN_DEV, program, udpPayload)
905
906 program = ApfV6Generator()
907 .addData(byteArrayOf())
908 .addLoadImmediate(R0, 0)
909 .addJumpIfPktAtR0DoesNotContainDnsA(needlesMatch, DROP_LABEL)
910 .addPass()
911 .generate()
912 assertPass(MIN_APF_VERSION_IN_DEV, program, udpPayload)
913
914 program = ApfV6Generator()
915 .addData(byteArrayOf())
916 .addLoadImmediate(R0, 0)
917 .addJumpIfPktAtR0DoesNotContainDnsASafe(needlesMatch, DROP_LABEL)
918 .addPass()
919 .generate()
920 assertPass(MIN_APF_VERSION_IN_DEV, program, udpPayload)
921
922 val badUdpPayload = intArrayOf(
923 0x00, 0x00, 0x84, 0x00, // tid = 0x00, flags = 0x8400,
924 0x00, 0x00, // qdcount = 0
925 0x00, 0x02, // ancount = 2
926 0x00, 0x00, // nscount = 0
927 0x00, 0x00, // arcount = 0
928 0x01, 'a'.code,
929 0x01, 'b'.code,
930 0x05, 'l'.code, 'o'.code, 'c'.code, 'a'.code, 'l'.code,
931 0x00, // name1 = a.b.local
932 0x00, 0x01, 0x80, 0x01, // type = A, class = 0x8001
933 0x00, 0x00, 0x00, 0x78, // ttl = 120
934 0x00, 0x04, 0xc0, 0xa8, 0x01, 0x09, // rdlengh = 4, rdata = 192.168.1.9
935 0xc0, 0x25, // corrupted pointer cause infinite loop
936 0x00, 0x01, 0x80, 0x01, // type = A, class = 0x8001
937 0x00, 0x00, 0x00, 0x78, // ttl = 120
938 0x00, 0x04, 0xc0, 0xa8, 0x01, 0x09 // rdlengh = 4, rdata = 192.168.1.9
939 ).map { it.toByte() }.toByteArray()
940
941 program = ApfV6Generator()
942 .addData(byteArrayOf())
943 .addLoadImmediate(R0, 0)
944 .addJumpIfPktAtR0ContainDnsA(needlesMatch, DROP_LABEL)
945 .addPass()
946 .generate()
947 var dataRegion = ByteArray(Counter.totalSize()) { 0 }
948 assertVerdict(MIN_APF_VERSION_IN_DEV, DROP, program, badUdpPayload, dataRegion)
949 var counterMap = decodeCountersIntoMap(dataRegion)
950 assertEquals(mapOf<Counter, Long>(
951 Counter.TOTAL_PACKETS to 1,
Yuyang Huangd6eb4fc2024-03-22 10:50:25 +0900952 Counter.CORRUPT_DNS_PACKET to 1
953 ), counterMap)
Yuyang Huangebd52752024-02-20 17:08:55 +0900954
955 program = ApfV6Generator()
956 .addData(byteArrayOf())
957 .addLoadImmediate(R0, 0)
958 .addJumpIfPktAtR0ContainDnsASafe(needlesMatch, DROP_LABEL)
959 .addPass()
960 .generate()
961 dataRegion = ByteArray(Counter.totalSize()) { 0 }
962 assertVerdict(MIN_APF_VERSION_IN_DEV, PASS, program, badUdpPayload, dataRegion)
963 counterMap = decodeCountersIntoMap(dataRegion)
964 assertEquals(mapOf<Counter, Long>(
965 Counter.TOTAL_PACKETS to 1,
Yuyang Huangd6eb4fc2024-03-22 10:50:25 +0900966 Counter.CORRUPT_DNS_PACKET to 1
967 ), counterMap)
Yuyang Huangebd52752024-02-20 17:08:55 +0900968 }
969
Yuyang Huang2f3f4492024-02-22 16:52:17 +0900970 @Test
971 fun testGetCounterValue() {
972 val counterBytes = intArrayOf(0xff, 0, 0, 0, 0x78, 0x56, 0x34, 0x12)
973 .map { it.toByte() }.toByteArray()
974 assertEquals(0xff, ApfCounterTracker.getCounterValue(counterBytes, Counter.TOTAL_PACKETS))
975 }
976
Yuyang Huangc11962e2024-02-14 20:37:06 +0900977 private fun decodeCountersIntoMap(counterBytes: ByteArray): Map<Counter, Long> {
978 val counters = Counter::class.java.enumConstants
979 val ret = HashMap<Counter, Long>()
980 // starting from index 2 to skip the endianness mark
981 for (c in listOf(*counters).subList(2, counters.size)) {
982 val value = ApfCounterTracker.getCounterValue(counterBytes, c)
983 if (value != 0L) {
984 ret[c] = value
985 }
986 }
987 return ret
988 }
989
Yuyang Huangae57be02023-10-16 17:49:31 +0900990 private fun encodeInstruction(opcode: Int, immLength: Int, register: Int): Byte {
Yuyang Huang73c6d2d2023-10-19 13:32:37 +0900991 val immLengthEncoding = if (immLength == 4) 3 else immLength
992 return opcode.shl(3).or(immLengthEncoding.shl(1)).or(register).toByte()
Yuyang Huangae57be02023-10-16 17:49:31 +0900993 }
Yuyang Huangbcfa09b2024-02-20 11:20:47 +0900994
995 companion object {
996 const val ETH_HLEN = 14
997 const val IPV4_HLEN = 20
998 const val IPPROTO_UDP = 17
999 }
Yuyang Huangae57be02023-10-16 17:49:31 +09001000}