To follow this on, looking at the output of "tcpdump -d",
it became obvious that the opcodes could be optimised.
The optimised would need to be seriously smarter than
it currently is to detect that it has a repeating group of
six statements, of which the second can be eliminated.
That's completely out of scope for what I'm doing.

One solution to that is to add another BPF opcode, that
is an indirect version of BPF_MSH - call it BPF_MSHM.

The attached patch introduces a "ldxbi" to complement
the "ldxb". With the patches attached applied, the
output of "tcpdump -d" becomes much more reasonable:

# tcpdump -d -vi net0 ip and tcp port 80
(000) ldh      [2]
(001) st       M[0]
(002) ldh      [8]
(003) jeq      #0x800           jt 4    jf 15
(004) ldx      M[0]
(005) ldb      [x + 9]
(006) jeq      #0x6             jt 7    jf 15
(007) ldh      [x + 6]
(008) jset     #0x1fff          jt 15   jf 9
(009) ldxbi    4*([[2]]&0xf)
(010) ldh      [x + 0]
(011) jeq      #0x50            jt 14   jf 12
(012) ldh      [x + 2]
(013) jeq      #0x50            jt 14   jf 15
(014) ret      #65535
(015) ret      #0

FWIW, BPF_MSHM equates to BPF_LEN|BPF_IND|BPF_ABS,
whereas BPF_MSH (ldxb) is BPF_LEN|BPF_ABS. Thus
this seems to be the right mneumonic/opcode for
the operation at hand.

Darren

diff --git a/bpf/net/bpf_filter.c b/bpf/net/bpf_filter.c
index 22aff79..1c75840 100644
--- a/bpf/net/bpf_filter.c
+++ b/bpf/net/bpf_filter.c
@@ -377,7 +377,37 @@ bpf_filter(pc, p, wirelen, buflen)
                                return 0;
 #endif
                        }
-                       X = (p[pc->k] & 0xf) << 2;
+                       X = (p[k] & 0xf) << 2;
+                       continue;
+
+               case BPF_LDX|BPF_MSHM|BPF_B:
+                       k = pc->k;
+                       if (k >= buflen) {
+#if defined(KERNEL) || defined(_KERNEL)
+                               if (m == NULL)
+                                       return 0;
+                               n = m;
+                               MINDEX(len, n, k);
+                               k = mtod(n, char *)[k];
+#else
+                               return 0;
+#endif
+                       } else {
+                               k = p[k];
+                       }
+                       if (k >= buflen) {
+#if defined(KERNEL) || defined(_KERNEL)
+                               if (m == NULL)
+                                       return 0;
+                               n = m;
+                               MINDEX(len, n, k);
+                               X = (mtod(n, char *)[k] & 0xf) << 2;
+                               continue;
+#else
+                               return 0;
+#endif
+                       }
+                       X = (p[k] & 0xf) << 2;
                        continue;
 
                case BPF_LD|BPF_IMM:
diff --git a/bpf_image.c b/bpf_image.c
index e2f1a77..7ccf95f 100644
--- a/bpf_image.c
+++ b/bpf_image.c
@@ -130,6 +130,11 @@ bpf_image(p, n)
                fmt = "4*([%d]&0xf)";
                break;
 
+       case BPF_LDX|BPF_MSHM|BPF_B:
+               op = "ldxbi";
+               fmt = "4*([[%d]]&0xf)";
+               break;
+
        case BPF_LD|BPF_MEM:
                op = "ld";
                fmt = "M[%d]";
diff --git a/gencode.c b/gencode.c
index b94ea72..6d2f6bb 100644
--- a/gencode.c
+++ b/gencode.c
@@ -1598,6 +1598,14 @@ init_linktype(p)
                off_nl = -1;
                off_nl_nosnap = -1;
                return;
+
+       case DLT_LINK:
+               off_linktype = 8;
+               off_macpl = 0;
+               off_macpl_is_variable = 1;
+               off_nl = 0;
+               off_nl_nosnap = 0;
+               return;
        }
        bpf_error("unknown data link type %d", linktype);
        /* NOTREACHED */
@@ -1766,7 +1774,10 @@ gen_loadx_iphdrlen()
 {
        struct slist *s, *s2;
 
-       s = gen_off_macpl();
+       if (linktype != DLT_LINK)
+               s = gen_off_macpl();
+       else
+               s = NULL;
        if (s != NULL) {
                /*
                 * There's a variable-length prefix preceding the
@@ -1808,8 +1819,13 @@ gen_loadx_iphdrlen()
                 * of off_mac_pl + off_nl from the beginning of the
                 * raw packet data.
                 */
-               s = new_stmt(BPF_LDX|BPF_MSH|BPF_B);
-               s->s.k = off_macpl + off_nl;
+               if (linktype == DLT_LINK) {
+                       s = new_stmt(BPF_LDX|BPF_MSHM|BPF_B);
+                       s->s.k = 2;
+               } else {
+                       s = new_stmt(BPF_LDX|BPF_MSH|BPF_B);
+                       s->s.k = off_macpl + off_nl;
+               }
        }
        return s;
 }
@@ -2427,6 +2443,39 @@ gen_load_radiotap_llprefixlen()
                return (NULL);
 }
 
+static struct slist *
+gen_load_link_ll_header_len()
+{
+       struct slist *s1, *s2;
+
+       if (reg_off_macpl == -1)
+               reg_off_macpl = alloc_reg();
+
+       /*
+        * Generate code to load the length of the link header into
+        * the register assigned to hold that length, if one has been
+        * assigned.  (If one hasn't been assigned, no code we've
+        * generated uses that prefix, so we don't need to generate any
+        * code to load it.)
+        */
+       if (reg_off_macpl != -1) {
+               s1 = new_stmt(BPF_LD|BPF_H|BPF_ABS);
+               s1->s.k = 2;
+               s2 = new_stmt(BPF_ST);
+               s2->s.k = reg_off_macpl;
+               sappend(s1, s2);
+
+               /*
+                * Now move it into the X register.
+                */
+               s2 = new_stmt(BPF_MISC|BPF_TAX);
+               sappend(s1, s2);
+
+               return (s1);
+       } else
+               return (NULL);
+}
+
 /* 
  * At the moment we treat PPI as normal Radiotap encoded
  * packets. The difference is in the function that generates
@@ -2765,6 +2814,11 @@ insert_compute_vloffsets(b)
        case DLT_PPI:
                s = gen_load_802_11_header_len(s, b->stmts);
                break;
+
+       case DLT_LINK:
+               s = gen_load_link_ll_header_len();
+               break;
+
        }
 
        /*
@@ -5670,8 +5724,13 @@ gen_protochain(v, proto, dir)
                s[i]->s.k = off_macpl + off_nl + 9;
                i++;
                /* X = ip->ip_hl << 2 */
-               s[i] = new_stmt(BPF_LDX|BPF_MSH|BPF_B);
-               s[i]->s.k = off_macpl + off_nl;
+               if (linktype == DLT_LINK) {
+                       s[i] = new_stmt(BPF_LDX|BPF_MSHM|BPF_B);
+                       s[i]->s.k = 2;
+               } else {
+                       s[i] = new_stmt(BPF_LDX|BPF_MSH|BPF_B);
+                       s[i]->s.k = off_macpl + off_nl;
+               }
                i++;
                break;
 #ifdef INET6
diff --git a/optimize.c b/optimize.c
index 46dffec..0f6fd0a 100644
--- a/optimize.c
+++ b/optimize.c
@@ -785,7 +785,8 @@ opt_peep(b)
                         * following it (with 0 or more nops between the
                         * ldxms and addx).
                         */
-                       if (next->s.code != (BPF_LDX|BPF_MSH|BPF_B))
+                       if (next->s.code != (BPF_LDX|BPF_MSH|BPF_B) &&
+                           next->s.code != (BPF_LDX|BPF_MSHM|BPF_B))
                                add = next;
                        else
                                add = this_op(next->next);
@@ -1030,6 +1031,11 @@ opt_stmt(s, val, alter)
                vstore(s, &val[X_ATOM], v, alter);
                break;
 
+       case BPF_LDX|BPF_MSHM|BPF_B:
+               v = F(s->code, s->k, 0L);
+               vstore(s, &val[X_ATOM], v, alter);
+               break;
+
        case BPF_ALU|BPF_NEG:
                if (alter && vmap[val[A_ATOM]].is_const) {
                        s->code = BPF_LD|BPF_IMM;
diff --git a/pcap/bpf.h b/pcap/bpf.h
index 950b85b..db4ff8e 100644
--- a/pcap/bpf.h
+++ b/pcap/bpf.h
@@ -1035,6 +1035,7 @@ struct bpf_version {
 #define                BPF_MEM         0x60
 #define                BPF_LEN         0x80
 #define                BPF_MSH         0xa0
+#define                BPF_MSHM        0xe0
 
 /* alu/jmp fields */
 #define BPF_OP(code)   ((code) & 0xf0)
-
This is the tcpdump-workers list.
Visit https://cod.sandelman.ca/ to unsubscribe.

Reply via email to