当前位置: 首页 > news >正文

LWIP的IP协议笔记

IP协议简介

IP协议是TCP/IP协议族的基石,它为上层提供无连接、不可靠的服务

无连接:指IP通信双方都不长久的维持对方的任何信息。这表示上层协议每次发送数据,都需要明确指出对方的IP地址

不可靠:指IP协议不能把IP数据报准确到达接收端,只是会尽最大努力。一旦发送失败,就通知上层协议,而不会试图重发

描述:总路线主机H1  到  主机H2

         目的地址IP2 就是主机H2的地址

         源地址IP1 就是主机H1的地址

传输

路径

网络层

写入IP数据报首部地址

数据链路层

写入MAC帧首部地址

源地址

目的地址

源地址

目的地址

H1->R1

IP1

IP2

HA1

HA3

R1->R2

IP1

IP2

HA4

HA5

R2->H2

IP1

IP2

HA6

HA2

为什么需要MAC地址和IP地址?

①数据传输过程中,源IP地址和目标IP不变

②路由器根据目标IP地址的网络号进行路由

IP地址分为ABCDE类地址

总结:

MAC地址用来数据转发,而IP地址用来确认路标

mac的作用则是实现直连的两个设备之间的通信,而IP则负责在没有智联的两个网络之间进行通信传输;

IP分片

MTU最大1500字节;

当数据传输大于1500字节的时候就需要数据分片

一、抓取 IP协议的内容
 

Wireshark抓包工具

可以看到每个数据包的所有bit

并可以分析数据

二、IP协议字段解析

version版本
header length头⻓度
differentiated service field差分服务区域
total length总⻓度
identification标识位
flags标志位
fragment offset偏移量
time to live⽣存周期
Protocol上层协议
Header checksum校验和
Source源IP地址
destination⽬的IP地址

 数据包框图

三、IP协议处理分片
 

3.1、MTU是什么最⼤传输单元,

默认是1500字节

指的是⼀个数据包从⽹卡发出时,最⼤的total length的⻓度

如果⼤于1500字节就会进⾏分⽚

3.2、理解identification 、flags 、fragment offset 这些字段 的作用


1,identification 字段:

⽤来标识⼀个分⽚ ,例如:4000字节(含首部的4000字节)需要分⽚,分成1500, 1500, 1040,三⽚ ,这些数据包的identification字段都是⼀致的;与下图3一致(这里和课程差异一点)

多出来的60 是多的三个包控制段3*20

2,flags 字段:

Reserved bit保留位,暂时没作⽤
Don’t fragmentDM位,该位置1,说明该数据包不能被分⽚(⽤来测试接⼝的MTU⼤⼩的)
More fragmentFM位,如果是最后⼀个分⽚,就⽤0来表示,不是最后⼀个分⽚就⽤1来表示
3,fragment offset 字段:

fragment offset也叫偏移量,偏移的计算是payload部分payload指的是去掉⼆层头部和三层头部后的内容1500字节的分⽚,指的是IP+payload的⼤⼩

加上E2,整个数据包抓包看到的⼤⼩是1514字节 ,这点不用理会

下图3的数据包,是首部20字节加数据3980的4000字节

888:标识符

0/1:尾部识别

185/370:是整个大包的数据偏移量  185是从3980数据的第185个开始的字节   

185=(1500-20)/8       mtu=1500    首部=20字节   除以8=是等于8倍的压缩量;注释1

    注释1:这个数据只有13bit 通过压缩 8倍  13bit+3bit=16bit      可描述偏移65535个字节

         这里是内存堆 payload+偏移量 指向分片的数据段

四、分片原理

调用分片原理的主函数实现在源文件:\Middlewares\lwip\src\core\ipv4\ip4.c       826行

err_t ip4_output_if_src(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest,
                  u8_t ttl, u8_t tos,
                  u8_t proto, struct netif *netif)

条件:用户数据大小:3960,pbuf:内存堆,TCP模式
本来用户数据是3980,至少20字节作为首部,但是多了各层添加头部,所以真正的数据是3960

不要看34  54的分片结构框图,我都被搞蒙。答:这里的54和分包的结构不一样,这是未分包时候的;

PS:以下的4000是 20字节头部+数据的4000

1),申请pbuf
 

54字节由来:20字节IP首部    20字节TCP经过各层的首部  14字节是选项字节和源/目标地址

下图是申请的内存堆大小 

2),递交给传输层
 

TCP首部:20,调用pbuf_add_header(p, TCP_HLEN)函数偏移payload指针
 

3),递交给网络层
 

IP首部:20,调用pbuf_add_header(p, IP_HLEN)函数偏移payload指针
 

4),分片ip4_frag()函数
 

err_t
ip4_frag(struct pbuf *p, struct netif *netif, const ip4_addr_t *dest)
{
struct pbuf *rambuf;
#if !LWIP_NETIF_TX_SINGLE_PBUF
struct pbuf *newpbuf;
u16_t newpbuflen = 0;
u16_t left_to_copy;
#endif
struct ip_hdr *original_iphdr;
struct ip_hdr *iphdr;
/* 第一步:nfb = (1500 - 20)/8 = 185 */
const u16_t nfb = (u16_t)((netif->mtu - IP_HLEN) / 8);
u16_t left, fragsize;
u16_t ofo;
int last;
/* poff = 20 */
u16_t poff = IP_HLEN;
u16_t tmp;
int mf_set;
/* 第二步:获取IP首部信息 */
original_iphdr = (struct ip_hdr *)p->payload;
iphdr = original_iphdr;
/* 第三步:判断首部获取成功 */
if (IPH_HL_BYTES(iphdr) != IP_HLEN) {
/* ip4_frag() does not support IP options */
return ERR_VAL;
} /
* 第四步:tmp = 保存偏移量的字段数值 = 0 */
tmp = lwip_ntohs(IPH_OFFSET(iphdr));
/* 第五步:ofo = 0 & 0x1fffU = 0 */
ofo = tmp & IP_OFFMASK;
/* 第六步:mf_set = 0 & 0x2000U = 0 */ */
mf_set = tmp & IP_MF;
/* 第七步:left = p->tot_len - 20
1:4000 - 20 = 3980 */
left = (u16_t)(p->tot_len - IP_HLEN);
/* 第八步:left > 0 ? */
while (left) {
/* 第九步:分片大小fragsize = left < (nfb * 8) ? left : (nfb * 8)
1:3980 < 1480 ? 3980 : 1480 fragsize = 1480
2:2500 < 1480 ? 2500 :1480 fragsize = 1480
3:1020 < 1480 ? 1020 :1480 fragsize = 1020 */
fragsize = LWIP_MIN(left, (u16_t)(nfb * 8));
/* 第十步:申请pbuf内存---用来描述分片 */
rambuf = pbuf_alloc(PBUF_LINK, IP_HLEN, PBUF_RAM);
if (rambuf == NULL) {
goto memerr;
} /
* 第十一步:把IP首部复制到rambuf当中 */
SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN);
/* iphdr指向rambuf->payload */
iphdr = (struct ip_hdr *)rambuf->payload;
/* left_to_copy = 分片大小fragsize
1:left_to_copy = 1480
2:left_to_copy = 1480
3:left_to_copy = 1020 */
left_to_copy = fragsize;
while (left_to_copy) {
struct pbuf_custom_ref *pcr;
/* plen = p->len - poff
1:4000 - 20 = 3980 plen = 3980
2:4000 - 1500 = 2500 plen = 2500
3:4000 - 2980 = 1020 plen = 1020 */
u16_t plen = (u16_t)(p->len - poff);
/* 新的pbuf大小 newpbuflen = left_to_copy < plen ? left_to_copy : plen
1:newpbuflen = 1480
2:newpbuflen = 1480
3:newpbuflen = 1020 */
newpbuflen = LWIP_MIN(left_to_copy, plen);
/* 是否为空 */
if (!newpbuflen) {
poff = 0;
p = p->next;
continue;
} /
* 申请一个新的结构pbuf_custom_ref */
pcr = ip_frag_alloc_pbuf_custom_ref();
if (pcr == NULL) {
pbuf_free(rambuf);
goto memerr;
} /
* 镜像pbuf(p),尽管我们可能不需要它的全部。 */
newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc,
(u8_t *)p->payload + poff, newpbuflen);
if (newpbuf == NULL) {
ip_frag_free_pbuf_custom_ref(pcr);
pbuf_free(rambuf);
goto memerr;
} p
buf_ref(p);
pcr->original = p;
pcr->pc.custom_free_function = ipfrag_free_pbuf_custom;
/* rambuf与newpbuf链接 */
pbuf_cat(rambuf, newpbuf);
/* 1:left_to_copy = 1480 - 1480 = 0
2:left_to_copy = 1480 - 1480 = 0
3:left_to_copy = 1020 - 1020 = 0 */
left_to_copy = (u16_t)(left_to_copy - newpbuflen);
if (left_to_copy) {
poff = 0;
p = p->next;
}
} /
* 1:poff = 20 + 1480 = 1500
2:poff = 1500 + 1480 = 2980
3:poff = 2980 + 1020 = 4000 */
poff = (u16_t)(poff + newpbuflen);
/* 1:last = (3980 <= 1500 - 20 ) = 0
2:last = (2500 <= 1500 - 20 ) = 0
3:last = (1020 <= 1500 - 20 ) = 1 */
last = (left <= netif->mtu - IP_HLEN);
/* 设置新的偏移量和MF标志 */
tmp = (IP_OFFMASK & (ofo));
if (!last || mf_set) {
/* 最后一个片段有MF设置 */
tmp = tmp | IP_MF;
} /
* 设置该分片的IP首部信息 */
IPH_OFFSET_SET(iphdr, lwip_htons(tmp));
IPH_LEN_SET(iphdr, lwip_htons((u16_t)(fragsize + IP_HLEN)));
IPH_CHKSUM_SET(iphdr, 0);
/* 发送该分片IP数据包 */
netif->output(netif, rambuf, dest);
IPFRAG_STATS_INC(ip_frag.xmit);
/* 释放内存 */
pbuf_free(rambuf);
/* 1:left = 3980 - 1480 = 2500
2:left = 2500 - 1480 = 1020
3:left = 1020 - 1020 = 0 */
left = (u16_t)(left - fragsize);
/* 1:ofo = 0 + 185 = 185
2:ofo = 185 + 185 = 370
3:ofo = 370 + 185 = 555 */
ofo = (u16_t)(ofo + nfb);
} M
IB2_STATS_INC(mib2.ipfragoks);
return ERR_OK;
memerr:
MIB2_STATS_INC(mib2.ipfragfails);
return ERR_MEM;
}

分片函数的效果图

传输层递交示意图(已经添加了IP首部,该数据包处于IP层(网络层))4000字节=头+数据

分片1

分片2

分片3

IP重装

相关文章:

  • Java中的代理机制
  • STC32G12K128程序大于64KB使用128KB用户EEPROM设置
  • JavaWeb基础
  • 438. 找到字符串中所有字母异位词(滑动窗口)
  • Android方法耗时监控插件开发
  • vue3项目中CodeMirror的复杂用法,实现自定义语法模式,手动在指定光标位置插入/获取/替换/绑定文本
  • 当可视化遇上 CesiumJS:突破传统,打造前沿生产配套方案
  • CentOS7.9部署FunASR实时语音识别接口 | 部署商用级别实时语音识别接口FunASR
  • 线程安全 1_线程安全
  • Java Bean容器详解:核心功能与最佳使用实践
  • 关于单片机的基础知识(一)
  • Qt/C++开发监控GB28181系统/实时视频预览/视频点播/rtp解包解码显示
  • M0基础篇之ADC
  • 树莓派4的v4l2摄像头(csi)no cameras available,完美解决
  • leetcode0829. 连续整数求和-hard
  • python:vars()方法
  • [docker基础四]容器虚拟化基础之 LXC
  • sensitive-word-admin v2.0.0 全新 ui 版本发布!vue+前后端分离
  • Windows 上使用 WSL 2 后端的 Docker Desktop
  • Linux `ifconfig` 指令深度解析与替代方案指南
  • 国内大模型人才大战打响!大厂各出奇招
  • 龙湖集团:今年前4个月销售220.8亿元,4月新增两块土地储备
  • 14岁女生瞒报年龄文身后洗不掉,法院判店铺承担六成责任
  • 高盛上调A股未来12个月目标点位,沪深300指数潜在回报15%
  • 国家主席习近平同普京总统签署关于进一步深化中俄新时代全面战略协作伙伴关系的联合声明
  • 国防部:奉劝有关国家不要引狼入室,甘当棋子