diff mbox series

[bpf-next,1/3] bpf: simplify try_match_pkt_pointers()

Message ID 20240108132802.6103-2-eddyz87@gmail.com (mailing list archive)
State Changes Requested
Delegated to: BPF
Headers show
Series infer packet range for 'if pkt ==/!= pkt_end' instructions | expand

Checks

Context Check Description
bpf/vmtest-bpf-next-PR success PR summary
bpf/vmtest-bpf-next-VM_Test-8 success Logs for aarch64-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-7 success Logs for aarch64-gcc / test (test_progs, false, 360) / test_progs on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-6 success Logs for aarch64-gcc / test (test_maps, false, 360) / test_maps on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-9 success Logs for aarch64-gcc / test (test_verifier, false, 360) / test_verifier on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-26 success Logs for x86_64-gcc / test (test_verifier, false, 360) / test_verifier on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-19 success Logs for x86_64-gcc / build / build for x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-23 success Logs for x86_64-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-22 success Logs for x86_64-gcc / test (test_progs, false, 360) / test_progs on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-31 success Logs for x86_64-llvm-17 / test (test_progs, false, 360) / test_progs on x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-32 success Logs for x86_64-llvm-17 / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-28 success Logs for x86_64-llvm-17 / build / build for x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-17 success Logs for s390x-gcc / veristat
bpf/vmtest-bpf-next-VM_Test-18 success Logs for set-matrix
bpf/vmtest-bpf-next-VM_Test-16 success Logs for s390x-gcc / test (test_verifier, false, 360) / test_verifier on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-27 success Logs for x86_64-gcc / veristat / veristat on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-24 success Logs for x86_64-gcc / test (test_progs_no_alu32_parallel, true, 30) / test_progs_no_alu32_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-33 success Logs for x86_64-llvm-17 / test (test_verifier, false, 360) / test_verifier on x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-30 success Logs for x86_64-llvm-17 / test (test_maps, false, 360) / test_maps on x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-11 success Logs for s390x-gcc / build / build for s390x with gcc
bpf/vmtest-bpf-next-VM_Test-34 success Logs for x86_64-llvm-17 / veristat
bpf/vmtest-bpf-next-VM_Test-21 success Logs for x86_64-gcc / test (test_maps, false, 360) / test_maps on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-25 success Logs for x86_64-gcc / test (test_progs_parallel, true, 30) / test_progs_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-20 success Logs for x86_64-gcc / build-release
bpf/vmtest-bpf-next-VM_Test-35 success Logs for x86_64-llvm-18 / build / build for x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-37 success Logs for x86_64-llvm-18 / test (test_maps, false, 360) / test_maps on x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-38 success Logs for x86_64-llvm-18 / test (test_progs, false, 360) / test_progs on x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-39 success Logs for x86_64-llvm-18 / test (test_progs_cpuv4, false, 360) / test_progs_cpuv4 on x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-40 success Logs for x86_64-llvm-18 / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-41 success Logs for x86_64-llvm-18 / test (test_verifier, false, 360) / test_verifier on x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-42 success Logs for x86_64-llvm-18 / veristat
bpf/vmtest-bpf-next-VM_Test-29 success Logs for x86_64-llvm-17 / build-release / build for x86_64 with llvm-17 and -O2 optimization
bpf/vmtest-bpf-next-VM_Test-36 success Logs for x86_64-llvm-18 / build-release / build for x86_64 with llvm-18 and -O2 optimization
bpf/vmtest-bpf-next-VM_Test-14 success Logs for s390x-gcc / test (test_progs, false, 360) / test_progs on s390x with gcc
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for bpf-next
netdev/ynl success SINGLE THREAD; Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 1093 this patch: 1093
netdev/cc_maintainers success CCed 0 of 0 maintainers
netdev/build_clang success Errors and warnings before: 1109 this patch: 1109
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 1120 this patch: 1120
netdev/checkpatch warning WARNING: line length of 95 exceeds 80 columns WARNING: line length of 96 exceeds 80 columns
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0
bpf/vmtest-bpf-next-VM_Test-3 success Logs for Validate matrix.py
bpf/vmtest-bpf-next-VM_Test-2 success Logs for Unittests
bpf/vmtest-bpf-next-VM_Test-1 success Logs for ShellCheck
bpf/vmtest-bpf-next-VM_Test-0 success Logs for Lint
bpf/vmtest-bpf-next-VM_Test-4 success Logs for aarch64-gcc / build / build for aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-5 success Logs for aarch64-gcc / build-release
bpf/vmtest-bpf-next-VM_Test-10 success Logs for aarch64-gcc / veristat
bpf/vmtest-bpf-next-VM_Test-13 success Logs for set-matrix
bpf/vmtest-bpf-next-VM_Test-12 success Logs for s390x-gcc / build-release
bpf/vmtest-bpf-next-VM_Test-15 success Logs for x86_64-gcc / build-release

Commit Message

Eduard Zingerman Jan. 8, 2024, 1:28 p.m. UTC
Reduce number of cases handled in try_match_pkt_pointers()
to <pkt_data> <op> <pkt_end> or <pkt_meta> <op> <pkt_data>
by flipping opcode.

Suggested-by: Andrii Nakryiko <andrii.nakryiko@gmail.com>
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
---
 kernel/bpf/verifier.c | 104 ++++++++++--------------------------------
 1 file changed, 24 insertions(+), 80 deletions(-)

Comments

Andrii Nakryiko Jan. 9, 2024, 12:40 a.m. UTC | #1
On Mon, Jan 8, 2024 at 5:28 AM Eduard Zingerman <eddyz87@gmail.com> wrote:
>
> Reduce number of cases handled in try_match_pkt_pointers()
> to <pkt_data> <op> <pkt_end> or <pkt_meta> <op> <pkt_data>
> by flipping opcode.
>
> Suggested-by: Andrii Nakryiko <andrii.nakryiko@gmail.com>
> Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
> ---
>  kernel/bpf/verifier.c | 104 ++++++++++--------------------------------
>  1 file changed, 24 insertions(+), 80 deletions(-)
>
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index adbf330d364b..918e6a7912e2 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -14677,6 +14677,9 @@ static bool try_match_pkt_pointers(const struct bpf_insn *insn,
>                                    struct bpf_verifier_state *this_branch,
>                                    struct bpf_verifier_state *other_branch)
>  {
> +       int opcode = BPF_OP(insn->code);
> +       int dst_regno = insn->dst_reg;
> +
>         if (BPF_SRC(insn->code) != BPF_X)
>                 return false;
>
> @@ -14684,90 +14687,31 @@ static bool try_match_pkt_pointers(const struct bpf_insn *insn,
>         if (BPF_CLASS(insn->code) == BPF_JMP32)
>                 return false;
>
> -       switch (BPF_OP(insn->code)) {
> +       if (dst_reg->type == PTR_TO_PACKET_END ||
> +           src_reg->type == PTR_TO_PACKET_META) {
> +               swap(src_reg, dst_reg);
> +               dst_regno = insn->src_reg;
> +               opcode = flip_opcode(opcode);
> +       }
> +
> +       if ((dst_reg->type != PTR_TO_PACKET ||
> +            src_reg->type != PTR_TO_PACKET_END) &&
> +           (dst_reg->type != PTR_TO_PACKET_META ||
> +            !reg_is_init_pkt_pointer(src_reg, PTR_TO_PACKET)))
> +               return false;

this inverted original condition just breaks my brain, I can't wrap my
head around it :) I think the original is easier to reason about
because it's two clear allowable patterns for which we do something. I
understand that this early exit reduces nestedness, but at least for
me it would be simpler to have the original non-inverted condition
with a nested switch.


> +
> +       switch (opcode) {
>         case BPF_JGT:
> -               if ((dst_reg->type == PTR_TO_PACKET &&
> -                    src_reg->type == PTR_TO_PACKET_END) ||
> -                   (dst_reg->type == PTR_TO_PACKET_META &&
> -                    reg_is_init_pkt_pointer(src_reg, PTR_TO_PACKET))) {
> -                       /* pkt_data' > pkt_end, pkt_meta' > pkt_data */
> -                       find_good_pkt_pointers(this_branch, dst_reg,
> -                                              dst_reg->type, false);
> -                       mark_pkt_end(other_branch, insn->dst_reg, true);
> -               } else if ((dst_reg->type == PTR_TO_PACKET_END &&
> -                           src_reg->type == PTR_TO_PACKET) ||
> -                          (reg_is_init_pkt_pointer(dst_reg, PTR_TO_PACKET) &&
> -                           src_reg->type == PTR_TO_PACKET_META)) {
> -                       /* pkt_end > pkt_data', pkt_data > pkt_meta' */
> -                       find_good_pkt_pointers(other_branch, src_reg,
> -                                              src_reg->type, true);
> -                       mark_pkt_end(this_branch, insn->src_reg, false);
> -               } else {
> -                       return false;
> -               }
> -               break;

[...]
Andrii Nakryiko Jan. 9, 2024, 12:43 a.m. UTC | #2
On Mon, Jan 8, 2024 at 4:40 PM Andrii Nakryiko
<andrii.nakryiko@gmail.com> wrote:
>
> On Mon, Jan 8, 2024 at 5:28 AM Eduard Zingerman <eddyz87@gmail.com> wrote:
> >
> > Reduce number of cases handled in try_match_pkt_pointers()
> > to <pkt_data> <op> <pkt_end> or <pkt_meta> <op> <pkt_data>
> > by flipping opcode.
> >
> > Suggested-by: Andrii Nakryiko <andrii.nakryiko@gmail.com>
> > Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
> > ---
> >  kernel/bpf/verifier.c | 104 ++++++++++--------------------------------
> >  1 file changed, 24 insertions(+), 80 deletions(-)
> >
> > diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> > index adbf330d364b..918e6a7912e2 100644
> > --- a/kernel/bpf/verifier.c
> > +++ b/kernel/bpf/verifier.c
> > @@ -14677,6 +14677,9 @@ static bool try_match_pkt_pointers(const struct bpf_insn *insn,
> >                                    struct bpf_verifier_state *this_branch,
> >                                    struct bpf_verifier_state *other_branch)
> >  {
> > +       int opcode = BPF_OP(insn->code);
> > +       int dst_regno = insn->dst_reg;
> > +
> >         if (BPF_SRC(insn->code) != BPF_X)
> >                 return false;
> >
> > @@ -14684,90 +14687,31 @@ static bool try_match_pkt_pointers(const struct bpf_insn *insn,
> >         if (BPF_CLASS(insn->code) == BPF_JMP32)
> >                 return false;
> >
> > -       switch (BPF_OP(insn->code)) {
> > +       if (dst_reg->type == PTR_TO_PACKET_END ||
> > +           src_reg->type == PTR_TO_PACKET_META) {
> > +               swap(src_reg, dst_reg);
> > +               dst_regno = insn->src_reg;
> > +               opcode = flip_opcode(opcode);
> > +       }
> > +
> > +       if ((dst_reg->type != PTR_TO_PACKET ||
> > +            src_reg->type != PTR_TO_PACKET_END) &&
> > +           (dst_reg->type != PTR_TO_PACKET_META ||
> > +            !reg_is_init_pkt_pointer(src_reg, PTR_TO_PACKET)))
> > +               return false;
>
> this inverted original condition just breaks my brain, I can't wrap my
> head around it :) I think the original is easier to reason about
> because it's two clear allowable patterns for which we do something. I
> understand that this early exit reduces nestedness, but at least for
> me it would be simpler to have the original non-inverted condition
> with a nested switch.
>
>
> > +
> > +       switch (opcode) {
> >         case BPF_JGT:
> > -               if ((dst_reg->type == PTR_TO_PACKET &&
> > -                    src_reg->type == PTR_TO_PACKET_END) ||
> > -                   (dst_reg->type == PTR_TO_PACKET_META &&
> > -                    reg_is_init_pkt_pointer(src_reg, PTR_TO_PACKET))) {
> > -                       /* pkt_data' > pkt_end, pkt_meta' > pkt_data */
> > -                       find_good_pkt_pointers(this_branch, dst_reg,
> > -                                              dst_reg->type, false);
> > -                       mark_pkt_end(other_branch, insn->dst_reg, true);

it seems like you can make a bit of simplification if mark_pkt_end
would just accept struct bpf_reg_state * instead of int regn (you
won't need to keep track of dst_regno at all, right?)

> > -               } else if ((dst_reg->type == PTR_TO_PACKET_END &&
> > -                           src_reg->type == PTR_TO_PACKET) ||
> > -                          (reg_is_init_pkt_pointer(dst_reg, PTR_TO_PACKET) &&
> > -                           src_reg->type == PTR_TO_PACKET_META)) {
> > -                       /* pkt_end > pkt_data', pkt_data > pkt_meta' */
> > -                       find_good_pkt_pointers(other_branch, src_reg,
> > -                                              src_reg->type, true);
> > -                       mark_pkt_end(this_branch, insn->src_reg, false);
> > -               } else {
> > -                       return false;
> > -               }
> > -               break;
>
> [...]
Eduard Zingerman Jan. 9, 2024, 12:52 a.m. UTC | #3
On Mon, 2024-01-08 at 16:40 -0800, Andrii Nakryiko wrote:
[...]
> > @@ -14684,90 +14687,31 @@ static bool try_match_pkt_pointers(const struct bpf_insn *insn,
> >         if (BPF_CLASS(insn->code) == BPF_JMP32)
> >                 return false;
> > 
> > -       switch (BPF_OP(insn->code)) {
> > +       if (dst_reg->type == PTR_TO_PACKET_END ||
> > +           src_reg->type == PTR_TO_PACKET_META) {
> > +               swap(src_reg, dst_reg);
> > +               dst_regno = insn->src_reg;
> > +               opcode = flip_opcode(opcode);
> > +       }
> > +
> > +       if ((dst_reg->type != PTR_TO_PACKET ||
> > +            src_reg->type != PTR_TO_PACKET_END) &&
> > +           (dst_reg->type != PTR_TO_PACKET_META ||
> > +            !reg_is_init_pkt_pointer(src_reg, PTR_TO_PACKET)))
> > +               return false;
> 
> this inverted original condition just breaks my brain, I can't wrap my
> head around it :) I think the original is easier to reason about
> because it's two clear allowable patterns for which we do something. I
> understand that this early exit reduces nestedness, but at least for
> me it would be simpler to have the original non-inverted condition
> with a nested switch.

I'm not sure I understand what you mean by nested switch.
If I write it down like below, would that be more clear?

	bool pkt_data_vs_pkt_end;
    bool pkt_meta_vs_pkt_data;
    ...
    pkt_data_vs_pkt_end =
      dst_reg->type == PTR_TO_PACKET && src_reg->type == PTR_TO_PACKET_END;
    pkt_meta_vs_pkt_data =
      dst_reg->type == PTR_TO_PACKET_META && reg_is_init_pkt_pointer(src_reg, PTR_TO_PACKET);

    if (!pkt_data_vs_pkt_end && !pkt_meta_vs_pkt_data)
        return false;

> > +
> > +       switch (opcode) {
> >         case BPF_JGT:
> > -               if ((dst_reg->type == PTR_TO_PACKET &&
> > -                    src_reg->type == PTR_TO_PACKET_END) ||
> > -                   (dst_reg->type == PTR_TO_PACKET_META &&
> > -                    reg_is_init_pkt_pointer(src_reg, PTR_TO_PACKET))) {
> > -                       /* pkt_data' > pkt_end, pkt_meta' > pkt_data */
> > -                       find_good_pkt_pointers(this_branch, dst_reg,
> > -                                              dst_reg->type, false);
> > -                       mark_pkt_end(other_branch, insn->dst_reg, true);

> it seems like you can make a bit of simplification if mark_pkt_end
> would just accept struct bpf_reg_state * instead of int regn (you
> won't need to keep track of dst_regno at all, right?)

mark_pkt_end() changes the register from either this_branch or other_branch.
I can introduce local pointers dst_this/dst_other and swap those,
but I'm not sure it's worth it.

[...]
Andrii Nakryiko Jan. 9, 2024, 6:22 p.m. UTC | #4
On Mon, Jan 8, 2024 at 4:52 PM Eduard Zingerman <eddyz87@gmail.com> wrote:
>
> On Mon, 2024-01-08 at 16:40 -0800, Andrii Nakryiko wrote:
> [...]
> > > @@ -14684,90 +14687,31 @@ static bool try_match_pkt_pointers(const struct bpf_insn *insn,
> > >         if (BPF_CLASS(insn->code) == BPF_JMP32)
> > >                 return false;
> > >
> > > -       switch (BPF_OP(insn->code)) {
> > > +       if (dst_reg->type == PTR_TO_PACKET_END ||
> > > +           src_reg->type == PTR_TO_PACKET_META) {
> > > +               swap(src_reg, dst_reg);
> > > +               dst_regno = insn->src_reg;
> > > +               opcode = flip_opcode(opcode);
> > > +       }
> > > +
> > > +       if ((dst_reg->type != PTR_TO_PACKET ||
> > > +            src_reg->type != PTR_TO_PACKET_END) &&
> > > +           (dst_reg->type != PTR_TO_PACKET_META ||
> > > +            !reg_is_init_pkt_pointer(src_reg, PTR_TO_PACKET)))
> > > +               return false;
> >
> > this inverted original condition just breaks my brain, I can't wrap my
> > head around it :) I think the original is easier to reason about
> > because it's two clear allowable patterns for which we do something. I
> > understand that this early exit reduces nestedness, but at least for
> > me it would be simpler to have the original non-inverted condition
> > with a nested switch.
>
> I'm not sure I understand what you mean by nested switch.
> If I write it down like below, would that be more clear?
>

Yes, much more clear. What I had in mind was something like:

if (pkt_data_vs_pkt_end || pkt_meta_vs_pkt_data) {
    switch (opcode) {
        ...
    }
}

But what you have below is easy to follow as well


>         bool pkt_data_vs_pkt_end;
>     bool pkt_meta_vs_pkt_data;
>     ...
>     pkt_data_vs_pkt_end =
>       dst_reg->type == PTR_TO_PACKET && src_reg->type == PTR_TO_PACKET_END;
>     pkt_meta_vs_pkt_data =
>       dst_reg->type == PTR_TO_PACKET_META && reg_is_init_pkt_pointer(src_reg, PTR_TO_PACKET);
>
>     if (!pkt_data_vs_pkt_end && !pkt_meta_vs_pkt_data)
>         return false;
>
> > > +
> > > +       switch (opcode) {
> > >         case BPF_JGT:
> > > -               if ((dst_reg->type == PTR_TO_PACKET &&
> > > -                    src_reg->type == PTR_TO_PACKET_END) ||
> > > -                   (dst_reg->type == PTR_TO_PACKET_META &&
> > > -                    reg_is_init_pkt_pointer(src_reg, PTR_TO_PACKET))) {
> > > -                       /* pkt_data' > pkt_end, pkt_meta' > pkt_data */
> > > -                       find_good_pkt_pointers(this_branch, dst_reg,
> > > -                                              dst_reg->type, false);
> > > -                       mark_pkt_end(other_branch, insn->dst_reg, true);
>
> > it seems like you can make a bit of simplification if mark_pkt_end
> > would just accept struct bpf_reg_state * instead of int regn (you
> > won't need to keep track of dst_regno at all, right?)
>
> mark_pkt_end() changes the register from either this_branch or other_branch.
> I can introduce local pointers dst_this/dst_other and swap those,
> but I'm not sure it's worth it.

Ah, I missed that it's other_branch register. Never mind then, it's
fine and it was minor anyways.

>
> [...]
diff mbox series

Patch

diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index adbf330d364b..918e6a7912e2 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -14677,6 +14677,9 @@  static bool try_match_pkt_pointers(const struct bpf_insn *insn,
 				   struct bpf_verifier_state *this_branch,
 				   struct bpf_verifier_state *other_branch)
 {
+	int opcode = BPF_OP(insn->code);
+	int dst_regno = insn->dst_reg;
+
 	if (BPF_SRC(insn->code) != BPF_X)
 		return false;
 
@@ -14684,90 +14687,31 @@  static bool try_match_pkt_pointers(const struct bpf_insn *insn,
 	if (BPF_CLASS(insn->code) == BPF_JMP32)
 		return false;
 
-	switch (BPF_OP(insn->code)) {
+	if (dst_reg->type == PTR_TO_PACKET_END ||
+	    src_reg->type == PTR_TO_PACKET_META) {
+		swap(src_reg, dst_reg);
+		dst_regno = insn->src_reg;
+		opcode = flip_opcode(opcode);
+	}
+
+	if ((dst_reg->type != PTR_TO_PACKET ||
+	     src_reg->type != PTR_TO_PACKET_END) &&
+	    (dst_reg->type != PTR_TO_PACKET_META ||
+	     !reg_is_init_pkt_pointer(src_reg, PTR_TO_PACKET)))
+		return false;
+
+	switch (opcode) {
 	case BPF_JGT:
-		if ((dst_reg->type == PTR_TO_PACKET &&
-		     src_reg->type == PTR_TO_PACKET_END) ||
-		    (dst_reg->type == PTR_TO_PACKET_META &&
-		     reg_is_init_pkt_pointer(src_reg, PTR_TO_PACKET))) {
-			/* pkt_data' > pkt_end, pkt_meta' > pkt_data */
-			find_good_pkt_pointers(this_branch, dst_reg,
-					       dst_reg->type, false);
-			mark_pkt_end(other_branch, insn->dst_reg, true);
-		} else if ((dst_reg->type == PTR_TO_PACKET_END &&
-			    src_reg->type == PTR_TO_PACKET) ||
-			   (reg_is_init_pkt_pointer(dst_reg, PTR_TO_PACKET) &&
-			    src_reg->type == PTR_TO_PACKET_META)) {
-			/* pkt_end > pkt_data', pkt_data > pkt_meta' */
-			find_good_pkt_pointers(other_branch, src_reg,
-					       src_reg->type, true);
-			mark_pkt_end(this_branch, insn->src_reg, false);
-		} else {
-			return false;
-		}
-		break;
-	case BPF_JLT:
-		if ((dst_reg->type == PTR_TO_PACKET &&
-		     src_reg->type == PTR_TO_PACKET_END) ||
-		    (dst_reg->type == PTR_TO_PACKET_META &&
-		     reg_is_init_pkt_pointer(src_reg, PTR_TO_PACKET))) {
-			/* pkt_data' < pkt_end, pkt_meta' < pkt_data */
-			find_good_pkt_pointers(other_branch, dst_reg,
-					       dst_reg->type, true);
-			mark_pkt_end(this_branch, insn->dst_reg, false);
-		} else if ((dst_reg->type == PTR_TO_PACKET_END &&
-			    src_reg->type == PTR_TO_PACKET) ||
-			   (reg_is_init_pkt_pointer(dst_reg, PTR_TO_PACKET) &&
-			    src_reg->type == PTR_TO_PACKET_META)) {
-			/* pkt_end < pkt_data', pkt_data > pkt_meta' */
-			find_good_pkt_pointers(this_branch, src_reg,
-					       src_reg->type, false);
-			mark_pkt_end(other_branch, insn->src_reg, true);
-		} else {
-			return false;
-		}
-		break;
 	case BPF_JGE:
-		if ((dst_reg->type == PTR_TO_PACKET &&
-		     src_reg->type == PTR_TO_PACKET_END) ||
-		    (dst_reg->type == PTR_TO_PACKET_META &&
-		     reg_is_init_pkt_pointer(src_reg, PTR_TO_PACKET))) {
-			/* pkt_data' >= pkt_end, pkt_meta' >= pkt_data */
-			find_good_pkt_pointers(this_branch, dst_reg,
-					       dst_reg->type, true);
-			mark_pkt_end(other_branch, insn->dst_reg, false);
-		} else if ((dst_reg->type == PTR_TO_PACKET_END &&
-			    src_reg->type == PTR_TO_PACKET) ||
-			   (reg_is_init_pkt_pointer(dst_reg, PTR_TO_PACKET) &&
-			    src_reg->type == PTR_TO_PACKET_META)) {
-			/* pkt_end >= pkt_data', pkt_data >= pkt_meta' */
-			find_good_pkt_pointers(other_branch, src_reg,
-					       src_reg->type, false);
-			mark_pkt_end(this_branch, insn->src_reg, true);
-		} else {
-			return false;
-		}
+		/* pkt_data >/>= pkt_end, pkt_meta >/>= pkt_data */
+		find_good_pkt_pointers(this_branch, dst_reg, dst_reg->type, opcode == BPF_JGE);
+		mark_pkt_end(other_branch, dst_regno, opcode == BPF_JGT);
 		break;
+	case BPF_JLT:
 	case BPF_JLE:
-		if ((dst_reg->type == PTR_TO_PACKET &&
-		     src_reg->type == PTR_TO_PACKET_END) ||
-		    (dst_reg->type == PTR_TO_PACKET_META &&
-		     reg_is_init_pkt_pointer(src_reg, PTR_TO_PACKET))) {
-			/* pkt_data' <= pkt_end, pkt_meta' <= pkt_data */
-			find_good_pkt_pointers(other_branch, dst_reg,
-					       dst_reg->type, false);
-			mark_pkt_end(this_branch, insn->dst_reg, true);
-		} else if ((dst_reg->type == PTR_TO_PACKET_END &&
-			    src_reg->type == PTR_TO_PACKET) ||
-			   (reg_is_init_pkt_pointer(dst_reg, PTR_TO_PACKET) &&
-			    src_reg->type == PTR_TO_PACKET_META)) {
-			/* pkt_end <= pkt_data', pkt_data <= pkt_meta' */
-			find_good_pkt_pointers(this_branch, src_reg,
-					       src_reg->type, true);
-			mark_pkt_end(other_branch, insn->src_reg, false);
-		} else {
-			return false;
-		}
+		/* pkt_data </<= pkt_end, pkt_meta </<= pkt_data */
+		find_good_pkt_pointers(other_branch, dst_reg, dst_reg->type, opcode == BPF_JLT);
+		mark_pkt_end(this_branch, dst_regno, opcode == BPF_JLE);
 		break;
 	default:
 		return false;