Detailed analysis of TCP/IP stack implementation in libnids (bottom) -- IP sharding

Source: Internet
Author: User

Before that, if you do not understand the IP sharding technology, refer to here. The IP sharding technology is simple and violent, and it is not as complicated as the TCP window protocol. Basically, the code is basically in ip_defragment.c.

Let's talk about it in general. First, each IP address (host) will have an IP segment package (note that it is an IP address, not an IP address pair ). Therefore, each IP Address has the following struct to maintain the above IP segments:

Struct hostfrags {struct ipq * ipqueue; // here, the IP shard queue int ip_frag_mem; u_int ip; // the IP address corresponding to the host. // The following three lines tell us, this is an element of the hash table, int hash_index; struct hostfrags * prev; struct hostfrags * next;}; // The following is a hash table that maintains all IP addresses. Static struct hostfrags ** fragtable;

There are a lot of fragmented IP Packets Under each IP address-IP Fragment queue, which is defined in the IP Fragment queue:

/* Describe an entry in the "incomplete datagrams" queue. */struct ipq {  unsigned char *mac;        /* pointer to MAC header                */  struct ip *iph;        /* pointer to IP header                 */  int len;            /* total length of original datagram    */  short ihlen;            /* length of the IP header              */  short maclen;            /* length of the MAC header             */  struct timer_list timer;    /* when will this queue expire?         */  struct ipfrag *fragments;    /* linked list of received fragments    */  struct hostfrags *hf;  struct ipq *next;        /* linked list pointers                 */  struct ipq *prev;  // struct device *dev;    /* Device - for icmp replies */};

The final IP fragmentation is defined here:

/* Describe an IP fragment. */struct ipfrag {  int offset;            /* offset of fragment in IP datagram    */  int end;            /* last byte of data in datagram        */  int len;            /* length of this fragment              */  struct sk_buff *skb;        /* complete received fragment           */  unsigned char *ptr;        /* pointer into real fragment data      */  struct ipfrag *next;        /* linked list pointers                 */  struct ipfrag *prev;};

Because the sharded code in libnids is modified from the kernel, the kernel comments are retained. I will not explain more here.

Now, proceed to the processing logic. As shown in the example, first look at initialization:

void ip_frag_init(int n){  struct timeval tv;   gettimeofday(&tv, 0);  time0 = tv.tv_sec;  fragtable = (struct hostfrags **) calloc(n, sizeof(struct hostfrags *));  if (!fragtable)    nids_params.no_mem("ip_frag_init");  hash_size = n;}

It is as simple as it cannot be simple as sharding a hash table of a host. Manual splitting. Okay, let's look at the reorganization logic:

// The int ip_defrag_stub (struct ip * iph, struct ip ** defrag) {int offset, flags, tot_len; struct sk_buff * skb; numpack ++; // process the timeout event timenow = 0; // refresh the time while (timer_head & timer_head-> expires <jiffies () {this_host = (struct ipq *) (timer_head-> data)-> hf; timer_head-> function (timer_head-> data);} // then calculate the part offset = ntohs (iph-> ip_off ); flags = offset &~ IP_OFFSET; offset & = IP_OFFSET; // this package is not a multipart if (flags & IP_MF) = 0) & (offset = 0) {ip_defrag (iph, 0); return IPF_NOTF;} // this package is a shard. First, apply for a sk_buff to save the shard data and hand it over to the defrag function tot_len = ntohs (iph-> ip_len ); skb = (struct sk_buff *) malloc (tot_len + sizeof (struct sk_buff); if (! Skb) nids_params.no_mem ("ip_defrag_stub"); skb-> data = (char *) (skb + 1); memcpy (skb-> data, iph, tot_len ); skb-> truesize = tot_len + 16 + nids_params.dev_addon; skb-> truesize = (skb-> truesize + 15 )&~ 15; skb-> truesize + = nids_params.sk_buff_size; // if all the parts of an IP package are collected, ip_defrag returns the merged IP package, IPF_NEW, process the next ip packet // otherwise, IPF_ISF is returned, and if (* defrag = (struct ip *) ip_defrag (struct ip *) (skb-> data) is skipped ), skb) return IPF_NEW; return IPF_ISF;}/* Process an incoming IP datatefragment. * // here is the main logic of fragment reorganization. static char * ip_defrag (struct ip * iph, struct sk_buff * skb) {struct ipfrag * prev, * next, * tmp; struct I Pfrag * tfp; struct ipq * qp; char * skb2; unsigned char * ptr; int flags, offset; int I, ihl, end; // if it is a shard, if there are no corresponding host items in the host hash table, create a new // here, and set the this_host variable to the host if (! Hostfrag_find (iph) & skb) hostfrag_create (iph);/* Start by cleaning up the memory. * // memory usage is too large, panic, and then release the memory used by the current host shard if (this_host) if (this_host-> ip_frag_mem> IPFRAG_HIGH_THRESH) ip_evictor (); /* Find the entry of this IP datatein the "incomplete queue Rams" queue. * // here, find the ip sharding linked list corresponding to this ip package if (this_host) qp = ip_find (iph); else qp = 0;/* Is this a non-fragmented datted? */Offset = ntohs (iph-> ip_off); flags = offset &~ IP_OFFSET; offset & = IP_OFFSET; if (flags & IP_MF) = 0) & (offset = 0) {if (qp! = NULL) ip_free (qp);/* Fragmented frame replaced by full unfragmented copy */return 0;}/* ip_evictor () cocould have removed all queues for the current host */if (! This_host) hostfrag_create (iph); offset <= 3;/* offset is in 8-byte chunks */ihl = iph-> ip_hl * 4; /* If the queue already existed, keep restarting its timer as long as we still are grouping fragments. otherwise, create a fresh queue entry. * /// if the current host passes through the package fragment if (qp! = NULL) {/* ANK. if the first fragment is already ed, we shoshould remember the correct IP header (with options) */if (offset = 0) {qp-> ihlen = ihl; memcpy (qp-> iph, iph, ihl + 8);} del_timer (& qp-> timer); qp-> timer. expires = jiffies () + IP_FRAG_TIME;/* about 30 seconds */qp-> timer. data = (unsigned long) qp;/* pointer to queue */qp-> timer. function = ip_expire;/* expire function */add_timer (& qp-> Timer);} // otherwise, create a new shard queue else {/* If we failed to create it, then discard the frame. */if (qp = ip_create (iph) = NULL) {kfree_skb (skb, FREE_READ); return NULL ;}/ * Attempt to construct an oversize packet. * /// the size of a large IP package cannot exceed 65535. Once discovered, the if (ntohs (iph-> ip_len) + (int) offset> 65535 will be abandoned) {// NETDEBUG (printk ("Oversized packet received ed from % s \ n", int_ntoa (iph-> ip_src.s_addr); nids_params.sys Log (NIDS_WARN_IP, NIDS_WARN_IP_OVERSIZED, iph, 0); kfree_skb (skb, FREE_READ); return NULL;} // locate the shard in the shard queue, at the same time, the overlap is processed // if there is overlap, remove the old overlapping part/* Determine the position of this fragment. */end = offset + ntohs (iph-> ip_len)-ihl;/* Point into the IP datate'data' part. */ptr = (unsigned char *) (skb-> data + ihl);/* Is this the final fragment? */If (flags & IP_MF) = 0) qp-> len = end; /* Find out which fragments are in front and at the back of us in the chain of fragments so far. we must know where to put this fragment, right? */Prev = NULL; for (next = qp-> fragments; next! = NULL; next = next-> next) {if (next-> offset> = offset) break;/* bingo! */Prev = next;}/* We found where to put this one. check for overlap with preceding fragment, and, if needed, align things so that any overlaps are eliminated. */if (prev! = NULL & offset <prev-> end) {nids_params.syslog (NIDS_WARN_IP, NIDS_WARN_IP_OVERLAP, iph, 0); I = prev-> end-offset; offset + = I; /* ptr into datasync */ptr + = I;/* ptr into fragment data */}/* Look for overlap with succeeding segments. if we can merge fragments, do it. */for (tmp = next; tmp! = NULL; tmp = tfp) {tfp = tmp-> next; if (tmp-> offset> = end) break;/* no overlaps at all */nids_params.syslog (NIDS_WARN_IP, NIDS_WARN_IP_OVERLAP, iph, 0); I = end-next-> offset;/* overlap is 'I' bytes */tmp-> len-= I; /* so reduce size of */tmp-> offset + = I;/* next fragment */tmp-> ptr + = I; /* If we get a frag size of <= 0, remove it and the packet that it goes. we never throw the new Frag away, so the frag being dumped has always been charged for. */if (tmp-> len <= 0) {if (tmp-> prev! = NULL) tmp-> prev-> next = tmp-> next; else qp-> fragments = tmp-> next; if (tmp-> next! = NULL) tmp-> next-> prev = tmp-> prev; next = tfp;/* We have killed the original next frame */frag_kfree_skb (tmp-> skb, FREE_READ); frag_kfree_s (tmp, sizeof (struct ipfrag);} // Insert the current shard into the queue/* Insert this fragment in the chain of fragments. */tfp = NULL; tfp = ip_frag_create (offset, end, skb, ptr);/* No memory to save the fragment-so throw the lot. if we failed the frag_create we haven't char Ged the queue. */if (! Tfp) {nids_params.no_mem ("ip_defrag"); kfree_skb (skb, FREE_READ); return NULL;}/* From now on our buffer is charged to the queues. */tfp-> prev = prev; tfp-> next = next; if (prev! = NULL) prev-> next = tfp; else qp-> fragments = tfp; if (next! = NULL) next-> prev = tfp;/* OK, so we inserted this new fragment into the chain. check if we now have a full IP datatewhich we can bump up to the IP layer... * // check whether all fragments have been collected. if yes, combine them into a large IP package and return if (ip_done (qp) {skb2 = ip_glue (qp ); /* glue together the fragments */return (skb2);} return (NULL );}

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.