手机版
你好,游客 登录 注册
背景:
阅读新闻

TCP/IP详解2 学习笔记2---ifnet ifaddr

[日期:2014-11-11] 来源:Linux社区  作者: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

本文永久更新链接地址http://www.linuxidc.com/Linux/2014-11/109289.htm

linux
相关资讯       TCP/IP 
本文评论   查看全部评论 (0)
表情: 表情 姓名: 字数

       

评论声明
  • 尊重网上道德,遵守中华人民共和国的各项有关法律法规
  • 承担一切因您的行为而直接或间接导致的民事或刑事法律责任
  • 本站管理人员有权保留或删除其管辖留言中的任意内容
  • 本站有权在网站内转载或引用您的评论
  • 参与本评论即表明您已经阅读并接受上述条款