1.选择路由  

  若要将数据包发至PC2,则linux系统通过查询路由表可知168.1.1.10(目的地址)的网关地址为192.168.1.1,此时linux系统选择网卡1发送数据包。

2.邻居子系统(通过arp协议建立起邻居的信息)

  选择网卡1发送数据时,首先将数据包发给邻居(网关),再由邻居转发至后面,若要发送给邻居,则必须知道邻居的MAC地址,若不知道邻居的MAC地址,则需要通过arp请求包获取邻居的MAC地址。

Linux网络体系结构由以下五个部分组成 1)系统调用接口 2)协议无关接口 3)网络协议 4)设备无关接口 5 设备驱动程序。下面分别简述五个部分:

1)系统调用接口

系统调用接口是用户空间的应用程序正常访问内核的唯一合法途径(终端和陷入也可访问内核)。如:

asmlingkage long sys_getpid(void)

{

return current->pid;

}

系统调用一般由sys开头 ,前面的修饰符是asmlingkage,表示函数由堆栈获得参数。

2)协议无关接口

协议无关接口是由socket来实现的。它提供了一组通用函数来支持各种不同协议。

通过网络栈进行的通信都需要对 socket 进行操作。Linux 中的 socket 结构是 struct sock ,这个结构是在 linux/include/net/sock.h 中定义的。这个巨大的结构中包含了特定 socket 所需要的所有状态信息,其中包括 socket 所使用的特定协议和在 socket 上可以执行的一些操作。

网络子系统可以通过一个定义了自己功能的特殊结构来了解可用协议。每个协议都维护了一个名为 proto 的结构(可以在 linux/include/net/sock.h 中找到)。这个结构定义了可以在从 socket 层到传输层中执行特定的 socket 操作

3)网络协议

Linux支持多种网络协议,可以在<linux/socket.h>中查到所支持的网络协议:

#define AF_UNIX        1    /* Unix domain sockets         */

#define AF_LOCAL    1    /* POSIX name for AF_UNIX    */

#define AF_INET        2    /* Internet IP Protocol     */

#define AF_AX25        3    /* Amateur Radio AX.25         */

#define AF_IPX        4    /* Novell IPX

… …

其中每一个所支持的协议对应net_family[]数组中的一项,net_family[]是结构体指针数组,其中的每一项都是一个结构体指针,指向一个net_proto_family 结构

struct net_proto_family {

int family;

int (*create) (struct socket * sock, int protocol);

short authentication;

short encryption;

short encrypt_net;

struct module *owner;

};这个结构体中注册了关于协议的信息。

4)设备无关接口

设备无关接口是由net_device实现的。任何设备和上层通信都是通过net_device设备无关接口。

它将协议与具有很多各种不同功能的硬件设备连接在一起。这一层提供了一组通用函数供底层网络设备驱动程序使用,让它们可以对高层协议栈进行操作。

首先,设备驱动程序可能会通过调用 register_netdevice 或 unregister_netdevice 在内核中进行注册或注销。调用者首先填写 net_device 结构,然后传递这个结构进行注册。内核调用它的 init 函数(如果定义了这种函数),然后执行一组健全性检查,并创建一个 sysfs 条目,然后将新设备添加到设备列表中(内核中的活动设备链表)。在 linux/include/linux/netdevice.h 中可以找到这个 net_device 结构。这些函数都是在 linux/net/core/dev.c 中实现的。

要从协议层向设备中发送 sk_buff ,就需要使用 dev_queue_xmit 函数。这个函数可以对 sk_buff 进行排队,从而由底层设备驱动程序进行最终传输(使用 sk_buff 中引用的 net_device 或 sk_buff->dev 所定义的网络设备)。dev 结构中包含了一个名为 hard_start_xmit 的方法,其中保存有发起 sk_buff 传输所使用的驱动程序函数。

报文的接收通常是使用 netif_rx 执行的。当底层设备驱动程序接收一个报文(包含在所分配的 sk_buff 中)时,就会通过调用 netif_rx 将 sk_buff 上传至网络层。然后,这个函数通过 netif_rx_schedule 将 sk_buff 在上层协议队列中进行排队,供以后进行处理。可以在 linux/net/core/dev.c 中找到 dev_queue_xmit 和 netif_rx 函数。

5)设备驱动程序

网络栈底部是负责管理物理网络设备的设备驱动程序。例如,包串口使用的 SLIP 驱动程序以及以太网设备使用的以太网驱动程序都是这一层的设备。

在进行初始化时,设备驱动程序会分配一个 net_device 结构,然后使用必须的程序对其进行初始化。这些程序中有一个是 dev->hard_start_xmit ,它定义了上层应该如何对 sk_buff 排队进行传输。这个程序的参数为 sk_buff 。这个函数的操作取决于底层硬件,但是通常 sk_buff 所描述的报文都会被移动到硬件环或队列中。就像是设备无关层中所描述的一样,对于 NAPI 兼容的网络驱动程序来说,帧的接收使用了 netif_rx 和 netif_receive_skb 接口。NAPI 驱动程序会对底层硬件的能力进行一些限制。

分析内核代码实现:

1.发送UDP数据包

  在应用程序中

  通过socket()函数建立一个socket,然后通过write()函数讲数据写入socket发送出去

  在内核中:

  a.在系统调用层和协议无关层中

  首先通过socket_file_ops结构找出应用程序在内核中的入口,其函数为sock_aio_write,紧接着调用do_sock_write---__sock_sendmsg---__sock_sendmsg_nosec

  b.在网络协议层中

  调用udp_sendmsg---ip_route_output_flow(选择路由)  udp_flush_pending_frames---ip_flush_pending_frames(ip协议入口)---ip_local_out---dst_output---ip_finish_output---ip_finish_output2---arp_generic_ops->neigh_resolve_output(建立邻居信息)

  c.在设备无关接口中

  调用dev_queue_ximt---dev_hard_start_xmit

  d.在驱动程序层中

  调用ndo_start_xmit

2.接收IP数据包

  在应用程序中

  通过系统调用recvmsg函数获取包的内容

  在内核中:

  网卡接收到数据包之后发生中断,通过netif_rx(此处触发一个软中断,当处理器空闲时再处理)函数将包递给上层的netif_rx_action(除驱动层之外,上面四层的总入口),继续调用netif_receive_skb(判断由哪个协议处理该包)---deliver_skb,然后将数据包递交给ip协议层处理(ip_rcv-ip协议栈层处理入口),紧接着有丢给udp协议层处理(udp_rcv-udp协议栈层处理入口),udp层处理完之后,递交给sock->ops->recvmsg,即为recvmsg系统调用对应的函数。

  

linux网络子系统内核分析的更多相关文章

  1. Linux网络子系统

    再Linux的世界里,万物皆文件,通过虚拟文件系统VFS,程序可以用标准的Linux系统调用对不同的文件系统,甚至不同介质上的文件系统进行读写操作.下面我们揭示Linux网络子系统的秘密 sockfs ...

  2. Linux 网络子系统

    今天记录一下Linux网络子系统相关的东西. 因为感觉对这一块还是有一个很大的空白,这件事情太可怕了. 摘抄多份博客进行总结一下Linux网络子系统的相关东西. 一. Linux网络子系统体系结构 L ...

  3. Linux 网络子系统之网络协议接口层(一)

    Linux 网络设备驱动之网络协议接口层介绍. 网络协议接口层最主要的功能是给上层协议提供透明的数据包发送和接收接口. 当上层ARP或IP需要发送数据包时,它将调用网络协议接口层的dev_queue_ ...

  4. Linux网络编程&内核学习

    c语言: 基础篇 1.<写给大家看的C语言书(第2版)> 原书名: Absolute Beginner's Guide to C (2nd Edition) 原出版社: Sams 作者: ...

  5. Linux输入子系统框架分析(1)

    在Linux下的输入设备键盘.触摸屏.鼠标等都能够用输入子系统来实现驱动.输入子系统分为三层,核心层和设备驱动层.事件层.核心层和事件层由Linux输入子系统本身实现,设备驱动层由我们实现.我们在设备 ...

  6. Linux网络编程案例分析

    本代码来自于博主:辉夜星辰 本篇主要对运行代码中出现的问题进行分析,代码本身的内容后续展开讨论. 服务器端代码 /* Linux网络编程之TCP编程,服务器端读数据 socket函数之后,返回值ser ...

  7. Linux input子系统实例分析(一)

    这是一个简单的输入设备驱动实例.这个输入设备只有一个按键,按键被连接到一条中断线上,当按键被按下时,将产生一个中断,内核将检测到这个中断,并对其进行处理.该实例的代码如下:     1: #inclu ...

  8. Linux网络子系统之---- PHY 配置

    MII即媒体独立接口,也叫介质无关接口. 它包括一个数据接口,以及一个MAC和PHY之间的管理接口(图1). 数据接口包括分别用于发送器和接收器的两条独立信道.每条信道都有自己的数据.时钟和控制信号. ...

  9. Linux input子系统实例分析(二)

    紧接着上一节的实例我们来分析调用的input子系统的接口: 1. input_dev,用来标识输入设备 1: struct input_dev { 2: const char *name; //设备名 ...

随机推荐

  1. html5—— 应用程序缓存

    使用 HTML5,通过创建 cache manifest 文件,可以轻松地创建 web 应用的离线版本. 什么是应用程序缓存(Application Cache)? HTML5 引入了应用程序缓存,这 ...

  2. android L 新控件侧滑菜单DrawerLayout 使用教程

    介绍 drawerLayout是Support Library包中实现了侧滑菜单效果的控件,可以说drawerLayout是因为第三方控件如MenuDrawer等的出现之后,google借鉴而出现的产 ...

  3. unity区分点击在3D物体还是2D UI上

    当场景中的3D物体需要响应点击,但同时有UI显示时,存在判断点击是在3D物体上还是UI上的问题,办法如下: 1. 射线检测所有2D 3D物体,有2D物体被检测到时表明当前有UI.但无论Physics2 ...

  4. SICP 1.1-1.5

    1.1 a = b = nil 1.2 (/ (+ (- (- (+ (/ ))))) (* (- ) (- )) 1.3 a = b = nil 1.4... 1.5 (define (p) (p) ...

  5. 简单jQuery实现选项框中列表项的选择

    这段代码非常的简单,仅仅作为自己的一个小小的记录! ok,先上一个简单的图例,效果如下(注意:这只是一个简单的例子,不过可以根据这个简单的例子,变化出更为复杂的效果)! 代码也非常的简单,如下所示(注 ...

  6. VC 运行时库 /MD、/MDd 和 /MT、/MTd

    这里总结下他们的区别,后面的那个'd'是代表DEBUG版本,没有'd'的就是RELEASE版本了. 首先说/MT /MT是 "multithread, static version ” 意思 ...

  7. SQL数据库基本语句

    SQL特点--> 1)综合统一.SQL是集数据定义.数据操作和数据控制于一体,语言峰峰统一,可独立完成数据库生命周期的所有活动. 2)高度非过程化.SQL语言是高度非过程化语言,当进行数据操作时 ...

  8. badge ionic tab

    我需要在tab上动态显示 badge badge="badges.carts" badge-style="badge-assertive" 将这段代码 放在了 ...

  9. 详解H264视频格式-2016.01.28

    专业名词解释 VCL(Video Coding Layer)视频编码层 NAL(Network Abstraction Layer)网络提取层 SPS(Sequence Parameter Set) ...

  10. vba 快速定位当前EXCEL最后一栏

    工作的需要,有时会对EXCEL数据进行处理,比如格式化,有数据的单元格画横线. 最初,傻傻的,直接用个循环从第1行,一直往后找,判断是否为空,真傻. Function FindLastCell() D ...