分类: BSD
2011-05-24 17:30:00
在系统初始化期间,分别为每个网络设备分配一个独立的ifnet结构。每个ifnet结构有一个列表,它包含这个设备的一个或多个协议地址结构ifaddr。
图3-5说明了一个接口和它的地址之间的关系。
结构i f n e t比较大,我们分五个部分来说明:
• 实现信息 • 硬件信息 • 接口统计 • 函数指针 • 输出队列
// 接口的通用信息结构ifnet
struct ifnet {
char * if_name; /*
name, e.g. ``en'' or ``lo'' */
struct ifnet * if_next; /* all struct ifnets are chained */
struct ifaddr * if_addrlist; /* linked list of addresses per if */
// 实现信息
struct if_data {
// 硬件信息
// 接口统计
};
// 函数指针
struct ifqueue {
// 输出队列
};
};
// 协议地址结构ifaddr
struct ifaddr {
struct sockaddr *ifa_addr; /* address of interface */
struct sockaddr *ifa_dstaddr; /* other end of p-to-p link */
#define ifa_broadaddr ifa_dstaddr /* broadcast address interface */
struct sockaddr *ifa_netmask; /* used to determine subnet */
struct ifnet *ifa_ifp; /* back-pointer to interface */
struct ifaddr *ifa_next; /* next address for interface */
void (*ifa_rtrequest)(); /* check or clean routes (+ or -)'d */
u_short ifa_flags; /* mostly rt_flags for cloning */
short ifa_refcnt; /* extra to malloc for link info */
int ifa_metric; /* cost of going out this interface */
#ifdef notdef
struct rtentry *ifa_rt; /* XXXX for ROUTETOIF ????? */
#endif
};
==============================================================
网络初始化函数从init_main.c中的main开始:
cpu_startup查找并初始化所有连接到系统的硬件设备,包括任何网络接口。
在内核初始化硬件设备后,它调用包含在pdevinit数组(./usr.bin/config中配置, 在内核配置期间构造这个数组)中的每个pdev_attach函数。
struct pdevinit pdevinit[] = {
{ slattach, 1 },
{ loopattach, 1 },
{ 0, 0 }
};
一旦一个设备被识别,一个设备专用的初始化函数就被调用。一般来说如:
1)一个AMD7990LANCE以太网接口:leattach函数被调用
2)一个串行线IP(SLIP)接口:slattach 函数被调用
3)一个环回接口:loopattach函数被调用
每个设备驱动函数(leattach/slattach/loopattach)为一个网络接口
1. 2. 构造专用的struct le_softc , 在struct le_softc中构造以太网共用的struct arpcom ,
struct le_softc {
struct arpcom sc_ac; /* common Ethernet structures */
#define sc_if sc_ac.ac_if /* network-visible interface */
#define sc_addr sc_ac.ac_enaddr /* hardware Ethernet address */
struct lereg0 *sc_r0; /* DIO registers */
struct lereg1 *sc_r1; /* LANCE registers */
struct lereg2 *sc_r2; /* dual-port RAM */
……
}
struct arpcom {
struct ifnet ac_if; /* network-visible interface */
u_char ac_enaddr[6]; /* ethernet hardware address */
struct in_addr ac_ipaddr; /* copy of ip address- XXX */
struct ether_multi *ac_multiaddrs; /* list of ether multicast addrs */
int ac_multicnt; /* length of ac_multiaddrs list */
};
3.设备复制硬件地址到 arpcom 结构中的sc_addr( 即sc_ac.ac_enaddr )。
4. 初始化 ifnet 结构
构造完后,
bpfattach登记有BPF的接口,在图31-8中说明。
函数if_attach把初始化了的ifnet结构插入到接口的链表中(3.11节)。
在函数 if_attach 中
{
1.配置全局数组: ifnet_addrs
struct ifaddr ** ifnet_addrs;
第一次调用if_attach时,数组ifnet_addrs不存在,因此要分配16(16=8<<1)项的空间。当数组满时,一个两倍大的新数组被分配,并且老数组中的项被复制到新的数组中。
2. 创建链路层名称并计算链路层地址的长度
3. 链路层地址 sockaddr_dl{}
4. 链路层掩码 sockaddr_dl{}
5. 函数ether_ifattach执行对所有以太网设备通用的ifnet结构的初始化。
}
接口结构被初始化并链接到一起后,main(图3-23)调用ifinit,如图3-42所示。
ifinit和domaininit完成网络接口和协议的初始化,并且scheduler开始内
核进程调度。
ifinit和domaininit在第7章讨论。