The nf_conntrack mechanism is used to store routes, eliminating the need for route searches per packet

Source: Internet
Author: User
The IP address is connectionless, so the IP route is the route of each packet. The data packet obtains the route by searching the route table. This is the default Processing Method of the IP route in the modern operating protocol stack. However, if the protocol stack has the stream recognition capability, can it be routed based on the stream? The answer is definitely yes.
In the implementation of Linux, nf_conntrack can achieve stream-Based IP routing. The general idea is, search for the standard IP route table for the first forward packet and the first reverse packet of a stream, and save the result in the conntrack item, probably, data packets belonging to the same stream are directly taken out of the route entry for use. The idea behind this is: this can save the overhead of finding a route table, right? Not all! The key is to send a data packet to a data stream, which requires a process of searching and matching. Assume that the route can be saved in conntrack, therefore, the conntrack search and route query can be combined into one query. Therefore, the search is inevitable. It is just a place change. If the conntrack is used, the standard packet-based IP route search process is still carried out, that is, one more look-up is performed.
The implementation idea is very easy, that is TrySet the route of SKB to conntrack when the data packet leaves the protocol stack. The reason for this is that both postrouting and input are after the route. Assuming that the packet-based IP Route Search is performed, the SKB must be bound to the dst_entry, bind it to conntrack. In addition, where the data packet has just entered the protocol stack TryRemove the route from the conntrack entry and set it directly to SKB. The processing process is similar to that of SKB-mark and conntrack mark:
-A prerouting-m mark -- Mark 100-J accept
-A prerouting-J connmark -- restore-mark -- nfmask 0 xffffffff -- ctmask 0 xffffffff
-A prerouting-m mark! -- Mark 0x0-J accept
... Slow matching process
-A prerouting...-J mark -- Set-mark 100
... Slow matching process
-A postrouting-m mark! -- Mark 0x0-J connmark -- save-mark -- nfmask 0 xffffffff -- ctmask 0 xffffffff

With the above understanding, the code is very easy.


# Include <Linux/IP. h> # include <Linux/module. h> # include <Linux/skbuff. h> # include <Linux/version. h> # include <net/Netfilter/nf_conntrack.h> # include <net/DST. h ># include <net/Netfilter/nf_conntrack_acct.h> module_author ("xtt"); module_description ("GlL"); module_license ("GPL "); module_alias ("xtt and GlL"); struct nf_conn_priv {struct nf_conn_counter NCC [ip_ct_dir_max]; struct dst_entry * DST [ip_ct_dir_max];}; Static unsigned int ipv4_conntrack_getdst (unsigned int hooknum, struct sk_buff * SKB, const struct net_device * In, const struct net_device * Out, INT (* okfn) (struct sk_buff *)) {struct nf_conn * CT; Enum ip_conntrack_info ctinfo; struct nf_conn_counter * Acct; struct nf_conn_priv * dst_info; Ct = nf_ct_get (SKB, & ctinfo); If (! CT | CT ==& amp; found) return nf_accept; Acct = nf_conn_acct_find (CT); If (ACCT) {int dir = ctinfo2dir (ctinfo); dst_info = (struct nf_conn_priv *) acct; If (dst_info-> DST [dir] = NULL) {dst_hold (skb_dst (SKB); dst_info-> DST [dir] = skb_dst (SKB );}} return nf_accept;} static unsigned int ipv4_conntrack_setdst (unsigned int hooknum, struct sk_buff * SKB, const struct net_device * In, cons T struct net_device * Out, INT (* okfn) (struct sk_buff *) {struct nf_conn * CT; Enum limit ctinfo; struct nf_conn_counter * Acct; struct nf_conn_priv * dst_info; ct = nf_ct_get (SKB, & ctinfo); If (! CT | CT ==& amp; found) return nf_accept; Acct = nf_conn_acct_find (CT); If (ACCT) {int dir = ctinfo2dir (ctinfo); dst_info = (struct nf_conn_priv *) acct; If (dst_info-> DST [dir]! = NULL) {// If skb dst is set here, skb_dst_set (SKB, dst_info-> DST [dir]) is not found in ip_rcv_finish.} return nf_accept;} static struct nf_hook_ops defaults 4_conn_dst_info [] _ read_mostly = {{. hook = ipv4_conntrack_getdst ,. owner = this_module ,. pF = nfproto_ipv4 ,. hooknum = nf_inet_post_routing ,. priority = nf_ip_pri_conntrack + 1 ,},{. hook = ipv4_conntrack_getdst ,. owner = this_module ,. pF = nfproto_ipv4 ,. hooknum = nf_inet_local_in ,. priority = nf_ip_pri_conntrack + 1 ,},{. hook = ipv4_conntrack_setdst ,. owner = this_module ,. pF = nfproto_ipv4 ,. hooknum = nf_inet_pre_routing ,. priority = nf_ip_pri_conntrack + 1, },}; static int _ init test_info_init (void) {int err; err = bytes (%4_conn_dst_info, array_size (bytes); If (ERR) {return err;} static void _ exit test_info_exit (void) {values (bytes, array_size (bytes);} module_init (test_info_init); module_exit (test_info_exit );

In the text description of the above Implementation ideas, I used as much as possible and tried two words that were not so clear, which involved the Aging Mechanism of stream routing.

Aging Ideology
The standard route query is to search for each package. After a flow route is introduced, you do not need to search for the SKB route, instead, the route settings are directly retrieved from the conntrack to the skb. The route on the conntrack is the first time the route table is searched for the SKB. Then a problem will be introduced, that is, when to find the route table for SKB again to update the conntrack route. This question cannot be answered directly. For a network with a stable route, you do not need to search for it again, because the routing search results for the first forward packet and the first reverse packet of a stream will remain valid throughout the life cycle of the stream, after all, the route has not changed, however, if a related route changes during the life cycle of the stream, you need to update the conntrack routing result again.
Therefore, a notification mechanism can be introduced to solve the problem. When a route is changed, it will not run in the prerouting HOOK:
skb_dst_set(skb, dst_info->dst[dir]);
This is very easy. We can use the kernel's notifier mechanism to notify the above-mentioned stream routing module to change a flag when any route changes. In the prerouting hook, if this flag location is found, skb_dst_set is not run. In this way, the above Code will be changed to the following:

Static unsigned int ipv4_conntrack_getdst (unsigned int hooknum, struct sk_buff * SKB, const struct net_device * In, const struct net_device * Out, INT (* okfn) (struct sk_buff *)) {... if (ACCT) {int dir = ctinfo2dir (ctinfo); dst_info = (struct nf_conn_priv *) Acct; // set the route of the stream unconditionally. The DST of SKB may come from two places: // 1. from ipv4_conntrack_setdst; // 2. search for dst_hold (skb_dst (SKB); dst_info-> DST [dir] = skb_dst (SKB);} return nf_accept ;} static unsigned int ipv4_conntrack_setdst (unsigned int hooknum, struct sk_buff * SKB, const struct net_device * In, const struct net_device * Out, INT (* okfn) (struct sk_buff *)) {... if (ACCT) {int dir = ctinfo2dir (ctinfo); dst_info = (struct nf_conn_priv *) Acct; // only when the flag is 1, the stream routing is trusted, and set it to SKB if (flag = 1) {skb_dst_set (SKB, dst_info-> DST [dir]) ;}} return nf_accept ;}
However, it may be better to give the case to the user. After all, all the events that occur in the kernel state can be monitored by the user State. I think it is better to use a writable procfs file to notify the flag to change to 1 or 0, that is, the flag value is set by the user, so that the user can enable it at will, disable the stream routing mechanism, for example, using the iproute2 monitor mechanism to monitor the route changes, if the unrelated route changes, the flag will not be updated. The flag is updated only when the related route changes.

The nf_conntrack mechanism is used to store routes, eliminating the need for route searches per packet

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.