free BSD协议栈源码分析----domain和protosw
写在开头
最近在学习freeBSD4.4 协议栈的代码,也就是TCP/IP详解中配套使用的协议栈版本,开这篇博客,也是对自己学习过程的一个输出总结。
domaininit初始化
整个tcp/ip协议栈的初始化是在domaininit函数内,每种协议族都已一个domain结构,如unix域协议,tcp/ip协议等。
tcp/ip协议栈的一些信息是在inetdomain结构中声明:
先看下domain结构体:
struct domain {
int dom_family; /* AF_xxx */ :域类型,一般是AF开头,如AF_INET
char *dom_name;//域名称,如 internet
void (*dom_init) /* 域初始化函数 */
__P((void));
int (*dom_externalize) /* externalize access rights */
__P((struct mbuf *));
int (*dom_dispose) /* dispose of internalized rights */
__P((struct mbuf *));
struct protosw *dom_protosw, *dom_protoswNPROTOSW;//具体的域协议信息,域协议结构体的结尾
struct domain *dom_next;/*用来连接下一个domain结构*/
int (*dom_rtattach) /* initialize routing table */
__P((void **, int));
int dom_rtoffset; /* an arg to rtattach, in bits */
int dom_maxrtkey; /* for routing layer */
};
domaininit初始化(部分次要代码已略去):
domaininit()
{
register struct domain *dp;
register struct protosw *pr;
ADDDOMAIN(unix);//将unixdomain挂载到domains上
ADDDOMAIN(route);//将routedomain挂载到domains上
ADDDOMAIN(inet);//将inetdomain挂载到domains上,也就是tcp/ip协议的domain结构
/*这里开始调用相应的domain结构中的初始化接口*/
for (dp = domains; dp; dp = dp->dom_next) {
if (dp->dom_init)
(*dp->dom_init)();
for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)/*这里开始调用inetsw中的协议初始化接口*/
if (pr->pr_init)
(*pr->pr_init)();
}
if (max_linkhdr < 16) /* 链路层首部长度不能小于16 */
max_linkhdr = 16;
max_hdr = max_linkhdr + max_protohdr;
max_datalen = MHLEN - max_hdr;
timeout(pffasttimo, (void *)0, 1);//启动定时器,调用protosw中的pffasttimo
timeout(pfslowtimo, (void *)0, 1);//启动定时器,调用protosw中的pr_slowtimo
}
/*ADDDOMAIN这个宏的作用,就是把每个domain挂载到domains指针上,
利用dom_next将所有domain结构连接起来形成一个链表结构,最后整个domains指向这个链表的第一个成员*/
#define ADDDOMAIN(x) { \
extern struct domain __CONCAT(x,domain); \
__CONCAT(x,domain.dom_next) = domains; \
domains = &__CONCAT(x,domain); \
}
protosw结构定义
每一种协议族都有相应的protosw结构,
struct protosw {
short pr_type; /* socket的类型*/
struct domain *pr_domain; /* domain protocol a member of */
short pr_protocol; /* protocol number */
short pr_flags; /* see below */
/* protocol-protocol hooks */
void (*pr_input)(); /* input to protocol (from below) */
int (*pr_output)(); /* output to protocol (from above) */
void (*pr_ctlinput)(); /* control input (from below) */
int (*pr_ctloutput)(); /* control output (from above) */
/* user-protocol hook */
int (*pr_usrreq)(); /* user request: see list below */
/* utility hooks */
void (*pr_init)(); /* initialization hook */
void (*pr_fasttimo)(); /* fast timeout (200ms) */
void (*pr_slowtimo)(); /* slow timeout (500ms) */
void (*pr_drain)(); /* flush any excess space possible */
int (*pr_sysctl)(); /* sysctl for protocol */
};
inetsw --internet的protosw结构
struct protosw inetsw[] = {
{ 0, &inetdomain, 0, 0,
0, ip_output, 0, 0,
0,
ip_init, 0, ip_slowtimo, ip_drain, ip_sysctl
},
{ SOCK_DGRAM, &inetdomain, IPPROTO_UDP, PR_ATOMIC|PR_ADDR,
udp_input, 0, udp_ctlinput, ip_ctloutput,
udp_usrreq,
udp_init, 0, 0, 0, udp_sysctl
},
{ SOCK_STREAM, &inetdomain, IPPROTO_TCP, PR_CONNREQUIRED|PR_WANTRCVD,
tcp_input, 0, tcp_ctlinput, tcp_ctloutput,
tcp_usrreq,
tcp_init, tcp_fasttimo, tcp_slowtimo, tcp_drain,
},
{ SOCK_RAW, &inetdomain, IPPROTO_RAW, PR_ATOMIC|PR_ADDR,
rip_input, rip_output, 0, rip_ctloutput,
rip_usrreq,
0, 0, 0, 0,
},
{ SOCK_RAW, &inetdomain, IPPROTO_ICMP, PR_ATOMIC|PR_ADDR,
icmp_input, rip_output, 0, rip_ctloutput,
rip_usrreq,
0, 0, 0, 0, icmp_sysctl
},
{ SOCK_RAW, &inetdomain, IPPROTO_IGMP, PR_ATOMIC|PR_ADDR,
igmp_input, rip_output, 0, rip_ctloutput,
rip_usrreq,
igmp_init, igmp_fasttimo, 0, 0,
},
#ifdef TPIP
{ SOCK_SEQPACKET,&inetdomain, IPPROTO_TP, PR_CONNREQUIRED|PR_WANTRCVD,
tpip_input, 0, tpip_ctlinput, tp_ctloutput,
tp_usrreq,
tp_init, 0, tp_slowtimo, tp_drain,
},
#endif
/* EON (ISO CLNL over IP) */
#ifdef EON
{ SOCK_RAW, &inetdomain, IPPROTO_EON, 0,
eoninput, 0, eonctlinput, 0,
0,
eonprotoinit, 0, 0, 0,
},
#endif
#ifdef NSIP
{ SOCK_RAW, &inetdomain, IPPROTO_IDP, PR_ATOMIC|PR_ADDR,
idpip_input, rip_output, nsip_ctlinput, 0,
rip_usrreq,
0, 0, 0, 0,
},
#endif
/* raw wildcard */
{ SOCK_RAW, &inetdomain, 0, PR_ATOMIC|PR_ADDR,
rip_input, rip_output, 0, rip_ctloutput,
rip_usrreq,
rip_init, 0, 0, 0,
},
};
inetsw数组中共定义了10个成员,分别对应每种协议,如TCP,UDP,IP等,在domaininit初始化中,会分别调用每个协议的pr_init接口初始化协议。