我们知道在tcp/ip模型中,基本每一层都可以处理多重协议类型,那么当一个输入帧到达后,内核的每一层是如何来取得相应的处理函数呢?也就是说当我要把包传递给上层的时候,如何取得相应协议的处理函数。

我们这里先来看从二层如何把把数据传递给三层。

struct sk_buff {  ....................................  __be16          protocol;  .....................................  };

在sk_buff中的protocol字段能够表示输入帧的3层的协议,或者输入帧的mac头。在内核里面,是在函数netif_receive_skb中,通过protocol域来决定在三层的协议,以及处理函数。

如果内核没有找到protocol所对应协议的处理函数,那么这个帧将会被丢掉。而且一个packet也有可能被分发到多个handler,举个例子,当packet sniffer运行的时候,这里的protocol域有时就会为ETH_P_ALL.此时就会放所有的包进入下一层。不过使用ETH_P_ALL一般只是为了监测网络设备或者debug。比如tcpdump。

来看下netif_receive_skb的代码片段:

 type = skb->protocol;  list_for_each_entry_rcu(ptype,&ptype_base[ntohs(type) & PTYPE_HASH_MASK], list) {  if (ptype->type == type &&  (ptype->dev == null_or_orig || ptype->dev == skb->dev ||  ptype->dev == orig_dev)) {  if (pt_prev)ret = deliver_skb(skb, pt_prev, orig_dev);  pt_prev = ptype;  }  }  static inline int deliver_skb(struct sk_buff *skb,struct packet_type *pt_prev,struct net_device *orig_dev)
{  atomic_inc(&skb->users);  return pt_prev->func(skb, skb->dev, pt_prev, orig_dev);
}

我们可以看到最终会通过判断protocol来决定调用哪一个ptype,并调用相应的虚函数func,接下来我们就来看packet_type这个结构体,也就是所有的协议handler结构。

首先来看它的整体结构:

static struct list_head ptype_base[PTYPE_HASH_SIZE] __read_mostly; 

这里有一个全局的ptype_base,他是一个hash链表。它表示所有的协议handler结构。当通过dev_add_pack注册协议的时候就插入到相应的hashcode的相应链表。

static struct list_head ptype_all __read_mostly;    /* Taps */  

ptype_all也是一个全局链表,可以看到他完全是和ptype_base独立的。他就表示了ETH_P_ALL协议。

接下来就来看packet_type的结构

struct packet_type {  __be16          type;   /* This is really htons(ether_type). */  struct net_device   *dev;   /* NULL is wildcarded here       */  int         (*func) (struct sk_buff *,  struct net_device *,  struct packet_type *,  struct net_device *);  struct sk_buff      *(*gso_segment)(struct sk_buff *skb,  int features);  int         (*gso_send_check)(struct sk_buff *skb);  void            *af_packet_priv;  struct list_head    list;
};

type表示了协议的类型,dev表示了那个设备的协议类型,如果是NULL,则表示是所有设备,比如tcpdum就能通过指定设备名来监测某个指定设备。func对应协议的处理函数。af_pack_priv,被PF_PACKET类型的socket所使用(具体看unix网络编程). list链表(也就是hash链表中,相同的桶所处的链表). 中间的两个gso开头的函数,可以自己去看下gso的相关资料。

来看下ip协议的注册,以及初始化:

static struct packet_type ip_packet_type = {  .type = __constant_htons(ETH_P_IP),  .func = ip_rcv,  .gso_send_check = inet_gso_send_check,  .gso_segment = inet_gso_segment,
};  static int __init inet_init(void)
{
。。。。。。。。。。。。。。。。。。。。  dev_add_pack(&ip_packet_type);
.........................................  }

可以看到在初始化函数中,调用dev_add_pack来上面定义的ip_packet_type加入到全局的hash链表中。

void dev_add_pack(struct packet_type *pt)
{  int hash;  spin_lock_bh(&ptype_lock);
///判断类型是否为ETH_P_ALL  if (pt->type == htons(ETH_P_ALL))  list_add_rcu(&pt->list, &ptype_all);  else {
///计算hash值  hash = ntohs(pt->type) & PTYPE_HASH_MASK;
///插入到相应的hash表位置  list_add_rcu(&pt->list, &ptype_base[hash]);  }  spin_unlock_bh(&ptype_lock);
} 

而链路层得到相应的输入包的协议类型是通过eth_type_trans来实现的,可以随便看一下驱动的代码,当驱动调用netif_rx之前,都会先调用这个函数来得到protocol值。

先来看下不同的帧类型的区别:

eth_type_trans有两个作用,一个是设置packet type,一个是设置协议类型。 
其中packet type也就是skb->pkt_type字段,表示了链路层的数据类型,他可以为下面几种类型:

Java代码  
  1. #define PACKET_HOST     0       /* To us        */
  2. #define PACKET_BROADCAST    1       /* To all       */
  3. #define PACKET_MULTICAST    2       /* To group     */
  4. #define PACKET_OTHERHOST    3       /* To someone else  */
  5. #define PACKET_OUTGOING     4       /* Outgoing of any type */

这里要注意的是PACKET_OTHERHOST类型,它表示这个帧不属于这个接收接口,可是他并不会立即被扔掉,当传递给高层的时候。它主要用来protocol sniffer.

/* *  This is an Ethernet frame header. */  //帧头的表示。
struct ethhdr {  unsigned char   h_dest[ETH_ALEN];   /* destination eth addr */  unsigned char   h_source[ETH_ALEN]; /* source ether addr    */  __be16      h_proto;        /* packet type ID field */
} __attribute__((packed));  __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev)
{  struct ethhdr *eth;  unsigned char *rawp;  //一些初始化  skb->dev = dev;  skb_reset_mac_header(skb);  skb_pull(skb, ETH_HLEN);  eth = eth_hdr(skb);  if (is_multicast_ether_addr(eth->h_dest)) {  //判断是否为广播。  if (!compare_ether_addr(eth->h_dest, dev->broadcast))  //数据位广播  skb->pkt_type = PACKET_BROADCAST;  else  //多播  skb->pkt_type = PACKET_MULTICAST;  }else if (1 /*dev->flags&IFF_PROMISC */ ) {  //主要用来网络的监测。  if (unlikely(compare_ether_addr(eth->h_dest, dev->dev_addr)))  skb->pkt_type = PACKET_OTHERHOST;  }  //通过上面的图我们知道大于1536为ethernet 类型的帧,因此直接返回h_proto。  if (ntohs(eth->h_proto) >= 1536)  return eth->h_proto;  rawp = skb->data;  //取数据位来判断是否是802.3的帧。  if (*(unsigned short *)rawp == 0xFFFF)  return htons(ETH_P_802_3);  /* *      Real 802.2 LLC */  return htons(ETH_P_802_2);
} 

链路层到网络层的数据传递相关推荐

  1. 链路层、网络层、传输层、应用层长度

    1.概述 首先要看TCP/IP协议,涉及到四层:链路层,网络层,传输层,应用层. 以太网(Ethernet)的数据帧在链路层 IP包在网络层 TCP或UDP包在传输层 TCP或UDP中的数据(Data ...

  2. 【学习笔记】【计算机网络【总】】物理层;链路层;网络层;传输层;应用层;详解

    目录 框架 一.计算机网络 1. 层次结构设计 2. 现代互联网拓扑 3. 网络性能指标 二.物理层 三.数据链路层 2.最大传输单元MTU 3.以太网协议详解 四.网络层 - 链接 五.传输层 - ...

  3. 链路层---->MAC地址,链路层与网络层对比

    链路层 >>>>>>>>>>>>>>>>>>>>>>>> ...

  4. Internet协议栈 TCP/IP模型 、以太网封装以及解封装过程、物理层、链路层、网络层、传输层、应用层的作用 OSI七层模型

    目录 TCP/IP参考模型 以太网数据封装以及解封装过程: 各层次的传输数据单元 ​编辑 物理层: 发送端: 接收端: 作用: 链路层: 作用: 网络层: 作用: 传输层: 8个比特(bit)=1个字 ...

  5. 7.2.1因特网的链路层与网络层 - 因特网的链路层与网络层

    简介 Internet(因特网) =interconnection+network 互联网 Internet(因特网)指当前全球最大的.开放的.由众多网络相互连接而成的特定计算机网络,其前身是美国的A ...

  6. TCP/IP第二章笔记链路层协议

    二.链路层 2.1 引言 链路层由三个目的: 主要为IP模块发送和接受IP数据包: 为ARP模块发送请求和接受ARP应答: 为RARP发送RARP请求和接收RARP应答: TCP/IP协议支持不同的链 ...

  7. 计网链路层mac地址和ip地址缺一不可

    在学习之途有个疑问,为什么要分链路层和网络层,链路层的帧还要包裹网络层的数据包,这难道不是既麻烦又浪费时间吗?随着这个疑问往下继续深究. 1.链路层中        我们知道链路层是MAC地址,网络层 ...

  8. 交换机 链路层无法udp通讯_一文读懂计算机底层网络原理,包括TCP、UDP、header,什么是包、帧、段等关键问题...

    说到计算机网络原理,大家可能马上联想到,七层协议,传输层,链路层,三次握手四次挥手:前端的同学,还会想到我们用Crome F12的network里面的headers,状态码等.后端同学可能会联想到,抓 ...

  9. 计算机网络自顶向下-链路层

    链路层和局域网 两台主机之间,数据报跨越一系列通信链路传输,一些是有线链路一些是无线链路,从源主机起,通过一些了分组交换机在目的主机结束.在链路层中有两种不同的链路层信道, 第一种是广播信道,这种信道 ...

最新文章

  1. 机械键盘连击怎么处理_怎么选择机械键盘?各种平价机械键盘推荐
  2. Android Https相关完全解析 当OkHttp遇到Https
  3. Binary Search
  4. 北航出品,CVPR 安全AI大赛第二名:梯度细化提高对抗传递性
  5. Opencv中的图像深、浅拷贝
  6. MongoDB基本语法和操作入门
  7. oracle先的lvm分配,LVM实战案例之LVM空间缩减(本次对PV,VG,LV等进行空间缩减)
  8. Enterprise Library: Data Access Application Block使用向导,Part 1
  9. 通过 EWF 创建一个XP Embedded
  10. 飘云阁15周年逆向破解教程
  11. CAD转JPG如何才能清晰?来看这两个方法
  12. Android http 下载保存文件
  13. java office在线预览_Office文件在线预览(JAVA)
  14. 区块链学习笔记19——ETH难度调整
  15. 突破常规限制运行asp木马(转)
  16. FFmpeg实现音频解码并播放
  17. 使用html创建浮标,介绍最基本的浮标调整方法,让大家钓鱼时鱼鱼得水
  18. 图形学笔记(三)画一个彩色的三角形
  19. java 气泡图_JavaScript图表库Highcharts入门教程(八):气泡图
  20. Win7 下安装 VC6 和SP5

热门文章

  1. matlab 32和64,在32或64位matlab上运行?
  2. pytorch修改tensor的维度(修改为任意维度,或单纯的增减维度)
  3. 解决docker中运行scrapy使用chrome selenium报错InvalidSessionIdException: Message: invalid session id
  4. sklearn模型使用贝叶斯优化调参(以随机森林为例)
  5. python selenium使用JS新建标签(new tab)与切换标签
  6. java tomcat 教程_从零开始学习 JavaWeb - 02Tomcat教程
  7. Python 三元表达式、列表推导式、生成器表达式
  8. KVM之一:安装准备(基于CentOS6.7)
  9. CSU 1416 Practical Number
  10. HTML Table 固定列宽,实现excel表格效果