首页 / 操作系统 / Linux / TCP/IP详解2 学习笔记2---ifnet ifaddr
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 #endif101 }
if_attach主要就是把ifp放到一个链表里,初始化后 找到组织了
voidif_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);}
至此,overTCP/IP详解2 学习笔记---mbuf http://www.linuxidc.com/Linux/2014-11/109290.htm本文永久更新链接地址:http://www.linuxidc.com/Linux/2014-11/109289.htm