- 论坛徽章:
- 0
|
内核态的实现在 <kernel>/net/core/filter.c 中
- /**
- * sk_run_filter - run a filter on a socket
- * @skb: buffer to run the filter on
- * @filter: filter to apply
- * @flen: length of filter
- *
- * Decode and apply filter instructions to the skb->data.
- * Return length to keep, 0 for none. skb is the data we are
- * filtering, filter is the array of filter instructions, and
- * len is the number of filter blocks in the array.
- */
- unsigned int sk_run_filter(struct sk_buff *skb, struct sock_filter *filter, int flen)
- {
- struct sock_filter *fentry; /* We walk down these */
- void *ptr;
- u32 A = 0; /* Accumulator */
- u32 X = 0; /* Index Register */
- u32 mem[BPF_MEMWORDS]; /* Scratch Memory Store */
- u32 tmp;
- int k;
- int pc;
- /*
- * Process array of filter instructions.
- */
- for (pc = 0; pc < flen; pc++) {
- fentry = &filter[pc];
- switch (fentry->code) {
- case BPF_ALU|BPF_ADD|BPF_X:
- A += X;
- continue;
- case BPF_ALU|BPF_ADD|BPF_K:
- A += fentry->k;
- continue;
- case BPF_ALU|BPF_SUB|BPF_X:
- A -= X;
- continue;
- case BPF_ALU|BPF_SUB|BPF_K:
- A -= fentry->k;
- continue;
- case BPF_ALU|BPF_MUL|BPF_X:
- A *= X;
- continue;
- case BPF_ALU|BPF_MUL|BPF_K:
- A *= fentry->k;
- continue;
- case BPF_ALU|BPF_DIV|BPF_X:
- if (X == 0)
- return 0;
- A /= X;
- continue;
- case BPF_ALU|BPF_DIV|BPF_K:
- A /= fentry->k;
- continue;
- case BPF_ALU|BPF_AND|BPF_X:
- A &= X;
- continue;
- case BPF_ALU|BPF_AND|BPF_K:
- A &= fentry->k;
- continue;
- case BPF_ALU|BPF_OR|BPF_X:
- A |= X;
- continue;
- case BPF_ALU|BPF_OR|BPF_K:
- A |= fentry->k;
- continue;
- case BPF_ALU|BPF_LSH|BPF_X:
- A <<= X;
- continue;
- case BPF_ALU|BPF_LSH|BPF_K:
- A <<= fentry->k;
- continue;
- case BPF_ALU|BPF_RSH|BPF_X:
- A >>= X;
- continue;
- case BPF_ALU|BPF_RSH|BPF_K:
- A >>= fentry->k;
- continue;
- case BPF_ALU|BPF_NEG:
- A = -A;
- continue;
- case BPF_JMP|BPF_JA:
- pc += fentry->k;
- continue;
- case BPF_JMP|BPF_JGT|BPF_K:
- pc += (A > fentry->k) ? fentry->jt : fentry->jf;
- continue;
- case BPF_JMP|BPF_JGE|BPF_K:
- pc += (A >= fentry->k) ? fentry->jt : fentry->jf;
- continue;
- case BPF_JMP|BPF_JEQ|BPF_K:
- pc += (A == fentry->k) ? fentry->jt : fentry->jf;
- continue;
- case BPF_JMP|BPF_JSET|BPF_K:
- pc += (A & fentry->k) ? fentry->jt : fentry->jf;
- continue;
- case BPF_JMP|BPF_JGT|BPF_X:
- pc += (A > X) ? fentry->jt : fentry->jf;
- continue;
- case BPF_JMP|BPF_JGE|BPF_X:
- pc += (A >= X) ? fentry->jt : fentry->jf;
- continue;
- case BPF_JMP|BPF_JEQ|BPF_X:
- pc += (A == X) ? fentry->jt : fentry->jf;
- continue;
- case BPF_JMP|BPF_JSET|BPF_X:
- pc += (A & X) ? fentry->jt : fentry->jf;
- continue;
- case BPF_LD|BPF_W|BPF_ABS:
- k = fentry->k;
- load_w:
- ptr = load_pointer(skb, k, 4, &tmp);
- if (ptr != NULL) {
- A = ntohl(get_unaligned((__be32 *)ptr));
- continue;
- }
- break;
- case BPF_LD|BPF_H|BPF_ABS:
- k = fentry->k;
- load_h:
- ptr = load_pointer(skb, k, 2, &tmp);
- if (ptr != NULL) {
- A = ntohs(get_unaligned((__be16 *)ptr));
- continue;
- }
- break;
- case BPF_LD|BPF_B|BPF_ABS:
- k = fentry->k;
- load_b:
- ptr = load_pointer(skb, k, 1, &tmp);
- if (ptr != NULL) {
- A = *(u8 *)ptr;
- continue;
- }
- break;
- case BPF_LD|BPF_W|BPF_LEN:
- A = skb->len;
- continue;
- case BPF_LDX|BPF_W|BPF_LEN:
- X = skb->len;
- continue;
- case BPF_LD|BPF_W|BPF_IND:
- k = X + fentry->k;
- goto load_w;
- case BPF_LD|BPF_H|BPF_IND:
- k = X + fentry->k;
- goto load_h;
- case BPF_LD|BPF_B|BPF_IND:
- k = X + fentry->k;
- goto load_b;
- case BPF_LDX|BPF_B|BPF_MSH:
- ptr = load_pointer(skb, fentry->k, 1, &tmp);
- if (ptr != NULL) {
- X = (*(u8 *)ptr & 0xf) << 2;
- continue;
- }
- return 0;
- case BPF_LD|BPF_IMM:
- A = fentry->k;
- continue;
- case BPF_LDX|BPF_IMM:
- X = fentry->k;
- continue;
- case BPF_LD|BPF_MEM:
- A = mem[fentry->k];
- continue;
- case BPF_LDX|BPF_MEM:
- X = mem[fentry->k];
- continue;
- case BPF_MISC|BPF_TAX:
- X = A;
- continue;
- case BPF_MISC|BPF_TXA:
- A = X;
- continue;
- case BPF_RET|BPF_K:
- return fentry->k;
- case BPF_RET|BPF_A:
- return A;
- case BPF_ST:
- mem[fentry->k] = A;
- continue;
- case BPF_STX:
- mem[fentry->k] = X;
- continue;
- default:
- WARN_ON(1);
- return 0;
- }
- /*
- * Handle ancillary data, which are impossible
- * (or very difficult) to get parsing packet contents.
- */
- switch (k-SKF_AD_OFF) {
- case SKF_AD_PROTOCOL:
- A = ntohs(skb->protocol);
- continue;
- case SKF_AD_PKTTYPE:
- A = skb->pkt_type;
- continue;
- case SKF_AD_IFINDEX:
- A = skb->dev->ifindex;
- continue;
- default:
- return 0;
- }
- }
- return 0;
- }
复制代码
这是一个类似有穷状态机的实现方式
个人认为如果 filter 的书写比较单一的话,还是有很高提升空间的
上上周刚结束一个 case,改写了 filter,实现自己的抓包过滤机制,由于规则模式很单一,所以改用 hash 实现,效率比 bpf 高出不少 |
|