TCP/IP详解2 学习笔记2---ifnet ifaddr
2013-01-23 15:04
716 查看
linux下用netdevice来描述一个接口,而BSD则用ifnet,包括接口的属性,硬件信息,统计信息,函数指针,输出队列
/*
* Structure describing information about an interface
* which may be of interest to management entities.
*/
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 */
int if_pcount;/* number of promiscuous listeners */
caddr_t
if_bpf; /* packet filter structure */
唯一的表示这个接口
u_short
if_index; /* numeric abbreviation for this if */
区分相同驱动的接口
short
if_unit; /* sub-unit for lower level driver */
short
if_timer; /* time 'til if_watchdog called */
#define IFF_UP0x1
/* interface is up */
#define IFF_BROADCAST0x2
/* broadcast address valid */
#define IFF_DEBUG0x4
/* turn on debugging */
#define IFF_LOOPBACK0x8
/* is a loopback net */
#define IFF_POINTOPOINT0x10
/* interface is point-to-point link */
#define IFF_NOTRAILERS0x20
/* avoid use of trailers */
#define IFF_RUNNING0x40
/* resources allocated */
#define IFF_NOARP0x80
/* no address resolution protocol */
#define IFF_PROMISC0x100
/* receive all packets */
#define IFF_ALLMULTI0x200
/* receive all multicast packets */
#define IFF_OACTIVE0x400
/* transmission in progress */
#define IFF_SIMPLEX0x800
/* can't hear own transmissions */
#define IFF_LINK00x1000
/* per link layer defined bit */
#define IFF_LINK10x2000
/* per link layer defined bit */
#define IFF_LINK20x4000
/* per link layer defined bit */
#define IFF_MULTICAST0x8000
/* supports multicast */
short
if_flags; /* up/down, broadcast, etc. */
struct
if_data {
/* generic interface information */
u_char
ifi_type; /* ethernet, tokenring, etc */
u_char
ifi_addrlen; /* media address length */
u_char
ifi_hdrlen; /* media header length */
u_long
ifi_mtu; /* maximum transmission unit */
u_long
ifi_metric; /* routing metric (external only) */
u_long
ifi_baudrate; /* linespeed */
/* volatile statistics */
u_long
ifi_ipackets; /* packets received on interface */
u_long
ifi_ierrors; /* input errors on interface */
u_long
ifi_opackets; /* packets sent on interface */
u_long
ifi_oerrors; /* output errors on interface */
u_long
ifi_collisions; /* collisions on csma interfaces */
u_long
ifi_ibytes; /* total number of octets received */
u_long
ifi_obytes; /* total number of octets sent */
u_long
ifi_imcasts; /* packets received via multicast */
u_long
ifi_omcasts; /* packets sent via multicast */
u_long
ifi_iqdrops; /* dropped on input, this interface */
u_long
ifi_noproto; /* destined for unsupported protocol */
struct
timeval ifi_lastchange;/* last updated */
}
if_data;
/* procedure handles */
驱动函数的挂载点
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 */
__P((struct ifnet *, int, caddr_t));
int
(*if_reset)
__P((int));/* new autoconfig will permit removal */
int
(*if_watchdog) /* timer routine */
__P((int));
输出队列结构,很简洁
struct
ifqueue {
struct
mbuf *ifq_head;
struct
mbuf *ifq_tail;
int
ifq_len;
int
ifq_maxlen;
int
ifq_drops;
} if_snd;/* output queue */
};
对输出队列的操作函数,simple and beauty
/*
* Output queues (ifp->if_snd) and internetwork datagram level (pup level 1)
* input routines have queues of messages stored on ifqueue structures
* (defined above). Entries are added to and deleted from these structures
* by these macros, which should be called with ipl raised to splimp().
*/
#define IF_QFULL(ifq)((ifq)->ifq_len >= (ifq)->ifq_maxlen)
#define IF_DROP(ifq)((ifq)->ifq_drops++)
#define IF_ENQUEUE(ifq, m) {
(m)->m_nextpkt = 0;
if ((ifq)->ifq_tail == 0)
(ifq)->ifq_head = m;
else
(ifq)->ifq_tail->m_nextpkt = m;
(ifq)->ifq_tail = m;
(ifq)->ifq_len++;
}
#define IF_PREPEND(ifq, m) {
(m)->m_nextpkt = (ifq)->ifq_head;
if ((ifq)->ifq_tail == 0)
(ifq)->ifq_tail = (m);
(ifq)->ifq_head = (m);
(ifq)->ifq_len++;
}
#define IF_DEQUEUE(ifq, m) {
(m) = (ifq)->ifq_head;
if (m) {
if (((ifq)->ifq_head = (m)->m_nextpkt) == 0)
(ifq)->ifq_tail = 0;
(m)->m_nextpkt = 0;
(ifq)->ifq_len--;
}
}
/*
* The ifaddr structure contains information about one address
* of an interface. They are maintained by the different address families,
* are allocated and attached when an address is set, and are linked
* together so all addresses for an interface can be located.
*/
struct ifaddr {
structsockaddr *ifa_addr;/*
address of interface */
struct
sockaddr *ifa_dstaddr; /* other end of p-to-p link */
#define ifa_broadaddrifa_dstaddr
/* broadcast address interface */
structsockaddr *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
};
以loop设备为例,其初始化函数为loopattach,相当于linux下的probe函数。
81 loopattach(n)
82 int n;
83 {
有专用的ifnet,其他的设备需要申请,并初始化
84 register struct ifnet *ifp = &loif;
85
86 #ifdef lint
87 n = n; /* Highlander: there can only be one... */
88 #endif
89 ifp->if_name = "lo";
90 ifp->if_mtu = LOMTU;
91 ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST;
92 ifp->if_ioctl = loioctl;
93 ifp->if_output = looutput;
94 ifp->if_type = IFT_LOOP;
95 ifp->if_hdrlen = 0;
96 ifp->if_addrlen = 0;
注册给内核,相当于register_netdevice
97 if_attach(ifp);
98 #if NBPFILTER > 0
分组过滤相关,按下不表
99 bpfattach(&ifp->if_bpf, ifp, DLT_NULL, sizeof(u_int));
100 #endif
101 }
if_attach主要就是把ifp放到一个链表里,初始化后 找到组织了
void
if_attach(ifp)
struct ifnet *ifp;
{
unsigned socksize, ifasize;
int namelen, unitlen, masklen, ether_output();
char workbuf[12], *unitname;
全局的一个结构
register struct ifnet **p = &ifnet;
register struct sockaddr_dl *sdl;
register struct ifaddr *ifa;
static int if_indexlim = 8;
extern void link_rtrequest();
这个循环很有意思,看了半天才明白
p指向的是ifnet结构中的一个成员,这个成员是ifnet*,*P指向下一个结构。所以*P==NULL,说明P所指的成员所在的结构是最后一个ifnet,所以可以直接对*P,既ifnet->if_next赋值。
while (*p)
p = &((*p)->if_next);
*p = ifp;
增加全区的if_index,如果有接口删除了,占用的if_index也不能用了
ifp->if_index = ++if_index;
动态的扩充ifnet_addr的大小,方法不错
if (ifnet_addrs == 0 || if_index >= if_indexlim) {
unsigned n = (if_indexlim <<= 1) * sizeof(ifa);
struct ifaddr **q = (struct ifaddr **)
malloc(n, M_IFADDR, M_WAITOK);
if (ifnet_addrs) {
bcopy((caddr_t)ifnet_addrs, (caddr_t)q, n/2);
free((caddr_t)ifnet_addrs, M_IFADDR);
}
ifnet_addrs = q;
}
/*
* create a Link Level name for this device
*/
这个函数也很有意思,很有意思
把ifp->if_unit转换成字符串,相当于itoa()....
unitname = sprint_d((u_int)ifp->if_unit, workbuf, sizeof(workbuf));
namelen = strlen(ifp->if_name);
unitlen = strlen(unitname);
#define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m))
masklen = _offsetof(struct sockaddr_dl, sdl_data[0]) +
unitlen + namelen;
比较抽象,看看书上那个图就明白内存布局了。
从前往后是name,unit,mask,分别由namelen,unitlen,masklen标识内存的长度
socksize = masklen + ifp->if_addrlen;
#define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1)))
socksize = ROUNDUP(socksize);
if (socksize < sizeof(*sdl))
socksize = sizeof(*sdl);
ifasize = sizeof(*ifa) + 2 * socksize;
这代码我是看的很晕,没细看,看71页的图就理解了
if (ifa = (struct ifaddr *)malloc(ifasize, M_IFADDR, M_WAITOK)) {
bzero((caddr_t)ifa, ifasize);
第一个sockaddr_dl 表示name和uinit信息,如eth0
物理地址是在后面的ether_attach中附给第一个sdl的
sdl = (struct sockaddr_dl *)(ifa + 1);
sdl->sdl_len = socksize;
sdl->sdl_family = AF_LINK;
bcopy(ifp->if_name, sdl->sdl_data, namelen);
bcopy(unitname, namelen + (caddr_t)sdl->sdl_data, unitlen);
sdl->sdl_nlen = (namelen += unitlen);
sdl->sdl_index = ifp->if_index;
sdl->sdl_type = ifp->if_type;
ifnet_addrs[if_index - 1] = ifa;
ifa->ifa_ifp = ifp;
ifa->ifa_next = ifp->if_addrlist;
ifa->ifa_rtrequest = link_rtrequest;
ifp->if_addrlist = ifa;
ifa->ifa_addr = (struct sockaddr *)sdl;
第2个sdl,表示netmask信息
sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl);
ifa->ifa_netmask = (struct sockaddr *)sdl;
sdl->sdl_len = masklen;
while (namelen != 0)
sdl->sdl_data[--namelen] = 0xff;
}
/* XXX -- Temporary fix before changing 10 ethernet drivers */
if (ifp->if_output == ether_output)
ether_ifattach(ifp);
}
至此,over
转自:http://blog.chinaunix.net/uid-22832715-id-292763.html
/*
* Structure describing information about an interface
* which may be of interest to management entities.
*/
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 */
int if_pcount;/* number of promiscuous listeners */
caddr_t
if_bpf; /* packet filter structure */
唯一的表示这个接口
u_short
if_index; /* numeric abbreviation for this if */
区分相同驱动的接口
short
if_unit; /* sub-unit for lower level driver */
short
if_timer; /* time 'til if_watchdog called */
#define IFF_UP0x1
/* interface is up */
#define IFF_BROADCAST0x2
/* broadcast address valid */
#define IFF_DEBUG0x4
/* turn on debugging */
#define IFF_LOOPBACK0x8
/* is a loopback net */
#define IFF_POINTOPOINT0x10
/* interface is point-to-point link */
#define IFF_NOTRAILERS0x20
/* avoid use of trailers */
#define IFF_RUNNING0x40
/* resources allocated */
#define IFF_NOARP0x80
/* no address resolution protocol */
#define IFF_PROMISC0x100
/* receive all packets */
#define IFF_ALLMULTI0x200
/* receive all multicast packets */
#define IFF_OACTIVE0x400
/* transmission in progress */
#define IFF_SIMPLEX0x800
/* can't hear own transmissions */
#define IFF_LINK00x1000
/* per link layer defined bit */
#define IFF_LINK10x2000
/* per link layer defined bit */
#define IFF_LINK20x4000
/* per link layer defined bit */
#define IFF_MULTICAST0x8000
/* supports multicast */
short
if_flags; /* up/down, broadcast, etc. */
struct
if_data {
/* generic interface information */
u_char
ifi_type; /* ethernet, tokenring, etc */
u_char
ifi_addrlen; /* media address length */
u_char
ifi_hdrlen; /* media header length */
u_long
ifi_mtu; /* maximum transmission unit */
u_long
ifi_metric; /* routing metric (external only) */
u_long
ifi_baudrate; /* linespeed */
/* volatile statistics */
u_long
ifi_ipackets; /* packets received on interface */
u_long
ifi_ierrors; /* input errors on interface */
u_long
ifi_opackets; /* packets sent on interface */
u_long
ifi_oerrors; /* output errors on interface */
u_long
ifi_collisions; /* collisions on csma interfaces */
u_long
ifi_ibytes; /* total number of octets received */
u_long
ifi_obytes; /* total number of octets sent */
u_long
ifi_imcasts; /* packets received via multicast */
u_long
ifi_omcasts; /* packets sent via multicast */
u_long
ifi_iqdrops; /* dropped on input, this interface */
u_long
ifi_noproto; /* destined for unsupported protocol */
struct
timeval ifi_lastchange;/* last updated */
}
if_data;
/* procedure handles */
驱动函数的挂载点
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 */
__P((struct ifnet *, int, caddr_t));
int
(*if_reset)
__P((int));/* new autoconfig will permit removal */
int
(*if_watchdog) /* timer routine */
__P((int));
输出队列结构,很简洁
struct
ifqueue {
struct
mbuf *ifq_head;
struct
mbuf *ifq_tail;
int
ifq_len;
int
ifq_maxlen;
int
ifq_drops;
} if_snd;/* output queue */
};
对输出队列的操作函数,simple and beauty
/*
* Output queues (ifp->if_snd) and internetwork datagram level (pup level 1)
* input routines have queues of messages stored on ifqueue structures
* (defined above). Entries are added to and deleted from these structures
* by these macros, which should be called with ipl raised to splimp().
*/
#define IF_QFULL(ifq)((ifq)->ifq_len >= (ifq)->ifq_maxlen)
#define IF_DROP(ifq)((ifq)->ifq_drops++)
#define IF_ENQUEUE(ifq, m) {
(m)->m_nextpkt = 0;
if ((ifq)->ifq_tail == 0)
(ifq)->ifq_head = m;
else
(ifq)->ifq_tail->m_nextpkt = m;
(ifq)->ifq_tail = m;
(ifq)->ifq_len++;
}
#define IF_PREPEND(ifq, m) {
(m)->m_nextpkt = (ifq)->ifq_head;
if ((ifq)->ifq_tail == 0)
(ifq)->ifq_tail = (m);
(ifq)->ifq_head = (m);
(ifq)->ifq_len++;
}
#define IF_DEQUEUE(ifq, m) {
(m) = (ifq)->ifq_head;
if (m) {
if (((ifq)->ifq_head = (m)->m_nextpkt) == 0)
(ifq)->ifq_tail = 0;
(m)->m_nextpkt = 0;
(ifq)->ifq_len--;
}
}
/*
* The ifaddr structure contains information about one address
* of an interface. They are maintained by the different address families,
* are allocated and attached when an address is set, and are linked
* together so all addresses for an interface can be located.
*/
struct ifaddr {
structsockaddr *ifa_addr;/*
address of interface */
struct
sockaddr *ifa_dstaddr; /* other end of p-to-p link */
#define ifa_broadaddrifa_dstaddr
/* broadcast address interface */
structsockaddr *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
};
以loop设备为例,其初始化函数为loopattach,相当于linux下的probe函数。
81 loopattach(n)
82 int n;
83 {
有专用的ifnet,其他的设备需要申请,并初始化
84 register struct ifnet *ifp = &loif;
85
86 #ifdef lint
87 n = n; /* Highlander: there can only be one... */
88 #endif
89 ifp->if_name = "lo";
90 ifp->if_mtu = LOMTU;
91 ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST;
92 ifp->if_ioctl = loioctl;
93 ifp->if_output = looutput;
94 ifp->if_type = IFT_LOOP;
95 ifp->if_hdrlen = 0;
96 ifp->if_addrlen = 0;
注册给内核,相当于register_netdevice
97 if_attach(ifp);
98 #if NBPFILTER > 0
分组过滤相关,按下不表
99 bpfattach(&ifp->if_bpf, ifp, DLT_NULL, sizeof(u_int));
100 #endif
101 }
if_attach主要就是把ifp放到一个链表里,初始化后 找到组织了
void
if_attach(ifp)
struct ifnet *ifp;
{
unsigned socksize, ifasize;
int namelen, unitlen, masklen, ether_output();
char workbuf[12], *unitname;
全局的一个结构
register struct ifnet **p = &ifnet;
register struct sockaddr_dl *sdl;
register struct ifaddr *ifa;
static int if_indexlim = 8;
extern void link_rtrequest();
这个循环很有意思,看了半天才明白
p指向的是ifnet结构中的一个成员,这个成员是ifnet*,*P指向下一个结构。所以*P==NULL,说明P所指的成员所在的结构是最后一个ifnet,所以可以直接对*P,既ifnet->if_next赋值。
while (*p)
p = &((*p)->if_next);
*p = ifp;
增加全区的if_index,如果有接口删除了,占用的if_index也不能用了
ifp->if_index = ++if_index;
动态的扩充ifnet_addr的大小,方法不错
if (ifnet_addrs == 0 || if_index >= if_indexlim) {
unsigned n = (if_indexlim <<= 1) * sizeof(ifa);
struct ifaddr **q = (struct ifaddr **)
malloc(n, M_IFADDR, M_WAITOK);
if (ifnet_addrs) {
bcopy((caddr_t)ifnet_addrs, (caddr_t)q, n/2);
free((caddr_t)ifnet_addrs, M_IFADDR);
}
ifnet_addrs = q;
}
/*
* create a Link Level name for this device
*/
这个函数也很有意思,很有意思
把ifp->if_unit转换成字符串,相当于itoa()....
unitname = sprint_d((u_int)ifp->if_unit, workbuf, sizeof(workbuf));
namelen = strlen(ifp->if_name);
unitlen = strlen(unitname);
#define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m))
masklen = _offsetof(struct sockaddr_dl, sdl_data[0]) +
unitlen + namelen;
比较抽象,看看书上那个图就明白内存布局了。
从前往后是name,unit,mask,分别由namelen,unitlen,masklen标识内存的长度
socksize = masklen + ifp->if_addrlen;
#define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1)))
socksize = ROUNDUP(socksize);
if (socksize < sizeof(*sdl))
socksize = sizeof(*sdl);
ifasize = sizeof(*ifa) + 2 * socksize;
这代码我是看的很晕,没细看,看71页的图就理解了
if (ifa = (struct ifaddr *)malloc(ifasize, M_IFADDR, M_WAITOK)) {
bzero((caddr_t)ifa, ifasize);
第一个sockaddr_dl 表示name和uinit信息,如eth0
物理地址是在后面的ether_attach中附给第一个sdl的
sdl = (struct sockaddr_dl *)(ifa + 1);
sdl->sdl_len = socksize;
sdl->sdl_family = AF_LINK;
bcopy(ifp->if_name, sdl->sdl_data, namelen);
bcopy(unitname, namelen + (caddr_t)sdl->sdl_data, unitlen);
sdl->sdl_nlen = (namelen += unitlen);
sdl->sdl_index = ifp->if_index;
sdl->sdl_type = ifp->if_type;
ifnet_addrs[if_index - 1] = ifa;
ifa->ifa_ifp = ifp;
ifa->ifa_next = ifp->if_addrlist;
ifa->ifa_rtrequest = link_rtrequest;
ifp->if_addrlist = ifa;
ifa->ifa_addr = (struct sockaddr *)sdl;
第2个sdl,表示netmask信息
sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl);
ifa->ifa_netmask = (struct sockaddr *)sdl;
sdl->sdl_len = masklen;
while (namelen != 0)
sdl->sdl_data[--namelen] = 0xff;
}
/* XXX -- Temporary fix before changing 10 ethernet drivers */
if (ifp->if_output == ether_output)
ether_ifattach(ifp);
}
至此,over
转自:http://blog.chinaunix.net/uid-22832715-id-292763.html
相关文章推荐
- TCP/IP详解2 学习笔记2---ifnet ifaddr
- TCP/IP详解2 学习笔记2---ifnet ifaddr
- TCP/IP详解2 学习笔记2---ifnet ifaddr
- TCP/IP详解--学习笔记(9)-TCP协议概述
- TCP/IP详解--学习笔记(9)-TCP协议概述
- TCP/IP详解2 学习笔记---mbuf
- TCP/IP详解2 学习笔记---mbuf
- 【学习笔记:0】TCP-IP详解卷一:协议
- TCP,IP详解,卷一:协议学习笔记之第三章IP:网际协议
- TCP-IP协议详解学习笔记-- IP
- TCP,IP详解,卷一:协议学习笔记之第六章 ICMP: Internet控制报文协议
- 《TCP-IP详解 卷2:实现》学习笔记—mbuf的深入解析
- TCP/IP 详解卷一学习笔记(四):TCP 连接建立与终止
- 《TCP-IP详解 卷2:实现》学习笔记—mbuf(存储器缓存)的结构
- 《TCP-IP详解 卷2:实现》学习笔记—接口层分析
- TCP,IP详解,卷一:协议学习笔记之第一章概述
- TCP,IP详解,卷一:协议学习笔记之第十七章 TCP:传输控制协议
- TCP/IP 详解 学习笔记2
- TCP/IP 详解卷一学习笔记(一):TCP/IP 协议基本概念
- TCP/IP 详解卷一学习笔记(二):网络层 IP