《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);
    ……
    }

ifconfig源码分析之与内核交互数据的更多相关文章

  1. 鸿蒙内核源码分析(管道文件篇) | 如何降低数据流动成本 | 百篇博客分析OpenHarmony源码 | v70.01

    百篇博客系列篇.本篇为: v70.xx 鸿蒙内核源码分析(管道文件篇) | 如何降低数据流动成本 | 51.c.h.o 文件系统相关篇为: v62.xx 鸿蒙内核源码分析(文件概念篇) | 为什么说一 ...

  2. 鸿蒙内核源码分析(调度队列篇) | 内核有多少个调度队列 | 百篇博客分析OpenHarmony源码 | v6.05

    百篇博客系列篇.本篇为: v06.xx 鸿蒙内核源码分析(调度队列篇) | 内核有多少个调度队列 | 51.c.h .o 任务管理相关篇为: v03.xx 鸿蒙内核源码分析(时钟任务篇) | 触发调度 ...

  3. springMVC源码分析--FlashMap和FlashMapManager重定向数据保存

    在上一篇博客springMVC源码分析--页面跳转RedirectView(三)中我们看到了在RedirectView跳转时会将跳转之前的请求中的参数保存到fFlashMap中,然后通过FlashMa ...

  4. MongoDB源码分析——mongo与JavaScript交互

    mongo与JavaScript交互 源码版本为MongoDB 2.6分支     之前已经说过mongo是MongoDB提供的一个执行JavaScript脚本的客户端工具,执行js其实就是一个js和 ...

  5. yolov3源码分析keras(一)数据的处理

    一.前言 本次分析的源码为大佬复现的keras版本,上一波地址:https://github.com/qqwweee/keras-yolo3 初步打算重点分析两部分,第一部分为数据,即分析图像如何做等 ...

  6. MPTCP 源码分析(四) 发送和接收数据

    简述:      MPTCP在发送数据方面和TCP的区别是可以从多条路径中选择一条 路径来发送数据.MPTCP在接收数据方面与TCP的区别是子路径对无序包 进行重排后,MPTCP的mpcb需要多所有子 ...

  7. ViewPager部分源码分析一:加载数据

    onMeasure()调用populate(),完成首次数据初始化. populate()维护ViewPager的page,包括mItems和mAdapter. populate(): if (cur ...

  8. 5. SOFAJRaft源码分析— RheaKV中如何存放数据?

    概述 上一篇讲了RheaKV是如何进行初始化的,因为RheaKV主要是用来做KV存储的,RheaKV读写的是相当的复杂,一起写会篇幅太长,所以这一篇主要来讲一下RheaKV中如何存放数据. 我们这里使 ...

  9. 内核通信之Netlink源码分析-用户内核通信原理2

    2017-07-05 上文以一个简单的案例描述了通过Netlink进行用户.内核通信的流程,本节针对流程中的各个要点进行深入分析 sock的创建 sock管理结构 sendmsg源码分析  sock的 ...

随机推荐

  1. 【Thinkphp5 】部署nginx时nginx.conf配置文件修改

    背景:thinkphp5项目 服务器环境: lnmp 1 打开路径  /usr/local/nginx/conf/vhost/ 此路径下会有你添加的域名文件夹..找到对应的域名打开. 2  代码如下, ...

  2. Docker 使用指南 (五)—— Dockerfile 详解

    版权声明:本文由田飞雨原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/97 来源:腾云阁 https://www.qclou ...

  3. hihocoder [Offer收割]编程练习赛14 小Hi和小Ho的礼物

    题目1 : 小Hi和小Ho的礼物 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 某人有N袋金币,其中第i袋内金币的数量是Ai.现在他决定选出2袋金币送给小Hi,再选2袋 ...

  4. js的字符串charAt()方法

    //字符中的字符从左向右进行索引,由0开始,字符串中的空格也算在内 var string = "charAt find word position"; document.write ...

  5. TDD中的单元测试写多少才够?

    测试驱动开发(TDD)已经是耳熟能详的名词,既然是测试驱动,那么测试用例代码就要写在开发代码的前面.但是如何写测试用例?写多少测试用例才够?我想大家在实际的操作过程都会产生这样的疑问. 3月15日,我 ...

  6. android异常:Can not perform this action after onSaveInstanc

    extends:http://zhiweiofli.iteye.com/blog/1539467 本人某个android项目开发阶段一直运行良好,直到上线前夕,在某款跑着android 4.03系统的 ...

  7. PMP 笔记

    项目: 为创造独特的产品.服务或结果而进行的临时性工作. 项目特征: 独特性:Unique.临时性:Temporary.渐进明细. 渐进明细:预算越来越精细.比如三峡工程中,预算从10亿级的误差到1亿 ...

  8. java类的成员初始化顺序和初始化块知识

    java类的成员初始化顺序和初始化块知识 转自:http://blog.csdn.net/lgfeng218/article/details/7606735 属性.方法.构造方法和自由块都是类中的成员 ...

  9. php程序中判断session过期

    我们最常用的是在php程序中设置,如下例程序所示: if(!isset($_SESSION['abc']) || time()-$_SESSION['abc']>60){ $_SESSION[' ...

  10. 170623、springboot编程之JdbcTemplate操作数据库

    使用JdbcTemplate操作mysql数据库! 1.在pom中引入jpa包 <dependency> <groupId>org.springframework.boot&l ...