《TCP-IP详解 卷2:实现》学习笔记—接口层分析

来源:互联网 发布:淘宝店铺怎么发微淘 编辑:程序博客网 时间:2024/06/03 18:53

所谓接口,就是指在一个特定网络上硬件与设备驱动器之间的接口BSD设计将网络协议和连接到一个系统的网络设备的驱动器间提供一个与硬件无关的编程接口。

1、ifnet结构

结构ifnet中包含所有接口的通用信息。在系统初始化期间,分别为每个网络设备分配一个独立的ifnet结构。每个ifnet结构有一个列表,它包含这个设备的一个或多个协议地址。函数if_attach在系统初始化期间构造这个链表。if_addrlist指向这个接口的ifaddr结构列表。每个ifaddr结构存储一个要用这个接口通信的协议的地址信息

结构ifnet比较大,我们分为部分来说明:

Ø 实现信息

Ø 硬件信息

Ø 接口统计

Ø 函数指针

Ø 输出队列

struct ifnet {/*实现信息*/char*if_name;/* name, e.g. ``en'' or ``lo'' *//* 字符串,标识接口的类型 */structifnet *if_next;/* all struct ifnets are chained *//* 把所有接口的ifnet结构/*链接成一个链表,if_attach在系统初始化期间构造这个链表 */Struct  ifaddr *if_addrlist;/* linked list of addresses per if *//* 指向这个接口的ifaddr结构列表 */intif_pcount;/* number of promiscuous listeners *//* 监听者的数目 */caddr_tif_bpf;/* packet filter structure */ /* 分组过滤器结构 */u_shortif_index;/* numeric abbreviation for this if *//* 在内核中唯一地标识这个接口  */shortif_unit;/* sub-unit for lower level driver */ /* 标识多个相同类型的实例 */shortif_timer;/* time 'til if_watchdog called */ /* 以秒为单位记录时间,直到内核为此接口调用函数if_watchdog为止 */Short  if_flags;/* up/down, broadcast, etc. */ /* 接口的操作状态和属性,譬如接口正在工作和用于广播 */structif_data {/*硬件信息*/u_charifi_type;/* ethernet, tokenring, etc *//* 指明接口支持的硬件地址类型,如以太网,令牌环 */u_charifi_addrlen;/* media address length *//* 数据链路地址的长度 */u_charifi_hdrlen;/* media header length */ /* 由硬件附加给任何分组的首部的长度 */u_longifi_mtu;/* maximum transmission unit *//* 接口在一次输出操作中能传输的最大数据单元的字节数,如以太网是1500 */u_longifi_metric;/* routing metric (external only) *//* routing metric,通常为0 */u_longifi_baudrate;/* linespeed *//* 指定接口的传输速率 */只有SLIP接口才设置它对于ifi_addrlen和ifi_hdrlen,例如,以太网有一个长度为6字节的地址和一个长度为14字节的首部。 /* 接口统计 */u_longifi_ipackets;/* packets received on interface */u_longifi_ierrors;/* input errors on interface */u_longifi_opackets;/* packets sent on interface */u_longifi_oerrors;/* output errors on interface */u_longifi_collisions;/* collisions on csma interfaces */u_longifi_ibytes;/* total number of octets received */u_longifi_obytes;/* total number of octets sent */u_longifi_imcasts;/* packets received via multicast */u_longifi_omcasts;/* packets sent via multicast */u_longifi_iqdrops;/* dropped on input, this interface */仅被SLIP设备驱动访问u_longifi_noproto;/* destined for unsupported protocol */structtimeval ifi_lastchange;/* last updated */记录任何统计改变的最近时间}if_data;/* 函数指针,在系统初始化时,每个设备驱动程序初始化它自己的ifnet结构 */int(*if_init)/* init routine */初始化接口__P((int));int(*if_output)/* output routine (enqueue) */对要传输的输出分组进行排队__P((struct ifnet *, struct mbuf *, struct sockaddr *,struct rtentry *));int(*if_start)/* initiate output routine */启动分组的传输__P((struct ifnet *));int(*if_done)/* output complete routine */传输完成后的清除(未用)__P((struct ifnet *));/* (XXX not used; fake prototype) */int(*if_ioctl)/* ioctl routine */处理I/O控制命令__P((struct ifnet *, u_long, caddr_t));int(*if_reset)  /*复位接口设备*/__P((int));/* new autoconfig will permit removal */int(*if_watchdog)/* timer routine */周期性接口例程__P((int));/* 输出队列 */structifqueue {structmbuf *ifq_head;/*指向队列的第一个分组(下一个要输出的分组)*/structmbuf *ifq_tail;/*指向队列最后一个分组*/intifq_len;/*当前队列中分组的数目*/intifq_maxlen;/*队列中允许的缓存最大个数*/intifq_drops;/*统计因为队列满而丢弃的分组数*/} if_snd;/* output queue */};


2、ifaddr结构

下面我们要看的下一个结构式接口地址结构,ifaddr,每个接口维护一个ifaddr结构的链表,因为一些数据链路,如以太网,支持多于一个的协议。一个单独的ifaddr结构描述每个分配给接口的地址,通常每个协议一个地址。支持多地址的另一个原因是很多协议,包括TCP/IP,支持为单个物理接口指派多个地址。虽然Net/3支持这个特性,但很多TCP/IP实现并不支持。

struct ifaddr {structsockaddr *ifa_addr;/* address of interface */指向接口的一个协议地址structsockaddr *ifa_dstaddr;/* other end of p-to-p link */指向一个点对点链路上的另一端的接口协议地址或指向一个广播网中分配给接口的广播地址(如以太网)#defineifa_broadaddrifa_dstaddr/* broadcast address interface */structsockaddr *ifa_netmask;/* used to determine subnet */指向一个位掩码,地址中表示网络部分的比特在掩码中被设置为1,地址中表示主机的部分被设置为0structifnet *ifa_ifp;/* back-pointer to interface */指回接口的ifnet结构的指针structifaddr *ifa_next;/* next address for interface */接口的下一个地址void(*ifa_rtrequest)();/* check or clean routes (+ or -)'d */支持接口的路由查找u_shortifa_flags;/* mostly rt_flags for cloning */支持接口的路由查找shortifa_refcnt;/* extra to malloc for link info */统计对结构ifaddr的引用,宏IFAFREE仅在引用计数将到0时才释放这个结构,结构ifaddr使用引用计数是因为接口和路由数据结构共享这个结构intifa_metric;/* cost of going out this interface */支持接口的路由查找#ifdef notdefstructrtentry *ifa_rt;/* XXXX for ROUTETOIF ????? */#endif};

 

3、sockaddr结构

一个接口的编码信息不仅仅只包括一个主机地址。Net/3在通用的sockaddr结构中维护主机地址、广播地址和网络掩码。通过使用一个通用的结构,将硬件与协议专用的地址细节相对于接口层隐藏起来。

如下,早期BSD版的定义——结构osockaddr

struct osockaddr {u_shortsa_family;/* address family *//* 地址族,如AF_INET */charsa_data[14];/* up to 14 bytes of direct address */ /* 具体地址数组 */};struct sockaddr {    u_char    sa_len;            /* sockaddr的长度 */    u_char    sa_family;        /* 地址族,如AF_INET */    char    sa_data[14];        /* 具体地址数组 */};


sa_family

协议

AF_INET

Internet

AF_ISO,AF_OSI

OSI

AF_UNIX

Unix

AF_ROUTE

路由表

AF_LINK

数据链路

AF_UNSPEC

 

             SA_FAMILY 常量

4、ifnet和ifaddr的专用化

结构ifnet和ifaddr包含适用于所有网络接口和协议地址的通用信息。为了容纳其他设备和协议专用信息,每个设备定义了并且每个协议分配了一个专用化版本的ifnet和ifaddr结构。这些专用化的结构总是包含一个ifnet或ifaddr结构作为它们的第一个成员,这样无须考虑其他专用信息就能访问这些公共信息。

多数设备驱动程序通过分配一个专用化的ifnet结构的数组来处理同一类型的多个接口,但其他设备(例如环回设备)仅处理一个接口。如下图是我们的例子接口的专用化ifnet结构的组织。

内核通过分配一个ifaddr结构和两个sockaddr_dl结构(一个是链路层地址本身,一个是地址掩码)来构造一个链路层地址。上图显示的是一个带有一个链路层地址、一个internet地址和一个OSI地址的以太网接口。

5、网络初始化概述

网络初始函数从main开始显示:

70-96 cpu_startup 查找并初始化所有连接到系统的硬件设备,包括任何网络接口

97-174 在内核初始化硬件设备后,它调用包含在pdevinit数组中的每个pdev_attach函数

175-234  ifinit和domaininit完成网络接口和协议的初始化,并且scheduler开始内核进程调度。

有些设备,例如SLIP和环回接口,完全用软件来实现。这些伪设备用存储在全局pdevinit数组中的一个pdevinit结构来表示。在内核配置期间构造这个数组。如上所示:

120-123 对于SLIP和环回接口,在结构pdevinit中,pdev_attach分别被设置为slattach和loopattach。当调用这个attach函数时,pedev_count作为传递的唯一参数,它指定创建的设备个数。只有一个环回设备被创建,但如果管理员适当配置SLIP项可能有多个SLIP设备被创建。

6、以太网、SLIP、环回初始化

以太网初始化:

作为cpu_startup的一部分,内核查找任何连接的网络设备。一旦一个设备被识别,一个设备专用的初始化函数就被调用。如下图是要讨论的3个例子接口的初始化函数。

设备

初始化函数

LANCE以太网

Leattach

SLIP

Slattach

环回

Loopattach

每个设备驱动程序为一个网络接口初始化一个专用化的ifnet结构,并调用if_attach把这个结构插入到接口链表中。如下图的结构le_softc是我们的例子以太网驱动程序的专用化ifnet结构

(1)le_softc结构:

69-95 在if_le.c中声明了一个le_softc结构(有NLE成员)的数组。每个结构的第一个成员是sc_ac,一个arpcom结构,它对于所有以太网接口都是通用的,接下来是设备专用成员。宏sc_if和sc_addr简化了对结构ifnet及存储在结构arpcom(sc_ac)中的以太网地址的访问,如下图所示。

(2)arpcom 结构:

95-101结构arpcom的第一个成员ac_if是一个ifnet结构,如上图所示。ac_enaddr是以太网硬件地址,它是在cpu_startup期间内核检测设备时由LANCE设备驱动程序从硬件上复制的。对于我们的例子驱动程序,这发生在函数leattach中(如下图)。ac_ipaddr是上一个分配给此设备的IP地址。ac_multiaddrs是一个用结构ether_multi表示的以太网多播地址的列表。ac_multicnt统计这个列表的项数。

下图所示的是LANCE以太网驱动程序的初始化代码。

106-115 内核在系统中每发现一个LANCE卡都调用一次leattach。

Le指向此卡的专用化ifnet结构(4、ifnet和ifaddr专用化的第一个图),ifp指向这个结构的第一个 sc_if,一个通用的ifnet结构。

(3)从设备复制硬件地址

126-137对于LANCE设备,由厂商指派的以太网地址在这个循环中以每次半个字节(4bit)从设备复制到sc_addr.

(4)初始化ifnet结构

150-157leattach从hp_device结构把设备单元号复制到if_unit来标识同类型的多个接口。这个设备的if_name是“le”:if_mtu为1500字节(ETHERMTU),以太网的最大传输单元;if_inti、if_reset、if_ioctol、if_output和it_start都指向控制网络接口的通用函数的设备专用实现。

158 所有的以太网设备都支持IFF_BROADCAST。LANCE设备不接收它自己发送的数据,因此被设置为IFF_SIMPLEX。支持多播的设备和硬件还要设置IFF_MULTICAST。

159-162 bpfattach登记有BPF的接口。函数if_attach把初始化了的ifnet结构插入到接口的链表中。

 

 

 

原创粉丝点击