On Sun, 2024-04-28 at 23:15 +0800, Xu Kuohai wrote:
[...]
diff --git a/kernel/bpf/tnum.c b/kernel/bpf/tnum.c index 9dbc31b25e3d..9d4480a683ca 100644 --- a/kernel/bpf/tnum.c +++ b/kernel/bpf/tnum.c @@ -150,6 +150,29 @@ struct tnum tnum_intersect(struct tnum a, struct tnum b) return TNUM(v & ~mu, mu); }
+/*
- Each bit has 3 states: unkown, known 0, known 1. If using x to represent
- unknown state, the result of the union of two bits is as follows:
| x 0 1
- -----+------------
x | x x x
0 | x 0 x
1 | x x 1
- For tnum a and b, only the bits that are both known 0 or known 1 in a
- and b are known in the result of union a and b.
- */
+struct tnum tnum_union(struct tnum a, struct tnum b) +{
u64 v0, v1, mu;
mu = a.mask | b.mask; // unkown bits either in a or b
v1 = (a.value & b.value) & ~mu; // "known 1" bits in both a and b
v0 = (~a.value & ~b.value) & ~mu; // "known 0" bits in both a and b
return TNUM(v1, mu | ~(v0 | v1));
+}
Zero would be represented as {.value=0,.mask=0}, suppose 'b' is zero:
1. mu = a.mask | 0; 2. mu = a.mask; v1 = (a.value & 0) & ~mu; v1 = 0; v0 = (~a.value & ~0) & ~mu; v0 = ~a.value & ~mu; return TNUM(v1, mu | ~(v0 | v1)); return TNUM(v1, mu | ~(v0 | v1));
3. v1 = 0; 4. v1 = 0; v0 = ~a.value & ~a.mask; v0 = ~a.value & ~a.mask; return TNUM(v1, a.mask | ~(v0 | v1)); return TNUM(0, a.mask | ~(~a.value & ~a.mask));
5. return TNUM(0, a.mask | a.value)
So ultimately this says that for 1's that we knew we no longer know if those are 1's. Which seems to make sense.