在netif_receive_skb()函数中,可以看出处理的是像ARP、IP这些链路层以上的协议,那么,链路层报头是在哪里去掉的呢?答案是网卡驱动中,在调用netif_receive_skb()前,

skb->protocol = eth_type_trans(skb, bp->dev);

该函数对处理后skb>data跳过以太网报头,由mac_header指示以太网报头:

进入netif_receive_skb()函数

list_for_each_entry_rcu(ptype,&ptype_base[ntohs(type) & PTYPE_HASH_MASK], list)

按照协议类型依次由相应的协议模块进行处理,而所以的协议模块处理都会注册在ptype_base中,实际是链表结构。

net/core/dev.c

static struct list_head ptype_base __read_mostly;   /* Taps */

而相应的协议模块是通过dev_add_pack()函数加入的:

void dev_add_pack(struct packet_type *pt)

{

int hash;

spin_lock_bh(&ptype_lock);

if (pt->type == htons(ETH_P_ALL))

list_add_rcu(&pt->list, &ptype_all);

else {

hash = ntohs(pt->type) & PTYPE_HASH_MASK;

list_add_rcu(&pt->list, &ptype_base[hash]);

}

spin_unlock_bh(&ptype_lock);

}

以ARP处理为例

该模块的定义,它会在arp_init()中注册进ptype_base链表中:

static struct packet_type arp_packet_type __read_mostly = {

.type =      cpu_to_be16(ETH_P_ARP),

.func =      arp_rcv,

};

然后在根据报文的TYPE来在ptype_base中查找相应协议模块进行处理时,实际调用arp_rcv()进行接收

arp_rcv() --> arp_process()

arp = arp_hdr(skb);

……

arp_ptr= (unsigned char *)(arp+1);

sha= arp_ptr;

arp_ptr += dev->addr_len;

memcpy(&sip, arp_ptr, 4);

arp_ptr += 4;

arp_ptr += dev->addr_len;

memcpy(&tip, arp_ptr, 4);

操作后这指针位置:

然后判断是ARP请求报文,这时先查询路由表ip_route_input()

if (arp->ar_op == htons(ARPOP_REQUEST) &&

ip_route_input(skb, tip, sip, 0, dev) == 0)

在ip_route_input()函数中,先在cache中查询是否存在相应的路由表项:

hash = rt_hash(daddr, saddr, iif, rt_genid(net));

缓存的路由项在内核中组织成hash表的形式,因此在查询时,先算出的hash值,再用该项- rt_hash_table[hash].chain即可。这里可以看到,缓存路由项包括了源IP地址、目的IP地址、网卡号。

如果在缓存中没有查到匹配项,或指定不查询cache,则查询路由表ip_route_input_slow();

进入ip_route_input_slow()函数,最终调用fib_lookup()得到查询结果fib_result

if ((err = fib_lookup(net, &fl, &res)) != 0)

如果结果fib_result合法,则需要更新路由缓存,将此次查询结果写入缓存

hash = rt_hash(daddr, saddr, fl.iif, rt_genid(net));

err = rt_intern_hash(hash, rth, NULL, skb, fl.iif);

在查找完路由表后,回到arp_process()函数,如果路由项指向本地,则应由本机接收该报文:

if (addr_type == RTN_LOCAL) {

……

if (!dont_send) {

n = neigh_event_ns(&arp_tbl, sha, &sip, dev);

if (n) {

arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha);

neigh_release(n);

}

}

goto out;

}

首先更新邻居表neigh_event_ns(),然后发送ARP响应 – arp_send。

至此,大致的ARP流程完成。由于ARP部分涉及到路由表以及邻居表,这都是很大的概念,在下一篇中介绍,这里直接略过了。

Linux内核分析 - 网络[三]:从netif_receive_skb()说起相关推荐

  1. linux内核启动分析 三,Linux内核分析 实验三:跟踪分析Linux内核的启动过程

    贺邦 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-1000029000 一. 实验过程 ...

  2. Linux内核分析(三)----初识linux内存管理子系统

    原文:Linux内核分析(三)----初识linux内存管理子系统 Linux内核分析(三) 昨天我们对内核模块进行了简单的分析,今天为了让我们今后的分析没有太多障碍,我们今天先简单的分析一下linu ...

  3. Linux内核分析——第三周学习笔记

    20135313吴子怡.北京电子科技学院 chapter1 知识点梳理 一.Linux内核源代码简介 (视频中对目录下的文件进行了简介,记录如下) arch目录 占有相当庞大的空间 arch/x86目 ...

  4. linux内核分析 网络九,“Linux内核分析”实验报告(九)

    一 Linux内核分析博客简介及其索引 本次实验简单的分析了计算机如何进行工作,并通过简单的汇编实例进行解释分析 在本次实验中 通过听老师的视频分析,和自己的学习,初步了解了进程切换的原理.操作系统通 ...

  5. Linux内核分析 - 网络[十六]:TCP三次握手

    内核:2.6.34       TCP是应用最广泛的传输层协议,其提供了面向连接的.可靠的字节流服务,但也正是因为这些特性,使得TCP较之UDP异常复杂,还是分两部分[创建与使用]来进行分析.这篇主要 ...

  6. Linux内核分析 - 网络[十]:ARP杂谈

    内核版本:2.6.34 杂谈一:重复地址检测 Linux协议栈中处理重复地址检测报文的是arp_process()中的一段代码,RFC2131是DHCP的草案,相应的sip==0是DHCP服务器用来检 ...

  7. Linux内核分析 - 网络[四]:路由表

    路由表 在内核中存在路由表fib_table_hash和路由缓存表rt_hash_table.路由缓存表主要是为了加速路由的查找,每次路由查询都会先查找路由缓存,再查找路由表.这和cache是一个道理 ...

  8. Linux内核分析 - 网络[九]:邻居表

    内核版本:2.6.34 这部分的重点是三个核心的数据结构-邻居表.邻居缓存.代理邻居表,以及NUD状态转移图. 总的来说,要成功添加一条邻居表项,需要满足两个条件:1. 本机使用该表项:2. 对方主机 ...

  9. linux内核 checksum,Linux内核分析 - 网络[十三]:校验和

    内核版本:2.6.34 报文的IP校验和.ICMP校验和.TCP/UDP校验和使用相同的算法,在RFC1071中定义,网上这方面的资料和例子很多,就不解释算法流程了,而是侧重于在实现的变化和技巧. T ...

最新文章

  1. python3 pillow使用测试
  2. 8,协议序列化组件NewLife.Serialization
  3. Apache 各启动方式的差别
  4. JPA J2SE 桌面应用范例
  5. RabbitMQ中常用的三种Exchange 类型
  6. 清华大学出版社,包邮送40本畅销书籍
  7. 如何抢占云栖大会C位?史上最强强强攻略来了
  8. Arm学习总结之 32位和64位寄存器
  9. pycharm-连接mysql设置
  10. Js事件对象EventUtil
  11. 树堆(Treap)图文详解与实现
  12. 毕业后,两个月,第二家公司上班第一天
  13. 李宏毅深度学习HW2 收入预测 (logistic regression)
  14. sharepoint搭建文档服务器,SharePoint Server教程
  15. Linux环境安装之Ant
  16. 009-lissajous(一)
  17. 纹波(ripple)--学习笔记
  18. 数据治理:数据质量管理策略!
  19. 咪咕音乐的下载音乐存储路径(MAC)
  20. 2015年:跑步计划

热门文章

  1. HTTP,TCP, socket,RPC 与gRPC都是啥?
  2. python pip下载本地依赖包,并在离线环境中安装,并解决报错ERROR: Could not find a version that satisfies the requirement报错
  3. python 读取、写入 pkl文件
  4. 反转dataframe
  5. core控制器属性注入的用处_asp.net-core – 如何使用Autofac和ASP.NET Core在控制器上启用属性注入?...
  6. java ldap 实例_JAVA_基本LDAP操作实例
  7. jQuery和react实现二维码
  8. Docker-创建和分享应用(3)
  9. 使Eclipse下支持编写HTML/JS/CSS/JSP页面的自动提示。
  10. How to Leak a Context: Handlers Inner Classes