BPF (BSD Packet Filter)-Application and concept Extension

Source: Internet
Author: User

BPF is a filtering mechanism used to filter data packets sent to a specific location, such as a user space. It is designed as a language similar to assembly language, which can be called a pseudo assembly code. Although designed to filter data packets, this design method is more suitable for operating hardware, especially for writing hardware drivers that require a small number of fixed sequences. No matter what it is used for, BPF is well designed and is a perfect example of state machine control logic. BPF is actually a set of matching filtering Sequences Based on the state machine for simple packet pattern matching. Each match contains four elements and is defined as a struct:
Struct socket_filter
{
_ Code; // operation code, which can be used for numeric operations, loading, comparison, and other operations
_ U8 JT; // Where to jump if match exists
_ U8 JF; // Where to jump if not matched
_ U32 K; // parameter field, which has different purposes for different operation codes. For example, when the operation code is a comparison key, the operation code is the offset of loading data in the data packet (link frame/datagram) during loading.
}
The matching sequence is similar to an assembly program and has its own operation code, operations, and branch jump functions, therefore, the execution process of this matching sequence is similar to the execution thread of a single process on a Von noiman machine. In essence, it is a state machine (from the data point of view, A process is a filter, and its name is the filter ...), obviously, its implementation should be a State-driven loop:
While (there are matches in the sequence ){
Switch (current operation code)
Case addition, subtraction, multiplication, division:
...
Case loading:
Load data with a low K value of the current matching item, set it to d
Next match
Case comparison jump:
Program counter + = comparison result? JT field of the current match: JF Field
...
}
Let's look at the Linux implementation code, which is basically implemented as follows:
Int sk_run_filter (struct sk_buff * SKB, struct sock_filter * filter, int FLEN)
{
... // Define the intermediate variable and save the temporary Calculation Result
Int K;
Int PC; // program counter, used for Branch jump
For (Pc = 0; Pc <FLEN; PC ++ ){
Fentry = & filter [PC];
Switch (fentry-> code ){
Case bpf_alu | bpf_add | bpf_x:
A + = X;
Continue;
... // Similar to subtraction, multiplication, division, inversion, and, or...
Case bpf_jmp | bpf_ja: // branch jump involved
PC + = fentry-> K;
Continue;
Case bpf_jmp | bpf_jgt | bpf_k: // greater
PC + = (A> fentry-> K )? Fentry-> JT: fentry-> JF;
Continue;
... // Similar to comparison operations such as smaller than or equal to, and then branch jump
Load_w: // load operations, similar to mov in x86 assembly, these load operations also need to be differentiated by size, such as load a word or dual word, or Byte...
If (k> = 0 & (unsigned INT) (K + sizeof (u32) <= Len ){
A = ntohl (* (u32 *) & Data [k]);
Continue;
}
...
}
BPF is used for many packet capture programs. in Linux, the kernel is usually automatically compiled into the af_packet driver. Therefore, you only need to prepare a PACKET socket in the user State, then configure the filter to the kernel. Use the so_attach_filter command of setsockopt. The filter is prepared in the user space, such as the tcpdump application, the relationship between tcpdump and kernel BPF filters is similar to that between iptables and netfilter, but netfilter implements the complex combination of match and target, the target of BPF is only "this packet is required" and "this packet is not required ". When the configuration is in the user State
Tcpdump-I eth0 host 1.2.3.4...
In fact, the filter that enters the kernel is the following sequence, and each {} is a socket_filter:
...
N: {loading, 0, 0, offset of the source IP address in the ethereframe },
N + 1: {comparison jump, N + 3, N + 2, "1.2.3.4 "},
N + 2: {loading, 0, 0, the offset of the target IP address in the ethereframe },
N + 3: {comparison jump, N + 4, N + M, "1.2.3.4 "},
N + 4 :{...},
...
N + M: {return ...}
Then, when a packet comes in, because the tcpdump socket is registered in the ptype_all list in advance, the packet will be copied to the tcpdump socket, then, in its packet_type func function, run_filter is called to filter data packets, so that you do not need to submit the package to tcpdump.
In Windows, the kernel does not directly contain BPF because of its weak network processing capability and transition layering, or the over-interface implementation caused by the creation of industry standards, an NDIS filter driver is required. This implementation is simple and modular. Create an interface similar to libpcap to implement ethereal. Regardless of the operating system, if such pseudo-assembly commands can be compiled into machine commands in a timely manner, the essence of the machine's CPU state machine, such as sk_run_filter, can be used to replace software functions, the performance will be greatly improved.
Finally, let's take a look at the BPF design concept for the hardware driver scenario. First, define a struct, similar to socket_filter in Linux BPF, but it is more compact and redundant. In fact, there is no need to implement so many fields, however, in that case, the driver function will be more complicated. In short, the idea is the same:
Struct sequence_item {
Int OPT; // operation code: read/write/addition, subtraction, multiplication, division, and inverse...
Int data; // operand
Int port; // The second operand, which can be a port.
Int flag; // flag to store whether intermediate results are used
Char reverse [0] // Reserved
};
Int Driver (struct sequence_item * sequence, unsigned int Len)
{
Int I = 0;
Int result =-1;
Struct sequence_item Si;
For (; I <Len; I ++ ){
SI = sequence [I];
If (Si. Opt = 0 ){
Outb_p (Si. Flag? Result: Si. Data, Si. Port );
} Else if (Si. Opt = 1 ){
Result = inb_p (Si. Port );
} Else {
Switch (Si. Opt ){
Case '~ ':
Result ~ = Si. Data;
Break;
Case '^ ':
Result ^ = Si. Data;
Break;
...
}
}
}
Return 1;
}
[PS]: This code was drawn from a driver I wrote a long time ago (3 years ago). The idea used is actually similar to BPF (2 years ago).

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.