• ifconfig源码分析之与内核交互数据


    《ifconfig源码分析之与内核交互数据》
    本文档的Copyleft归rosetta所有,使用GPL发布,可以自由拷贝、转载,转载时请保持文档的完整性。
    参考资料:《Linux设备驱动程序 第三版》,scull源码,Linux内核源码
    来源:http://blog.csdn.net/rosetta/article/details/7563615

        ifconifg是Linux提供的一个操作网络接口的应用层程序,虽然和设备驱动编写没什么联系,但分析它的部分核心代码有助于理解应用层和内核层交互过程。
        这也是对《字符设备驱动程序编写基础》最后提出的问题的一个解答。
        ifconifg.c文件一千多行再加上相关公共文件大概会达到二千行,只分析其与内核交互过程,其它部分有兴趣的朋友可以自行分析。

    知识点:
    * 获取ifconfig源码方法。
    * ifconfig 输出结果解释。
    * 应用层和内核层交互过程。
    * ioctl的使用。
    * 认识/proc/net/dev。

    一、获取ifconifg源码包并编译。
      [root@xxx net-tools-1.60]# type ifconfig          
      ifconfig is hashed (/sbin/ifconfig)
      [root@xxx net-tools-1.60]# rpm -qf /sbin/ifconfig 
      net-tools-1.60-78.el5
      可知ifconfig属于net-tools源码包,下载之。net-tools源码包不仅包含ifconifg,还包含常用的arp、route、netstat等工具源码。
      
      直接make,应该会有错误,按着错误提示修改下源码即可。

    二、ifconifg eth0执行结果解释
      [root@ xxx]# ./ifconfig eth0
      eth0      Link encap:Ethernet  HWaddr 00:0C:29:9a:26:37  
                inet addr:192.168.95.162  Bcast:192.168.95.255  Mask:255.255.255.0
                inet6 addr: fe80::21c:29ff:fe9b:2637/64 Scope:Link
                UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
                RX packets:2495308 errors:0 dropped:0 overruns:0 frame:0
                TX packets:2215616 errors:0 dropped:0 overruns:0 carrier:0
                collisions:0 txqueuelen:1000 
                RX bytes:998016881 (951.7 MiB)  TX bytes:886972155 (845.8 MiB)
                Interrupt:18 Base address:0x2000 
      Link encap:Ethernet   本网卡接入的网络的类型是以太网。
      HWaddr 00:0C:29:9a:26:37   本网卡的硬件地址。
      inet6 addr: fe80::21c:29ff:fe9b:2637/64 Scope:Link  ipv6地址。
      UP 网卡状态为开启。
      BROADCAST 支持广播。
      RUNNING 网卡的网线被接上。
      MULTICAST  支持多播。
      MTU:1500 IP数据包的最大长度,带IP头。
      RX表示接收数据包的情况。
      TX表示发送数据包的情况。
      如果网卡已经完成配置却还是无法与其它设备通信,那么从RX 和TX 的显示数据上可以简单地分析一下故障原因。在这种情况下,如果接收和传送的包的计数(packets)增加,那有可能是系统的IP地址出现了冲突;如果看到大量的错误(errors)和冲突(Collisions),那么这很有可能是网络的传输介质出了问题,例如网线不通或hub损坏。
      collisions: 网络讯号碰撞的情况说明
      txqueuelen: 传输缓区长度大小

    三、认识/proc/net/dev
        这里列出了所有网络设备的其属性状态和收发包情况。ifconfig会open这个设备查找匹配信息。
      [root@xxx ipsec]# cat /proc/net/dev    
      Inter-|   Receive                                                |  Transmit
       face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
          lo:   14920     167    0    0    0     0          0         0    14920     167    0    0    0     0       0          0
        eth0:104165628  231316    5    5    0     0          0         0 27195571  185064    0    0    0     0       0          0
        eth1:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
        eth2:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
        sit0:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
      ipsec0:     128       2    0    0    0     0          0         0      900       6    0    0    0     0       0          0
      ipsec1:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
      ipsec2:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
      ipsec3:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
         sn0:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
         sn1:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0

    四、分析./ifconfig eth0 源码执行流程
      前面部分是对选项的解析判断,给出函数调用过程,具体内容跳过。
      //ifconfig.c
      main()
       ->if_print()//输入参数为"eth0"
         ->lookup_interface()
         ->do_if_fetch()
           ->if_fetch()//从内核获取网卡信息,也是和内核交互的核心
           ->ife_print()//再把接收到的数据以第二步的格式打出

        int if_fetch(struct interface *ife)
      {
          struct ifreq ifr;
          int fd;
          char *ifname = ife->name;
      
          strcpy(ifr.ifr_name, ifname);
          if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0)//skfd为本地域套接字,SIOCGIFFLAGS为传给内核的cmd,ifr接收从内核返回的数据。
          return (-1);
          ife->flags = ifr.ifr_flags;
      
          strcpy(ifr.ifr_name, ifname);
          if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0)
          memset(ife->hwaddr, 0, 32);
          else
          memcpy(ife->hwaddr, ifr.ifr_hwaddr.sa_data, 8);
      
          ife->type = ifr.ifr_hwaddr.sa_family;
          
          ……  
      }

      讲到这里,我觉得就讲完了,虽然没有很高深的内容,但原本在脑海中模糊的概念已经变得清晰。

      再帖上一段内核有关ioctl处理的源码:
    int dev_ioctl(unsigned int cmd, void __user *arg)
    {
        struct ifreq ifr;
        int ret;
        char *colon;

        /* One special case: SIOCGIFCONF takes ifconf argument
           and requires shared lock, because it sleeps writing
           to user space.
         */

        if (cmd == SIOCGIFCONF) {
            rtnl_shlock();
            ret = dev_ifconf((char __user *) arg);
            rtnl_shunlock();
            return ret;
        }
        if (cmd == SIOCGIFNAME)
            return dev_ifname((struct ifreq __user *)arg);

        if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
            return -EFAULT;

        ifr.ifr_name[IFNAMSIZ-1] = 0;
        colon = strchr(ifr.ifr_name, ':');
        if (colon)
            *colon = 0;

        /*
         *  See which interface the caller is talking about.
         */

        switch (cmd) {
            /*
             *  These ioctl calls:
             *  - can be done by all.
             *  - atomic and do not require locking.
             *  - return a value
             */
            case SIOCGIFFLAGS://here case
            case SIOCGIFMETRIC:
            case SIOCGIFMTU:
            case SIOCGIFHWADDR:
            case SIOCGIFSLAVE:
            case SIOCGIFMAP:
            case SIOCGIFINDEX:
            case SIOCGIFTXQLEN:
                dev_load(ifr.ifr_name);
                read_lock(&dev_base_lock);
                ret = dev_ifsioc(&ifr, cmd);//here
                read_unlock(&dev_base_lock);
                if (!ret) {
                    if (colon)
                      *colon = ':';
                                    if (copy_to_user(arg, &ifr,
                                             sizeof(struct ifreq)))
                                        ret = -EFAULT;
                                }
                                return ret;
        ……
        }
        
         /*          
         *  Perform the SIOCxIFxxx calls.
         */             
        static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd)
        {               
            int err;             
            struct net_device *dev = __dev_get_by_name(ifr->ifr_name);
                    
            if (!dev)
                return -ENODEV;
                
            switch (cmd) {
                case SIOCGIFFLAGS:  /* Get interface flags */
                    ifr->ifr_flags = dev_get_flags(dev);//给ifr赋值
                    return 0;
                    
                case SIOCSIFFLAGS:  /* Set interface flags */
                    return dev_change_flags(dev, ifr->ifr_flags);
        ……
        }
                        

  • 相关阅读:
    在預設設定下,SQL Server 不允許遠端連接
    windows7语言包安装失败
    使一个销售组织能够销售另一个销售组织的产品
    转:多线程六种多线程方法解决UI线程阻塞
    转:BeginInvoke和EndInvoke方法 (原网址:http://www.cnblogs.com/nokiaguy/archive/2008/07/13/1241817.html)
    员工客户的统驭科目不能更改?
    公司间采购的退货(有序列号)
    排程 经典图示
    取消凭证分解 (取消公司下的多个利润中心)
    查找已删除的交货单信息
  • 原文地址:https://www.cnblogs.com/Ph-one/p/9024145.html
Copyright © 2020-2023  润新知