zoukankan      html  css  js  c++  java
  • 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);
        ……
        }
                        

  • 相关阅读:
    高精度计算
    高精度除以低精度
    P1258 小车问题
    POJ 2352 stars (树状数组入门经典!!!)
    HDU 3635 Dragon Balls(超级经典的带权并查集!!!新手入门)
    HDU 3938 Portal (离线并查集,此题思路很强!!!,得到所谓的距离很巧妙)
    POJ 1703 Find them, Catch them(确定元素归属集合的并查集)
    HDU Virtual Friends(超级经典的带权并查集)
    HDU 3047 Zjnu Stadium(带权并查集,难想到)
    HDU 3038 How Many Answers Are Wrong(带权并查集,真的很难想到是个并查集!!!)
  • 原文地址:https://www.cnblogs.com/Ph-one/p/9024145.html
Copyright © 2011-2022 走看看