• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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  */
16 
17 package android.net.apf;
18 
19 import static android.net.apf.ApfConstants.IPV4_FRAGMENT_MORE_FRAGS_MASK;
20 import static android.net.apf.ApfConstants.IPV4_FRAGMENT_OFFSET_MASK;
21 import static android.net.apf.ApfConstants.IPV4_FRAGMENT_OFFSET_OFFSET;
22 import static android.net.apf.ApfCounterTracker.Counter.PASSED_IPV6_ICMP;
23 import static android.net.apf.BaseApfGenerator.Rbit.Rbit0;
24 import static android.net.apf.BaseApfGenerator.Register.R0;
25 import static android.net.apf.BaseApfGenerator.Register.R1;
26 
27 
28 import android.annotation.NonNull;
29 
30 import com.android.internal.annotations.VisibleForTesting;
31 
32 import java.util.List;
33 import java.util.Set;
34 
35 /**
36  * APF assembler/generator.  A tool for generating an APF program.
37  *
38  * Call add*() functions to add instructions to the program, then call
39  * {@link BaseApfGenerator#generate} to get the APF bytecode for the program.
40  * <p>
41  * Choose between these approaches for your instruction helper methods: If the functionality must
42  * be identical across APF versions, make it a final method within the base class. If it needs
43  * version-specific adjustments, use an abstract method in the base class with final
44  * implementations in generator instances.
45  *
46  * @param <Type> the generator class
47  *
48  * @hide
49  */
50 public abstract class ApfV4GeneratorBase<Type extends ApfV4GeneratorBase<Type>> extends
51         BaseApfGenerator {
52 
53     /**
54      * Creates an ApfV4GeneratorBase instance which is able to emit instructions for the specified
55      * {@code version} of the APF interpreter. Throws {@code IllegalInstructionException} if
56      * the requested version is unsupported.
57      */
58     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
ApfV4GeneratorBase(int version, int ramSize, int clampSize, boolean disableCounterRangeCheck)59     public ApfV4GeneratorBase(int version, int ramSize, int clampSize,
60             boolean disableCounterRangeCheck) throws IllegalInstructionException {
61         super(version, ramSize, clampSize, disableCounterRangeCheck);
62         requireApfVersion(APF_VERSION_2);
63     }
64 
self()65     final Type self() {
66         return (Type) this;
67     }
68 
append(Instruction instruction)69     final Type append(Instruction instruction) {
70         if (mGenerated) {
71             throw new IllegalStateException("Program already generated");
72         }
73         mInstructions.add(instruction);
74         return self();
75     }
76 
77     /**
78      * Define a label at the current end of the program. Jumps can jump to this label. Labels are
79      * their own separate instructions, though with size 0. This facilitates having labels with
80      * no corresponding code to execute, for example a label at the end of a program. For example
81      * an {@link ApfV4GeneratorBase} might be passed to a function that adds a filter like so:
82      * <pre>
83      *   load from packet
84      *   compare loaded data, jump if not equal to "next_filter"
85      *   load from packet
86      *   compare loaded data, jump if not equal to "next_filter"
87      *   jump to drop label
88      *   define "next_filter" here
89      * </pre>
90      * In this case "next_filter" may not have any generated code associated with it.
91      */
defineLabel(short name)92     public final Type defineLabel(short name) throws IllegalInstructionException {
93         return append(new Instruction(Opcodes.LABEL).setLabel(name));
94     }
95 
96     /**
97      * Add an unconditional jump instruction to the end of the program.
98      */
addJump(short target)99     public final Type addJump(short target) {
100         return append(new Instruction(Opcodes.JMP).setTargetLabel(target));
101     }
102 
103     /**
104      * Add an unconditional jump instruction to the next instruction - ie. a no-op.
105      */
addNop()106     public final Type addNop() {
107         return append(new Instruction(Opcodes.JMP).addUnsigned(0));
108     }
109 
110     /**
111      * Add an instruction to the end of the program to load the byte at offset {@code offset}
112      * bytes from the beginning of the packet into {@code register}.
113      */
addLoad8intoR0(int ofs)114     public final Type addLoad8intoR0(int ofs) {
115         return append(new Instruction(Opcodes.LDB, R0).addPacketOffset(ofs));
116     }
117 
118     /**
119      * Add an instruction to the end of the program to load 16-bits at offset {@code offset}
120      * bytes from the beginning of the packet into {@code register}.
121      */
addLoad16intoR0(int ofs)122     public final Type addLoad16intoR0(int ofs) {
123         return append(new Instruction(Opcodes.LDH, R0).addPacketOffset(ofs));
124     }
125 
126     /**
127      * Add an instruction to the end of the program to load 32-bits at offset {@code offset}
128      * bytes from the beginning of the packet into {@code register}.
129      */
addLoad32intoR0(int ofs)130     public final Type addLoad32intoR0(int ofs) {
131         return append(new Instruction(Opcodes.LDW, R0).addPacketOffset(ofs));
132     }
133 
134     /**
135      * Add an instruction to the end of the program to load a byte from the packet into
136      * {@code register}. The offset of the loaded byte from the beginning of the packet is
137      * the sum of {@code offset} and the value in register R1.
138      */
addLoad8R1IndexedIntoR0(int ofs)139     public final Type addLoad8R1IndexedIntoR0(int ofs) {
140         return append(new Instruction(Opcodes.LDBX, R0).addTwosCompUnsigned(ofs));
141     }
142 
143     /**
144      * Add an instruction to the end of the program to load 16-bits from the packet into
145      * {@code register}. The offset of the loaded 16-bits from the beginning of the packet is
146      * the sum of {@code offset} and the value in register R1.
147      */
addLoad16R1IndexedIntoR0(int ofs)148     public final Type addLoad16R1IndexedIntoR0(int ofs) {
149         return append(new Instruction(Opcodes.LDHX, R0).addTwosCompUnsigned(ofs));
150     }
151 
152     /**
153      * Add an instruction to the end of the program to load 32-bits from the packet into
154      * {@code register}. The offset of the loaded 32-bits from the beginning of the packet is
155      * the sum of {@code offset} and the value in register R1.
156      */
addLoad32R1IndexedIntoR0(int ofs)157     public final Type addLoad32R1IndexedIntoR0(int ofs) {
158         return append(new Instruction(Opcodes.LDWX, R0).addTwosCompUnsigned(ofs));
159     }
160 
161     /**
162      * Add an instruction to the end of the program to add {@code value} to register R0.
163      */
addAdd(long val)164     public abstract Type addAdd(long val);
165 
166     /**
167      * Add an instruction to the end of the program to subtract {@code value} from register R0.
168      */
addSub(long val)169     public final Type addSub(long val) {
170         return addAdd(-val);  // note: addSub(4 billion) isn't valid, as addAdd(-4 billion) isn't
171     }
172 
173     /**
174      * Add an instruction to the end of the program to multiply register R0 by {@code value}.
175      */
addMul(long val)176     public final Type addMul(long val) {
177         if (val == 0) return addLoadImmediate(R0, 0);  // equivalent, as APFv6 would '*= R1'
178         return append(new Instruction(Opcodes.MUL).addUnsigned(val));
179     }
180 
181     /**
182      * Add an instruction to the end of the program to divide register R0 by {@code value}.
183      */
addDiv(long val)184     public final Type addDiv(long val) {
185         if (val == 0) return addPass();  // equivalent, as APFv6 would '/= R1'
186         return append(new Instruction(Opcodes.DIV).addUnsigned(val));
187     }
188 
189     /**
190      * Add an instruction to the end of the program to logically and register R0 with {@code value}.
191      */
addAnd(long val)192     public abstract Type addAnd(long val);
193 
194     /**
195      * Add an instruction to the end of the program to logically or register R0 with {@code value}.
196      */
addOr(long val)197     public final Type addOr(long val) {
198         if (val == 0) return self();  // nop, as APFv6 would '|= R1'
199         return append(new Instruction(Opcodes.OR).addTwosCompUnsigned(val));
200     }
201 
202     /**
203      * Add an instruction to the end of the program to shift left register R0 by {@code value} bits.
204      */
205     // TODO: consider whether should change the argument type to byte
addLeftShift(int val)206     public final Type addLeftShift(int val) {
207         if (val == 0) return self();  // nop, as APFv6 would '<<= R1'
208         return append(new Instruction(Opcodes.SH).addSigned(val));
209     }
210 
211     /**
212      * Add an instruction to the end of the program to shift right register R0 by {@code value}
213      * bits.
214      */
215     // TODO: consider whether should change the argument type to byte
addRightShift(int val)216     public final Type addRightShift(int val) {
217         return addLeftShift(-val);
218     }
219 
220     // R0 op= R1, where op should be one of Opcodes.{ADD,MUL,DIV,AND,OR,SH}
addR0ArithR1(Opcodes opcode)221     abstract void addR0ArithR1(Opcodes opcode);
222 
223     /**
224      * Add an instruction to the end of the program to add register R1 to register R0.
225      */
addAddR1ToR0()226     public final Type addAddR1ToR0() {
227         addR0ArithR1(Opcodes.ADD);  // R0 += R1
228         return self();
229     }
230 
231     /**
232      * Add an instruction to the end of the program to multiply register R0 by register R1.
233      */
addMulR0ByR1()234     public final Type addMulR0ByR1() {
235         addR0ArithR1(Opcodes.MUL);  // R0 *= R1
236         return self();
237     }
238 
239     /**
240      * Add an instruction to the end of the program to divide register R0 by register R1.
241      */
addDivR0ByR1()242     public final Type addDivR0ByR1() {
243         addR0ArithR1(Opcodes.DIV);  // R0 /= R1
244         return self();
245     }
246 
247     /**
248      * Add an instruction to the end of the program to logically and register R0 with register R1
249      * and store the result back into register R0.
250      */
addAndR0WithR1()251     public final Type addAndR0WithR1() {
252         addR0ArithR1(Opcodes.AND);  // R0 &= R1
253         return self();
254     }
255 
256     /**
257      * Add an instruction to the end of the program to logically or register R0 with register R1
258      * and store the result back into register R0.
259      */
addOrR0WithR1()260     public final Type addOrR0WithR1() {
261         addR0ArithR1(Opcodes.OR);  // R0 |= R1
262         return self();
263     }
264 
265     /**
266      * Add an instruction to the end of the program to shift register R0 left by the value in
267      * register R1.
268      */
addLeftShiftR0ByR1()269     public final Type addLeftShiftR0ByR1() {
270         addR0ArithR1(Opcodes.SH);  // R0 <<= R1
271         return self();
272     }
273 
274     /**
275      * Add an instruction to the end of the program to move {@code value} into {@code register}.
276      */
addLoadImmediate(Register register, int value)277     public final Type addLoadImmediate(Register register, int value) {
278         return append(new Instruction(Opcodes.LI, register).addSigned(value));
279     }
280 
281     /**
282      * Add an instruction to the end of the program to jump to {@code target} if register R0's
283      * value equals {@code value}.
284      */
addJumpIfR0Equals(long val, short tgt)285     public final Type addJumpIfR0Equals(long val, short tgt) {
286         return append(new Instruction(Opcodes.JEQ).addTwosCompUnsigned(val).setTargetLabel(tgt));
287     }
288 
289     /**
290      * Add instructions to the end of the program to increase counter and drop packet if R0 equals
291      * {@code val}
292      * WARNING: may modify R1
293      */
addCountAndDropIfR0Equals(long val, ApfCounterTracker.Counter cnt)294     public abstract Type addCountAndDropIfR0Equals(long val, ApfCounterTracker.Counter cnt)
295             throws IllegalInstructionException;
296 
297     /**
298      * Add instructions to the end of the program to increase counter and pass packet if R0 equals
299      * {@code val}
300      * WARNING: may modify R1
301      */
addCountAndPassIfR0Equals(long val, ApfCounterTracker.Counter cnt)302     public abstract Type addCountAndPassIfR0Equals(long val, ApfCounterTracker.Counter cnt)
303             throws IllegalInstructionException;
304 
305     /**
306      * Add an instruction to the end of the program to jump to {@code target} if register R0's
307      * value does not equal {@code value}.
308      */
addJumpIfR0NotEquals(long val, short tgt)309     public final Type addJumpIfR0NotEquals(long val, short tgt) {
310         return append(new Instruction(Opcodes.JNE).addTwosCompUnsigned(val).setTargetLabel(tgt));
311     }
312 
313     /**
314      * Add instructions to the end of the program to increase counter and drop packet if R0 not
315      * equals {@code val}
316      * WARNING: may modify R1
317      */
addCountAndDropIfR0NotEquals(long val, ApfCounterTracker.Counter cnt)318     public abstract Type addCountAndDropIfR0NotEquals(long val, ApfCounterTracker.Counter cnt)
319             throws IllegalInstructionException;
320 
321     /**
322      * Add instructions to the end of the program to increase counter and pass packet if R0 not
323      * equals {@code val}
324      * WARNING: may modify R1
325      */
addCountAndPassIfR0NotEquals(long val, ApfCounterTracker.Counter cnt)326     public abstract Type addCountAndPassIfR0NotEquals(long val, ApfCounterTracker.Counter cnt)
327             throws IllegalInstructionException;
328 
329     /**
330      * Add an instruction to the end of the program to jump to {@code target} if register R0's
331      * value is greater than {@code value}.
332      */
addJumpIfR0GreaterThan(long val, short tgt)333     public final Type addJumpIfR0GreaterThan(long val, short tgt) {
334         return append(new Instruction(Opcodes.JGT).addUnsigned(val).setTargetLabel(tgt));
335     }
336 
337     /**
338      * Add instructions to the end of the program to increase counter and drop packet if R0 greater
339      * than {@code val}
340      * WARNING: may modify R1
341      */
addCountAndDropIfR0GreaterThan(long val, ApfCounterTracker.Counter cnt)342     public abstract Type addCountAndDropIfR0GreaterThan(long val, ApfCounterTracker.Counter cnt)
343             throws IllegalInstructionException;
344 
345     /**
346      * Add instructions to the end of the program to increase counter and pass packet if R0 greater
347      * than {@code val}
348      * WARNING: may modify R1
349      */
addCountAndPassIfR0GreaterThan(long val, ApfCounterTracker.Counter cnt)350     public abstract Type addCountAndPassIfR0GreaterThan(long val, ApfCounterTracker.Counter cnt)
351             throws IllegalInstructionException;
352 
353     /**
354      * Add an instruction to the end of the program to jump to {@code target} if register R0's
355      * value is less than {@code value}.
356      */
addJumpIfR0LessThan(long val, short tgt)357     public final Type addJumpIfR0LessThan(long val, short tgt) {
358         return append(new Instruction(Opcodes.JLT).addUnsigned(val).setTargetLabel(tgt));
359     }
360 
361     /**
362      * Add instructions to the end of the program to increase counter and drop packet if R0 less
363      * than {@code val}
364      * WARNING: may modify R1
365      */
addCountAndDropIfR0LessThan(long val, ApfCounterTracker.Counter cnt)366     public abstract Type addCountAndDropIfR0LessThan(long val, ApfCounterTracker.Counter cnt)
367             throws IllegalInstructionException;
368 
369     /**
370      * Add instructions to the end of the program to increase counter and pass packet if R0 less
371      * than {@code val}
372      * WARNING: may modify R1
373      */
addCountAndPassIfR0LessThan(long val, ApfCounterTracker.Counter cnt)374     public abstract Type addCountAndPassIfR0LessThan(long val, ApfCounterTracker.Counter cnt)
375             throws IllegalInstructionException;
376 
377     /**
378      * Add an instruction to the end of the program to jump to {@code target} if register R0's
379      * value has any bits set that are also set in {@code value}.
380      */
addJumpIfR0AnyBitsSet(long val, short tgt)381     public final Type addJumpIfR0AnyBitsSet(long val, short tgt) {
382         return append(new Instruction(Opcodes.JSET).addTwosCompUnsigned(val).setTargetLabel(tgt));
383     }
384 
385     /**
386      * Add an instruction to the end of the program to count and drop packet if register R0's
387      * value has any bits set that are also set in {@code value}.
388      * WARNING: may modify R1
389      */
addCountAndDropIfR0AnyBitsSet(long val, ApfCounterTracker.Counter cnt)390     public abstract Type addCountAndDropIfR0AnyBitsSet(long val, ApfCounterTracker.Counter cnt)
391             throws IllegalInstructionException;
392 
393     /**
394      * Add an instruction to the end of the program to count and pass packet if register R0's
395      * value has any bits set that are also set in {@code value}.
396      * WARNING: may modify R1
397      */
addCountAndPassIfR0AnyBitsSet(long val, ApfCounterTracker.Counter cnt)398     public abstract Type addCountAndPassIfR0AnyBitsSet(long val, ApfCounterTracker.Counter cnt)
399             throws IllegalInstructionException;
400 
401     /**
402      * Add an instruction to the end of the program to count and drop if the bytes of the
403      * packet at an offset specified by register R0 match any of the elements in {@code bytesList}.
404      * WARNING: may modify R1
405      */
addCountAndDropIfBytesAtR0EqualsAnyOf(@onNull List<byte[]> bytesList, ApfCounterTracker.Counter cnt)406     public abstract Type addCountAndDropIfBytesAtR0EqualsAnyOf(@NonNull List<byte[]> bytesList,
407             ApfCounterTracker.Counter cnt) throws IllegalInstructionException;
408 
409     /**
410      * Add an instruction to the end of the program to count and pass if the bytes of the
411      * packet at an offset specified by register R0 match any of the elements in {@code bytesList}.
412      * WARNING: may modify R1
413      */
addCountAndPassIfBytesAtR0EqualsAnyOf(@onNull List<byte[]> bytesList, ApfCounterTracker.Counter cnt)414     public abstract Type addCountAndPassIfBytesAtR0EqualsAnyOf(@NonNull List<byte[]> bytesList,
415             ApfCounterTracker.Counter cnt) throws IllegalInstructionException;
416 
417     /**
418      * Add an instruction to the end of the program to count and drop if the bytes of the
419      * packet at an offset specified by register R0 match none the elements in {@code bytesList}.
420      * WARNING: may modify R1
421      */
addCountAndDropIfBytesAtR0EqualsNoneOf(@onNull List<byte[]> bytesList, ApfCounterTracker.Counter cnt)422     public abstract Type addCountAndDropIfBytesAtR0EqualsNoneOf(@NonNull List<byte[]> bytesList,
423             ApfCounterTracker.Counter cnt) throws IllegalInstructionException;
424 
425     /**
426      * Add an instruction to the end of the program to count and pass if the bytes of the
427      * packet at an offset specified by register R0 match none of the elements in {@code bytesList}.
428      * WARNING: may modify R1
429      */
addCountAndPassIfBytesAtR0EqualsNoneOf(@onNull List<byte[]> bytesList, ApfCounterTracker.Counter cnt)430     public abstract Type addCountAndPassIfBytesAtR0EqualsNoneOf(@NonNull List<byte[]> bytesList,
431             ApfCounterTracker.Counter cnt) throws IllegalInstructionException;
432 
433     /**
434      * Add an instruction to the end of the program to jump to {@code target} if register R0's
435      * value equals register R1's value.
436      */
addJumpIfR0EqualsR1(short tgt)437     public final Type addJumpIfR0EqualsR1(short tgt) {
438         return append(new Instruction(Opcodes.JEQ, R1).setTargetLabel(tgt));
439     }
440 
441     /**
442      * Add an instruction to the end of the program to jump to {@code target} if register R0's
443      * value does not equal register R1's value.
444      */
addJumpIfR0NotEqualsR1(short tgt)445     public final Type addJumpIfR0NotEqualsR1(short tgt) {
446         return append(new Instruction(Opcodes.JNE, R1).setTargetLabel(tgt));
447     }
448 
449     /**
450      * Add an instruction to the end of the program to jump to {@code target} if register R0's
451      * value is greater than register R1's value.
452      */
addJumpIfR0GreaterThanR1(short tgt)453     public final Type addJumpIfR0GreaterThanR1(short tgt) {
454         return append(new Instruction(Opcodes.JGT, R1).setTargetLabel(tgt));
455     }
456 
457     /**
458      * Add an instruction to the end of the program to jump to {@code target} if register R0's
459      * value is less than register R1's value.
460      */
addJumpIfR0LessThanR1(short target)461     public final Type addJumpIfR0LessThanR1(short target) {
462         return append(new Instruction(Opcodes.JLT, R1).setTargetLabel(target));
463     }
464 
465     /**
466      * Add an instruction to the end of the program to jump to {@code target} if register R0's
467      * value has any bits set that are also set in R1's value.
468      */
addJumpIfR0AnyBitsSetR1(short tgt)469     public final Type addJumpIfR0AnyBitsSetR1(short tgt) {
470         return append(new Instruction(Opcodes.JSET, R1).setTargetLabel(tgt));
471     }
472 
473     /**
474      * Add an instruction to the end of the program to jump to {@code tgt} if the bytes of the
475      * packet at an offset specified by register0 don't match {@code bytes}.
476      * R=0 means check for not equal.
477      */
addJumpIfBytesAtR0NotEqual(@onNull byte[] bytes, short tgt)478     public final Type addJumpIfBytesAtR0NotEqual(@NonNull byte[] bytes, short tgt) {
479         validateBytes(bytes);
480         return append(new Instruction(Opcodes.JBSMATCH).addUnsigned(
481                 bytes.length).setTargetLabel(tgt).setBytesImm(bytes));
482     }
483 
484     /**
485      * Add an instruction to the end of the program to jump to {@code tgt} if the bytes of the
486      * packet at an offset specified by {@code offset} don't match {@code bytes}.
487      * This method needs to be non-final because APFv4 and APFv6 share the same implementation,
488      * but in APFv6.1, this method will be overridden to use the JBSPTRMATCH instruction.
489      */
addJumpIfBytesAtOffsetNotEqual(int offset, @NonNull byte[] bytes, short tgt)490     public Type addJumpIfBytesAtOffsetNotEqual(int offset, @NonNull byte[] bytes, short tgt)
491             throws IllegalInstructionException {
492         return addLoadImmediate(R0, offset).addJumpIfBytesAtR0NotEqual(bytes, tgt);
493     }
494 
495     /**
496      * Add instructions to the end of the program to increase counter and drop packet if the
497      * bytes of the packet at an offset specified by register0 don't match {@code bytes}.
498      * WARNING: may modify R1
499      */
addCountAndDropIfBytesAtR0NotEqual(byte[] bytes, ApfCounterTracker.Counter cnt)500     public abstract Type addCountAndDropIfBytesAtR0NotEqual(byte[] bytes,
501             ApfCounterTracker.Counter cnt) throws IllegalInstructionException;
502 
503     /**
504      * Add instructions to the end of the program to increase counter and pass packet if the
505      * bytes of the packet at an offset specified by register0 don't match {@code bytes}.
506      * WARNING: may modify R1
507      */
addCountAndPassIfBytesAtR0NotEqual(byte[] bytes, ApfCounterTracker.Counter cnt)508     public abstract Type addCountAndPassIfBytesAtR0NotEqual(byte[] bytes,
509             ApfCounterTracker.Counter cnt) throws IllegalInstructionException;
510 
511     /**
512      * Add instructions to the end of the program to increase counter and drop packet if the
513      * bytes of the packet at an offset specified by {@code offset} don't match {@code bytes}.
514      * This method needs to be non-final because APFv4 and APFv6 share the same implementation,
515      * but in APFv6.1, this method will be overridden to use the JBSPTRMATCH instruction.
516      */
addCountAndDropIfBytesAtOffsetNotEqual(int offset, byte[] bytes, ApfCounterTracker.Counter cnt)517     public Type addCountAndDropIfBytesAtOffsetNotEqual(int offset, byte[] bytes,
518             ApfCounterTracker.Counter cnt) throws IllegalInstructionException {
519         return addLoadImmediate(R0, offset).addCountAndDropIfBytesAtR0NotEqual(bytes, cnt);
520     }
521 
522     /**
523      * Add instructions to the end of the program to increase counter and pass packet if the
524      * bytes of the packet at an offset specified by {@code offset} don't match {@code bytes}.
525      * This method needs to be non-final because APFv4 and APFv6 share the same implementation,
526      * but in APFv6.1, this method will be overridden to use the JBSPTRMATCH instruction.
527      */
addCountAndPassIfBytesAtOffsetNotEqual(int offset, byte[] bytes, ApfCounterTracker.Counter cnt)528     public Type addCountAndPassIfBytesAtOffsetNotEqual(int offset, byte[] bytes,
529             ApfCounterTracker.Counter cnt) throws IllegalInstructionException {
530         return addLoadImmediate(R0, offset).addCountAndPassIfBytesAtR0NotEqual(bytes, cnt);
531     }
532 
533     /**
534      * Add instructions to the end of the program to increase counter and drop packet if the
535      * bytes of the packet at an offset specified by {@code offset} does match {@code bytes}.
536      * This method needs to be non-final because APFv4 and APFv6 share the same implementation,
537      * but in APFv6.1, this method will be overridden to use the JBSPTRMATCH instruction.
538      */
addCountAndDropIfBytesAtOffsetEqual(int offset, byte[] bytes, ApfCounterTracker.Counter cnt)539     public Type addCountAndDropIfBytesAtOffsetEqual(int offset, byte[] bytes,
540             ApfCounterTracker.Counter cnt) throws IllegalInstructionException {
541         return addLoadImmediate(R0, offset).addCountAndDropIfBytesAtR0Equal(bytes, cnt);
542     }
543 
544     /**
545      * Add instructions to the end of the program to increase counter and pass packet if the
546      * bytes of the packet at an offset specified by {@code offset} does match {@code bytes}.
547      * This method needs to be non-final because APFv4 and APFv6 share the same implementation,
548      * but in APFv6.1, this method will be overridden to use the JBSPTRMATCH instruction.
549      */
addCountAndPassIfBytesAtOffsetEqual(int offset, byte[] bytes, ApfCounterTracker.Counter cnt)550     public Type addCountAndPassIfBytesAtOffsetEqual(int offset, byte[] bytes,
551             ApfCounterTracker.Counter cnt) throws IllegalInstructionException {
552         return addLoadImmediate(R0, offset).addCountAndPassIfBytesAtR0Equal(bytes, cnt);
553     }
554 
555     /**
556      * Add instructions to the end of the program to increase counter and drop packet if the
557      * bytes of the packet at an offset specified by register0 match {@code bytes}.
558      * WARNING: may modify R1
559      */
addCountAndDropIfBytesAtR0Equal(byte[] bytes, ApfCounterTracker.Counter cnt)560     public final Type addCountAndDropIfBytesAtR0Equal(byte[] bytes,
561             ApfCounterTracker.Counter cnt) throws IllegalInstructionException {
562         final short tgt = getUniqueLabel();
563         return addJumpIfBytesAtR0NotEqual(bytes, tgt).addCountAndDrop(cnt).defineLabel(tgt);
564     }
565 
566 
567     /**
568      * Add instructions to the end of the program to increase counter and pass packet if the
569      * bytes of the packet at an offset specified by register0 match {@code bytes}.
570      * WARNING: may modify R1
571      */
addCountAndPassIfBytesAtR0Equal(byte[] bytes, ApfCounterTracker.Counter cnt)572     public final Type addCountAndPassIfBytesAtR0Equal(byte[] bytes,
573             ApfCounterTracker.Counter cnt) throws IllegalInstructionException {
574         final short tgt = getUniqueLabel();
575         return addJumpIfBytesAtR0NotEqual(bytes, tgt).addCountAndPass(cnt).defineLabel(tgt);
576     }
577 
578     /**
579      * Add instructions to the end of the program to increase counter and pass packet if the
580      * value in register0 is one of {@code values}.
581      * WARNING: may modify R1
582      */
addCountAndPassIfR0IsOneOf(@onNull Set<Long> values, ApfCounterTracker.Counter cnt)583     public abstract Type addCountAndPassIfR0IsOneOf(@NonNull Set<Long> values,
584             ApfCounterTracker.Counter cnt) throws IllegalInstructionException;
585 
586     /**
587      * Add instructions to the end of the program to increase counter and drop packet if the
588      * value in register0 is one of {@code values}.
589      * WARNING: may modify R1
590      */
addCountAndDropIfR0IsOneOf(@onNull Set<Long> values, ApfCounterTracker.Counter cnt)591     public abstract Type addCountAndDropIfR0IsOneOf(@NonNull Set<Long> values,
592             ApfCounterTracker.Counter cnt) throws IllegalInstructionException;
593 
594     /**
595      * Add instructions to the end of the program to increase counter and pass packet if the
596      * value in register0 is none of {@code values}.
597      * WARNING: may modify R1
598      */
addCountAndPassIfR0IsNoneOf(@onNull Set<Long> values, ApfCounterTracker.Counter cnt)599     public abstract Type addCountAndPassIfR0IsNoneOf(@NonNull Set<Long> values,
600             ApfCounterTracker.Counter cnt) throws IllegalInstructionException;
601 
602     /**
603      * Add instructions to the end of the program to increase counter and drop packet if the
604      * value in register0 is none of {@code values}.
605      * WARNING: may modify R1
606      */
addCountAndDropIfR0IsNoneOf(@onNull Set<Long> values, ApfCounterTracker.Counter cnt)607     public abstract Type addCountAndDropIfR0IsNoneOf(@NonNull Set<Long> values,
608             ApfCounterTracker.Counter cnt) throws IllegalInstructionException;
609 
610     /**
611      * Add an instruction to the end of the program to load memory slot {@code slot} into
612      * {@code register}.
613      */
addLoadFromMemory(Register r, MemorySlot slot)614     public final Type addLoadFromMemory(Register r, MemorySlot slot)
615             throws IllegalInstructionException {
616         return append(new BaseApfGenerator.Instruction(ExtendedOpcodes.LDM, slot.value, r));
617     }
618 
619     /**
620      * Add an instruction to the end of the program to store {@code register} into memory slot
621      * {@code slot}.
622      */
addStoreToMemory(MemorySlot slot, Register r)623     public final Type addStoreToMemory(MemorySlot slot, Register r)
624             throws IllegalInstructionException {
625         return append(new Instruction(ExtendedOpcodes.STM, slot.value, r));
626     }
627 
628     /**
629      * Add instructions to the end of the program to check whether the packet is an unfragmented
630      * IPv4 packet with the specified protocol, and jump to the target if it is not.
631      * WARNING: this helper method will modify R0
632      */
addJumpIfNotUnfragmentedIPv4Protocol(long protocol, short tgt)633     public Type addJumpIfNotUnfragmentedIPv4Protocol(long protocol, short tgt) {
634         // Mask out all but the reserved and don't fragment bits, plus the TTL field.
635         // Because:
636         //   IPV4_FRAGMENT_OFFSET_MASK = 0x1fff
637         //   IPV4_FRAGMENT_MORE_FRAGS_MASK = 0x2000
638         // hence this constant ends up being 0x3FFF00FF.
639         // We want the more flag bit and offset to be 0 (ie. not a fragment),
640         // so after this masking we end up with just the ip protocol.
641         return addLoad32intoR0(IPV4_FRAGMENT_OFFSET_OFFSET)
642                 .addAnd((IPV4_FRAGMENT_MORE_FRAGS_MASK | IPV4_FRAGMENT_OFFSET_MASK) << 16 | 0xFF)
643                 .addJumpIfR0NotEquals(protocol, tgt);
644     }
645 
646     /**
647      * Add an instruction to the end of the program to logically not {@code register}.
648      */
addNot(Register r)649     public final Type addNot(Register r) {
650         return append(new Instruction(ExtendedOpcodes.NOT, r));
651     }
652 
653     /**
654      * Add an instruction to the end of the program to negate {@code register}.
655      */
addNeg(Register r)656     public final Type addNeg(Register r) {
657         return append(new Instruction(ExtendedOpcodes.NEG, r));
658     }
659 
660     /**
661      * Add an instruction to swap the values in register R0 and register R1.
662      */
addSwap()663     public final Type addSwap() {
664         return append(new Instruction(ExtendedOpcodes.SWAP));
665     }
666 
667     /**
668      * Add an instruction to the end of the program to move the value into
669      * {@code register} from the other register.
670      */
addMove(Register r)671     public final Type addMove(Register r) {
672         return append(new Instruction(ExtendedOpcodes.MOVE, r));
673     }
674 
675     /**
676      * Add an instruction to the end of the program to let the program immediately return PASS.
677      */
addPass()678     public final Type addPass() {
679         // PASS requires using Rbit0 because it shares opcode with DROP
680         return append(new Instruction(Opcodes.PASSDROP, Rbit0));
681     }
682 
683     /**
684      * Abstract method for adding instructions to increment the counter and return PASS.
685      */
addCountAndPass(ApfCounterTracker.Counter counter)686     public abstract Type addCountAndPass(ApfCounterTracker.Counter counter);
687 
688     /**
689      * Abstract method for adding instructions to increment the counter and return DROP.
690      */
addCountAndDrop(ApfCounterTracker.Counter counter)691     public abstract Type addCountAndDrop(ApfCounterTracker.Counter counter);
692 
693     /**
694      * Add an instruction to the end of the program to load 32 bits from the data memory into
695      * {@code register}.
696      * In APFv2, it is a noop.
697      * WARNING: clobbers the *other* register.
698      */
addLoadCounter(Register register, ApfCounterTracker.Counter counter)699     public abstract Type addLoadCounter(Register register, ApfCounterTracker.Counter counter)
700             throws IllegalInstructionException;
701 
702     /**
703      * Add an instruction to the end of the program to store 32 bits from {@code register} into the
704      * data memory.
705      * In APFv2, it is a noop.
706      * WARNING: clobbers the *other* register.
707      */
addStoreCounter(ApfCounterTracker.Counter counter, Register register)708     public abstract Type addStoreCounter(ApfCounterTracker.Counter counter, Register register)
709             throws IllegalInstructionException;
710 
711     /**
712      * Add an instruction to the end of the program to increment counter value by {@code val).
713      * In APFv2, it is a noop.
714      * WARNING: clobbers both registers.
715      */
addIncrementCounter(ApfCounterTracker.Counter counter, int val)716     public final Type addIncrementCounter(ApfCounterTracker.Counter counter, int val)
717             throws IllegalInstructionException {
718         if (mVersion <= 2) return self();
719         return addLoadCounter(R0, counter).addAdd(val).addStoreCounter(counter, R0);
720     }
721 
722     /**
723      * Add an instruction to the end of the program to increment counter value by one.
724      * In APFv2, it is a noop.
725      * WARNING: clobbers both registers.
726      */
addIncrementCounter(ApfCounterTracker.Counter counter)727     public final Type addIncrementCounter(ApfCounterTracker.Counter counter)
728             throws IllegalInstructionException {
729         return addIncrementCounter(counter, 1);
730     }
731 
732     /**
733      * The abstract method to generate count trampoline instructions.
734      * @return
735      * @throws IllegalInstructionException
736      */
addCountTrampoline()737     public abstract Type addCountTrampoline() throws IllegalInstructionException;
738 
739     /**
740      * Returns the base program size when the interpreter is initialized.
741      */
getBaseProgramSize()742     public abstract int getBaseProgramSize();
743 
744     /**
745      * Appends default packet handling and counting to the APF program.
746      * This method adds logic to:
747      * 1. Increment the {@code PASSED_IPV6_ICMP} counter and pass the packet.
748      * 3. Add trampoline logic for counter processing.
749      *
750      *
751      * @return The type resulting from the appended instructions.
752      * @throws IllegalInstructionException If an error occurs while adding instructions.
753      */
addDefaultPacketHandling()754     public final Type addDefaultPacketHandling() throws IllegalInstructionException {
755         addCountAndPass(PASSED_IPV6_ICMP);
756         return addCountTrampoline();
757     }
758 
759     /**
760      * Returns an overestimate of the size of the default packet handling logic.
761      */
getDefaultPacketHandlingSizeOverEstimate()762     public abstract int getDefaultPacketHandlingSizeOverEstimate();
763 }
764 
765