TCP/IP详解2 学习笔记---mbuf
1,mbuf就是存储要发送数据的memery buf,类似于skb_buf.不过结构比较简单。
/* header at beginning of each mbuf: */
这个结构用来描述mbuf跟具体的内容无关
struct m_hdr {
struct mbuf *mh_next; /* next buffer in chain */
struct mbuf *mh_nextpkt; /* next chain in queue/record */
int mh_len; /* amount of data in this mbuf */
caddr_t mh_data; /* location of data */
short mh_type; /* type of data in this mbuf */
short mh_flags; /* flags; see below */
};
/* record/packet header in first mbuf of chain; valid if M_PKTHDR set */
对mbuf中数据的描述,len和接收接口
struct pkthdr {
int len; /* total packet length */
struct ifnet *rcvif; /* rcv interface */
};
/* description of external storage mapped into mbuf, valid if M_EXT set */
struct m_ext {
caddr_t ext_buf; /* start of buffer */
void (*ext_free)(); /* free routine if not the usual */
u_int ext_size; /* size of buffer, for ext_free */
};
这个就是mbuf的描述,设计的比较巧妙
struct mbuf {
struct m_hdr m_hdr;
union {
struct {
struct pkthdr MH_pkthdr; /* M_PKTHDR set */
union {
struct m_ext MH_ext; /* M_EXT set */
char MH_databuf[MHLEN];
} MH_dat;
} MH;
char M_databuf[MLEN]; /* !M_PKTHDR, !M_EXT */
} M_dat;
};
2,mbuf中mhdr.md_flags:
/* mbuf flags */
一个mbuf的大小是128字节,猜测是一个cacheline的大小。如果数据比较多,就需要多个mbuf连起来或者用一个叫cluster的东西来存储数据。M_EXT就是这个标志
#define M_EXT 0x0001 /* has associated external storage */
表明分组的第一个mbuf,在数据区中有pkthdr
#define M_PKTHDR 0x0002 /* start of record */
表明记录的尾部,TCP是一个字节流,不设置这个标志
#define M_EOR 0x0004 /* end of record */
/* mbuf pkthdr flags, also in m_flags */
#define M_BCAST 0x0100 /* send/received as link-level broadcast */
#define M_MCAST 0x0200 /* send/received as link-level multicast */
/* flags copied when copying m_pkthdr */
这个具体干嘛用的不懂。。。
#define M_COPYFLAGS (M_PKTHDR|M_EOR|M_BCAST|M_MCAST)
3,mbuf的种类
/* mbuf types */
#define MT_FREE 0 /* should be on free list */
#define MT_DATA 1 /* dynamic (data) allocation */ 数据就是这个类型
#define MT_HEADER 2 /* packet header */
#define MT_SOCKET 3 /* socket structure */
#define MT_PCB 4 /* protocol control block */
#define MT_RTABLE 5 /* routing tables */
#define MT_HTABLE 6 /* IMP host tables */
#define MT_ATABLE 7 /* address resolution tables */
#define MT_SONAME 8 /* socket name */
#define MT_SOOPTS 10 /* socket options */
#define MT_FTABLE 11 /* fragment reassembly header */
#define MT_RIGHTS 12 /* access rights */
#define MT_IFADDR 13 /* interface address */
#define MT_CONTROL 14 /* extra-data protocol message */
#define MT_OOBDATA 15 /* expedited data */
4,mbuf相关函数
4.1mbuf的分配
/*
* mbuf allocation/deallocation macros:
*
* MGET(struct mbuf *m, int how, int type)
* allocates an mbuf and initializes it to contain internal data.
*
* MGETHDR(struct mbuf *m, int how, int type)
* allocates an mbuf and initializes it to contain a packet header
* and internal data.
*/
#define MGET(m, how, type) { \
mbtypes[type]把mbuf的type转换成MALLOC需要的type,如M_MBUF,M_SOCKET等
MALLOC((m), struct mbuf *, MSIZE, mbtypes[type], (how)); \
if (m) { \
(m)->m_type = (type); \
MBUFLOCK改变处理器优先级,防止被网络处理器中断,共享资源的保护
MBUFLOCK(mbstat.m_mtypes[type]++;) \
(m)->m_next = (struct mbuf *)NULL; \
(m)->m_nextpkt = (struct mbuf *)NULL; \
#define m_dat M_dat.M_databuf 为pkthdr和m_ext预留了空间
(m)->m_data = (m)->m_dat; \
(m)->m_flags = 0; \
} else \
尝试重新分配,一个主要的问题,分配的内存从哪里来?详见后面
(m) = m_retry((how), (type)); \
}
/*
* When MGET failes, ask protocols to free space when short of memory,
* then re-attempt to allocate an mbuf.
*/
struct mbuf *
m_retry(i, t)
int i, t;
{
register struct mbuf *m;
调用协议的注册函数释放内存
m_reclaim();
把m_retrydefine成NULL这样就直接返回NULL了,但这里怎么保证这个MGET中m_retry返回的是NULL,而上一个返回的是这个函数???????#define在预编译期间就做替换了。
这个的关键就是MGET是一个宏,而不是函数。
#define m_retry(i, t) (struct mbuf *)0
MGET(m, i, t);
#undef m_retry
return (m);
}
这个函数循环调用协议的drain函数分配内存
m_reclaim()
{
register struct domain *dp;
register struct protosw *pr;
提升处理器的优先级不被网络处理中断
int s = splimp();
for (dp = domains; dp; dp = dp->dom_next)
for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
if (pr->pr_drain)
(*pr->pr_drain)();
恢复处理器的优先级
splx(s);
mbstat.m_drain++;
}
分配一个分组头部的mbuf,对m_data和m_flags进行初始化
#define MGETHDR(m, how, type) { \
MALLOC((m), struct mbuf *, MSIZE, mbtypes[type], (how)); \
if (m) { \
(m)->m_type = (type); \
MBUFLOCK(mbstat.m_mtypes[type]++;) \
(m)->m_next = (struct mbuf *)NULL; \
(m)->m_nextpkt = (struct mbuf *)NULL; \
(m)->m_data = (m)->m_pktdat; \
(m)->m_flags = M_PKTHDR; \
} else \
(m) = m_retryhdr((how), (type)); \
}
587 /*
588 * Routine to copy from device local memory into mbufs.
589 */
590 struct mbuf *
591 m_devget(buf, totlen, off0, ifp, copy)
592 char *buf;
593 int totlen, off0;
594 struct ifnet *ifp;
595 void (*copy)();
这个函数是对MGET和MGETHDR的封装,一般由设备驱动程序调用,分配mbuf空间。
1,如果数据长度《84,则在数据(IP数据包)的前面保留16个字节。为输出时添加14字节的MAC包头准备。(一个包含pak_hdr的mbuf最多放100字节的数据)
2,如果数据》85 && 数据《100则不额外保留这16字节的数据
3,如果数据》100,则分配一个cluster进行数据的存放。
可见m_devget根据数据的长度,分配合适的mbuf
4.2mbuf到mbuf中data的转换
定义了两个宏
56 * mtod(m,t) - convert mbuf pointer to data pointer of correct type
57 * dtom(x) - convert data pointer within mbuf to mbuf pointer (XXX)
61 #define mtod(m,t) ((t)((m)->m_data))
MSIZE == 128 这个基于mbuf是128字节对齐
62 #define dtom(x) ((struct mbuf *)((int)(x) & ~(MSIZE-1)))
dotm对cluster的数据有问题,不能正常转换到mbuf,所以需要下面的函数
/*
* Rearange an mbuf chain so that len bytes are contiguous
* and in the data area of an mbuf (so that mtod and dtom
* will work for a structure of size len). Returns the resulting
* mbuf chain on success, frees it and returns null on failure.
* If there is room, it will add up to max_protohdr-len extra bytes to the
* contiguous region in an attempt to avoid being called next time.
*/
这个函数从mbuf链表中取出len字节的数据放在第一个mbuf中,使dtom能正确运行
struct mbuf *http://www.zyxsw.net
m_pullup(n, len)
register struct mbuf *n;
int len;
{
register struct mbuf *m;
register int count;
int space;
/*
* If first mbuf has no cluster, and has room for len bytes
* without shifting current data, pullup into it,
* otherwise allocate a new mbuf to prepend to the chain.
*/
if ((n->m_flags & M_EXT) == 0 &&
n->m_data + len < &n->m_dat[MLEN] && n->m_next) {
if (n->m_len >= len)
return (n);
m = n;
n = n->m_next;
len -= m->m_len;
} else {
if (len > MHLEN)
goto bad;
MGET(m, M_DONTWAIT, n->m_type);
if (m == 0)
goto bad;
m->m_len = 0;
if (n->m_flags & M_PKTHDR) {
M_COPY_PKTHDR(m, n);
n->m_flags &= ~M_PKTHDR;
}
}
space = &m->m_dat[MLEN] - (m->m_data + m->m_len);
do {
count = min(min(max(len, max_protohdr), space), n->m_len);
bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
(unsigned)count);
len -= count;
m->m_len += count;
n->m_len -= count;
space -= count;
if (n->m_len)
n->m_data += count;
else
n = m_free(n);
} while (len > 0 && n);
if (len > 0) {
(void) m_free(m);
goto bad;
}
m->m_next = n;
return (m);
bad:
m_freem(n);
MPFail++;
return (0);
}
有些细节的东西还不明确,还需要进一步整理。
TCP/IP详解2 学习笔记---mbuf的更多相关文章
- TCP/IP详解 卷一学习笔记(转载)
https://blog.csdn.net/cpcpcp123/article/details/51259498
- 《TCP/IP详解》读书笔记
本书以UNIX为背景,紧贴实际介绍了数据链层.网络层.运输层 一.整体概念 1.各层协议的关系,只讨论四层 各层常见的协议: 网络层协议:IP协议.ICMP协议.ARP协议.RARP协议. ...
- 《TCP/IP详解 卷1:协议》系列分享专栏
<TCP/IP详解卷1:协议>是一本详细的TCP/IP协议指南,计算机网络历久不衰的经典著作之一. 作者理论联系实际,使读者可以轻松掌握TCP/IP的知识.阅读对象为计算机专业学生.教师以 ...
- 《TCP/IP详解 卷1:协议》第3章 IP:网际协议
3.1 引言 IP是TCP/IP协议族中最为核心的协议.所有的TCP.UDP.ICMP及IGMP数据都以IP数据报格式传输(见图1-4).许多刚开始接触TCP/IP的人对IP提供不可靠.无连接的数据报 ...
- 《TCP/IP详解 卷1:协议》第4章 ARP:地址解析协议
4.1 引言 本章我们要讨论的问题是只对TCP/IP协议簇有意义的IP地址.数据链路如以太网或令牌环网都有自己的寻址机制(常常为48 bit地址),这是使用数据链路的任何网络层都必须遵从的.一个网络如 ...
- TCP/IP详解学习笔记
TCP/IP详解学习笔记(1)-基本概念 TCP/IP详解学习笔记(2)-数据链路层 TCP/IP详解学习笔记(3)-IP协议,ARP协议,RARP协议 TCP/IP详解学习笔记(4)-ICMP协议, ...
- TCP/IP详解学习笔记 这位仁兄写得太好了
TCP/IP详解学习笔记(1)-基本概念 为什么会有TCP/IP协议 在世界上各地,各种各样的电脑运行着各自不同的操作系统为大家服务,这些电脑在表达同一种信息的时候所使用的方法是千差万别.就好像圣 ...
- TCP/IP详解学习笔记- 概述
TCP/IP详解学习笔记(1)-- 概述1.TCP/IP的分层结构 网络协议通常分不同层次进行开发,每一层分别负责不同的同信功能.TCP/IP通常被认为是一个四层协议系统. 如图所 ...
- TCP/IP详解学习笔记 这位仁兄写得太好了.(转载)
TCP/IP详解学习笔记 这位仁兄写得太好了 TCP/IP详解学习笔记 这位仁兄写得太好了. http://blog.csdn.net/goodboy1881/category/20444 ...
随机推荐
- [Android Pro] How to get recent tasks on Android “L”?
reference : http://stackoverflow.com/questions/24590533/how-to-get-recent-tasks-on-android-l/2688546 ...
- !对c++类的理解
c++的类可以分为两类,一种是entity的类(i.e.,实体类),一种是function的类(i.e.,功能类). 对于构造entity的类,包括这种entity的属性已经它本身具备的功能: 而fu ...
- iOS-Runtime-Headers
iOS8.4 及之前的头文件 私有及共有API https://github.com/nst/iOS-Runtime-Headers
- LeetCode : 223. Rectangle Area
aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAABRQAAAQ0CAYAAAAPPZBqAAAMFGlDQ1BJQ0MgUHJvZmlsZQAASImVlw
- settimeout,cleartimeout的使用分析
设置时间的定时轮回执行,大家想到的js也就是settimeout这个方法,这个方法确实能够实现定时反复执行的功能,clearttimeout这是清理或者是暂停轮回执行的情况.可是发现clearttim ...
- 【Java EE 学习 21 下】【使用java实现邮件发送、邮件验证】
一.邮件发送 1.邮件发送使用SMTP协议或者IMAP协议,这里使用SMTP协议演示. SMTP协议使用的端口号:25 rfc821详细记载了该协议的相关信息 (1)使用telnet发送邮件(使用12 ...
- C与C++之间相互调用
1.导出C函数以用于C或C++的项目 如果使用C语言编写的DLL,希望从中导出函数给C或C++的模块访问,则应使用 __cplusplus 预处理器宏确定正在编译的语言.如果是从C++语言模块使用,则 ...
- 对服务器的ftp端口进行修改
对服务器的ftp端口进行了修改,把21端口改了,比如221端口,就这样用221连接的时候,连接登录成功,但打不开目录,为何,总结如下: 1.完成一个FTP的传输过程不仅仅只需要21一个端口,而是2个端 ...
- js setTimeout运用
js setTimeout运用 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "ht ...
- 6-04使用SQL语句更新数据
修改数据语法: UPDATTE 表名 SET 列名 =更新值 WHERE 更新条件 1:省略WHERE条件的更新: 更新性别: UPDATE UserInfo SET Gender=1 三行受影响. ...