歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> TCP/IP詳解2 學習筆記2---ifnet ifaddr

TCP/IP詳解2 學習筆記2---ifnet ifaddr

日期:2017/3/1 9:37:20   编辑:Linux編程

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_UP 0x1 /* interface is up */

#define IFF_BROADCAST 0x2 /* broadcast address valid */

#define IFF_DEBUG 0x4 /* turn on debugging */

#define IFF_LOOPBACK 0x8 /* is a loopback net */

#define IFF_POINTOPOINT 0x10 /* interface is point-to-point link */

#define IFF_NOTRAILERS 0x20 /* avoid use of trailers */

#define IFF_RUNNING 0x40 /* resources allocated */

#define IFF_NOARP 0x80 /* no address resolution protocol */

#define IFF_PROMISC 0x100 /* receive all packets */

#define IFF_ALLMULTI 0x200 /* receive all multicast packets */

#define IFF_OACTIVE 0x400 /* transmission in progress */

#define IFF_SIMPLEX 0x800 /* can't hear own transmissions */

#define IFF_LINK0 0x1000 /* per link layer defined bit */

#define IFF_LINK1 0x2000 /* per link layer defined bit */

#define IFF_LINK2 0x4000 /* per link layer defined bit */

#define IFF_MULTICAST 0x8000 /* 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 {

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

};


以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

TCP/IP詳解2 學習筆記---mbuf http://www.linuxidc.com/Linux/2014-11/109290.htm

Copyright © Linux教程網 All Rights Reserved