1、 IP分片
任何IP层接收到一份要发送的IP数据报时,它要判断向本地哪个接口发送数据,并查询该接口的MTU。IP把MTU与数据报的长度进行比较,如果需要则进行分片。分片可以发生在原始发送端主机上,也可以发送在中间路由器上。IP数据报分片后,只有到达目的主机后才进行重装。
IP首部与分片有关的字段:
(1)对于每份IP数据报来说,都有一个标识字段,该值在分片时被复制到每个片中。
(2)标志字段用其中一个bit表示
“
更多的片
”
,除最后一片外,其他每个分片都要设置为1。
(3)片偏移字段指的是该片偏移原始数据报开始处的位置。
(4)数据报被分片后,每个片的总长度要改为该片的长度值。
(5)标志字段中有一个bit表示
“
不分片
”
,如果该位1,IP将不对数据报进行分片。
IP报即使丢失一片数据报也要重传整个数据报。为什么呢?因为IP层没有超时重传的机制,必须由更高层负责超时重传。
总结:
三个字段
标识字段(ip_id):标识特定数据报的分片
标志字段(ip_off的3个高位比特)
偏移字段(ip_off的13个低位比特)
几个区别
普通IP包:ip_off、MF 为 0
最后一个分片包: ip_off > 0、MF 为 0
其它分片包:ip_off ≥ 0、MF 为 1
2、 数据结构设计
链表_FRAG
结点结构ipfrag,保存一个分片
作用:保存同属于一个IP包的所有分片数据
链表中各结点按ip_off由小到大排序
链表_IPQ
结点结构ipq,作为_FRAG的头结点,描述属于同一个IP包的所有分片数据的共同特征
作用:将目的地址相同的分片组织到一起
链表_HOSTFRAG
结点结构hostfrags,作为_IPQ的头结点
作用:将目的地址不同但hash值相同的分片数据组织到地起
hash表fragtable
实现:struct hostfrags **fragtable
作用: fragtable[index]为_HOSTFRAG的头结点
hash表及三个链表之间的关系图
3、 分片重组流程
4、 代码及相关注释
http://blog.csdn.net/sandrain_zeq/archive/2007/06/13/1651258.aspx
5、 几个细节
5.1 Step 14:在_FRAG链表中插入的位置
代码:
if (next->offset >= offset)
break;
当prev和next结点都存在时满足的条件
offset
∊
(
prev->offset
,
next->offset
]
隐含意思:当前分片与prev之前的结点无重叠,与prev可能有重叠
5.2 step 15:和prev有重叠,调整当前分片
调整前图
调整后图
step 15:和prev有重叠,调整当前分片后没有判断当前数据的长度,之后会创建一个无用结点!
2.6.17内核已处理!
////////////////////////////////////////////////////////////////////////
~
[
source navigation
] ~
[
diff markup
] ~
[
identifier search
] ~
[
freetextsearch
] ~
[
file search
] ~
Linux
Cross Reference
Linux-2.6.17/net/ipv4/ip_fragment.c
Version: ~
[
2.6.16
] ~
[
2.6.17
] ~
Architecture: ~
[ ia64
] ~
[
i386
] ~
[ arm
] ~
[ ppc
] ~
[ sparc64
] ~
1
/*
2
* INET An implementation of the TCP/IP protocol suite for the LINUX
3
* operating system. INET is implemented using the BSD Socket
4
* interface as the means of communication with the user level.
5
*
6
* The IP fragmentation functionality.
7
*
8
* Version: $Id: ip_fragment.c,v 1.59 2002/01/12 07:54:56 davem Exp $
9
*
12
*
13
* Fixes:
14
* Alan Cox : Split from ip.c , see ip_input.c for history.
15
* David S. Miller : Begin massive cleanup...
16
* Andi Kleen : Add sysctls.
17
* xxxx : Overlapfrag bug.
18
* Ultima : ip_expire() kernel panic.
19
* Bill Hawes : Frag accounting and evictor fixes.
20
* John McDonald : 0 length frag bug.
21 * Alexey Kuznetsov: SMP races, threading, cleanup.
22 * Patrick McHardy : LRU queue of frag heads for evictor.
23 */
24
465
466 /* Add new segment to existing queue. */
467 static void
ip_frag_queue
(struct
ipq
*
qp
, struct
sk_buff
*
skb
)
468 {
469 struct
sk_buff
*prev, *
next
;
470 int
flags
,
offset
;
........................
........................
........................
........................
522 /* Find out which fragments are in front and at the back of us
523 * in the chain of fragments so far. We must know where to put
524 * this fragment, right?
525 */
526 prev =
NULL
;
527 for(
next
=
qp
->
fragments
;
next
!=
NULL
;
next
=
next
->
next
) {
528 if (
FRAG_CB
(
next
)->
offset
>=
offset
)
529 break; /* bingo! */
530 prev =
next
;
531 }
532
533 /* We found where to put this one. Check for overlap with
534 * preceding fragment, and, if needed, align things so that
535 * any overlaps are eliminated.
536 */
537 if (prev) {
538 int
i
= (
FRAG_CB
(prev)->
offset
+ prev->
len
) -
offset
;
539
540 if (
i
> 0) {
541
offset
+=
i
;
542
if (end <= offset)
543 goto err;
544 if (!
pskb_pull
(
skb
,
i
))
545 goto
err
;
546 if (
skb
->ip_summed !=
CHECKSUM_UNNECESSARY
)
547
skb
->ip_summed =
CHECKSUM_NONE
;
548 }
549 }
550
551 while (
next
&&
FRAG_CB
(
next
)->
offset
<
end
) {
552 int
i
=
end
-
FRAG_CB
(
next
)->
offset
; /* overlap is 'i' bytes */
553
554 if (
i
<
next
->
len
) {
555 /* Eat head of the next overlapped fragment
556 * and leave the loop. The next ones cannot overlap.
557 */
558 if (!
pskb_pull
(
next
,
i
))
559 goto
err
;
560
FRAG_CB
(
next
)->
offset
+=
i
;
561
qp
->meat -=
i
;
........................
........................
........................
........................
~ [
source navigation
]
~ [
diff markup
]
~ [
identifier search
]
~ [
freetext search
]
~ [
file search
]
~
This page was automatically generated by the
LXR engine
.
Visit the
LXR main site
for more
information.
////////////////////////////////////////////////////////////////////////
5.3 step 18:
i = end - next->offset
tmp->len -= i
tmp->offset += i
tmp->ptr += i
和next有重叠时的两种情况:
1:
2:
5.4 ipq结构中的特殊成员timer
作用:描述已经收到的属于同一IP包的所有分片的存活期限
创建:step 8
初始设置:step 10
expires为当前时间+30秒
function:失效时的处理函数地址
data:失效时的处理函数的参数,即timer所在的ipq结点首地址
5.5 ipq结构中的特殊成员timer
更新:
所有ipq结点中的timer成员组成一个双向链表_TIMER,链首:timer_head,链尾:timer_tail
分片链表超时处理 step 1 : 当一个_IPQ链表在30秒内没有再收到分片数据时,放弃重组
timer的更新step 13 :当收到一个分片时,重新设置失效时间,并将该分片所属ipq中的timer移到_TIMER的尾部
5.6 分片数据是否可重组的判断
借助ipq结构中的成员变量len
初始值:0
更新:仅当收到最后一个分片时才设置len
判断:
当ipq.len为0时直接返回
当收到最后一个分片后才检查_FRAG链表中的各分片是否相连 (ip_done函数中)判断
代码:
参tag: zeq_final_frag