1、linux目前支持多种协议族,每个协议族用一个net_porto_family结构实例来表示,在初始化时,会调用sock_register()函数初始化注册到net_families[NPROTO]中去;

同时出现了一个地址族的概念,目前协议族和地址族是一 一 对应关系。历史上曾经有一个协议族支持多个地址族,实际上从未实现过。在socket.h文件中PF_XX和AF_XX 值一样

2、由于不同协议族的结构差别很大,为了封装统一,以便在初始化时,可以统一接口,于是就有了net_proto_family。其用sock_register统一注册,初始化钩子,具体初始化,其实现见钩子实现,类似于VFS 的实现方式。一种很好的设计思想。

/*ops->create在应用程序创建套接字的时候,引起系统调用,从而在函数__sock_create中执行ops->create  netlink为netlink_family_ops
应用层创建套接字的时候,内核系统调用sock_create,然后执行该函数
pf_inet的net_families[]为inet_family_ops,对应的套接口层ops参考inetsw_array中的inet_stream_ops inet_dgram_ops inet_sockraw_ops,
传输层操作集分别为tcp_prot udp_prot raw_prot
netlink的net_families[]netlink_family_ops,对应的套接口层ops为netlink_ops
family协议族通过sock_register注册  传输层接口tcp_prot udp_prot netlink_prot等通过proto_register注册
IP层接口通过inet_add_protocol(&icmp_protocol等注册 ,这些组成过程参考inet_init函数*/

struct net_proto_family {//操作集参考inetsw_arrayint        family;int        (*create)(struct net *net, struct socket *sock,int protocol, int kern);协议族的套接字创建函数指针,每个协议族实现都不同struct module    *owner;
};

Internet 协议族的net_proto_family结构实例为inet_family_ops,创建套接字socket时,其调用接口为inet_create().

2、inet_protosw 结构

/* This is used to register socket interfaces for IP protocols.  */
struct inet_protosw {struct list_head list;/* 初始化时将相同的type的inet_protosw散列在同一个链表*//* These two fields form the lookup key.  */unsigned short  type;     /* This is the 2nd argument to socket(2). 表示套接口字的类型,对于Internet 协议族有三种类型 SOCK_STREAM SOCK_DGRAM SOCK_RAW 对于与应用层socket函数的第二个参数type*/unsigned short   protocol; /* This is the L4 protocol number.  */struct proto    *prot; /*套接口网络层口,tcp为tcp_port udp为udp_port 原始套接字为raw_port*/const struct proto_ops *ops;/* 套接口传输层接口,tcp为inet_stream_ops,udp 为inet_dgram_ops,原始套接字为inet_sockraw_ops*/unsigned char  flags;      /* See INET_PROTOSW_* below.  */
};

#define INET_PROTOSW_REUSE 0x01         /* Are ports automatically reusable? 端口重用*/
#define INET_PROTOSW_PERMANENT 0x02  /* Permanent protocols are unremovable. 协议不能被替换卸载*/
#define INET_PROTOSW_ICSK      0x04  /* Is this an inet_connection_sock? 是不是为连接类型的接口*/

View Code

tcp 不能被替换卸载切为连接型套接字,udp 不能被替换和卸载,rawsocket端口可以重用。

/* Upon startup we insert all the elements in inetsw_array[] into* the linked list inetsw.在初始化的时候我们会将上面数组中的的元素按套接字类型插入static struct list_head inetsw[SOCK_MAX];链表数组中*/  /* * inetsw_array数组包含三个inet_protosw结构的实例,分别对应* TCP、UDP和原始套接字。在Internet协议族初始化函数inet_init()中* 调用inet_register_protosw()将inetsw_array数组中* 的inet_protosw结构实例,以其type值为key组织到散列表inetsw中,* 也就是说各协议族中type值相同而protocol值不同的inet_protosw结构* 实例,在inetsw散列表中以type为关键字连接成链表,通过inetsw* 散列表可以找到所有协议族的inet_protosw结构实例。*/ //ipv4_specific是TCP传输层到网络层数据发送以及TCP建立过程的真正OPS,在tcp_prot->init中被赋值给inet_connection_sock->icsk_af_ops
static struct inet_protosw inetsw_array[] =   //这个和应用层创建套接字相关,个人我理解是属于套接口层,为了把套接口层和传输层衔接起来(tcp_protocol udp_protol icmp_protocol)
{{  .type =       SOCK_STREAM, //在inet_create的时候,用它做为关键字,把下面这几个成员联系在一起.protocol =   IPPROTO_TCP,//tcp_prot udp proto raw_proto头添加到的proto_list中,通过遍历该链表就可以知道有哪些传输层协议添加到该链表中
//协议最终都是通过inet_init中的proto_register添加到proto_list链表中的。family协议族通过sock_register注册
//传输层接口tcp_prot udp_prot netlink_prot等通过proto_register注册
//IP层接口通过inet_add_protocol(&icmp_protocol等注册 ,这些组成过程参考inet_init函数.prot =       &tcp_prot,//传输层操作集  在inet_create中的sk_alloc中赋值
// 先执行ops中的函数,然后执行prot中对应的函数 proto结构为网络接口层,
//结构中的操作实现传输层的操作和从传输层到网络层调用的跳转,
//在proto结构中的某些成员跟proto_ops结构中的成员对应,比如connect()等.ops =        &inet_stream_ops,//套接口层操作集,也就是协议族操作集
// 用来区分协议族(netlink family(ops为netlink_ops)或者 inet family)
// ops在创建套接字的时候被赋值,例如netlink赋值的地方在__netlink_create  pf_net赋值的地方在inet_create中.no_check =   0, //为0表示始终进行校验和操作.flags =      INET_PROTOSW_PERMANENT |INET_PROTOSW_ICSK,},{.type =       SOCK_DGRAM,.protocol =   IPPROTO_UDP,.prot =       &udp_prot,//传输层操作集  在inet_create中的sk_alloc中赋值  先执行ops中的函数,然后执行prot中对应的函数.ops =        &inet_dgram_ops,//套接口层操作集 用来区分协议族(netlink family(ops为netlink_ops)或者 inet family)
// ops在创建套接字的时候被赋值,例如netlink赋值的地方在__netlink_create  pf_net赋值的地方在inet_create中.no_check =   UDP_CSUM_DEFAULT,.flags =      INET_PROTOSW_PERMANENT,},{.type =       SOCK_RAW,  //原始套接口.protocol =   IPPROTO_IP, /* wild card */.prot =       &raw_prot,//传输层操作集  在inet_create中的sk_alloc中赋值  先执行ops中的函数,然后执行prot中对应的函数.ops =        &inet_sockraw_ops,//套接口层操作集
//用来区分协议族(netlink family(ops为netlink_ops)或者 inet family)  ops在创建套接字的时候被赋值,
//例如netlink赋值的地方在__netlink_create  pf_net赋值的地方在inet_create中.no_check =   UDP_CSUM_DEFAULT,.flags =      INET_PROTOSW_REUSE,}
};

3、net_protocol 结构

net_protocol 结构定义了传输层协议(包含icmp igmp协议)以及传输层的报文接收例程,此结构是网络层和传输层之间的桥梁。

/* * inet_add_protocol函数用于将上述结构的实例(指针)* 存储到inet_protos 数组中* update:*  net_protocol是一个非常重要的结构,定义了协议族中支持的传输层协议以及传输层的报文接收实例。此结构是网络层和 传输层之间的桥梁,当网络数据包从网络层流向传输层时,* 会调用此结构中的传输层协议数据时,会调用此结构中的传输层协议数据报接收处理函数。** 内核中为Internet协议族定义了4个net_protocol结构实例---* icmp_protocol、udp_protocol、tcp_protocol和igmp_protocol* ,分别与ICMP、UDP、TCP和IGMP协议一一对应。在Internet协议族* 初始化时,调用inet_add_protocol()将它们注册到net_protocol* 结构指针数组inet_protos[MAX_INET_PROTOS]中。在系统运行* 过程中,随时可以用内核模块加载/卸载方式,调用函数inet_add_protocol()* /inet_del_protocol()将net_protocol结构实例注册到inet_protos[]数组中,* 或从中删除。*///ops = rcu_dereference(inet_protos[proto]);通过该函数获取对应的协议ops
/* This is used to register protocols. */
struct net_protocol {void           (*early_demux)(struct sk_buff *skb);/* 分组将传递到该函数进行进一步处理*//** 传输层协议数据包接收处理函数指针,当网络层接收IP数据包* 之后,根据IP数据包所指示传输层协议,调用对应传输层* net_protocol结构的该例程接收报文。* TCP协议的接收函数为tcp_v4_rcv(),UDP协议的接收函数为* udp_rcv(),IGMP协议为igmp_rcv(),ICMP协议为icmp_rcv()。*/int          (*handler)(struct sk_buff *skb);/* * 在接收到ICMP错误信息并需要传递到更高层时,* 调用该函数*//** 在ICMP模块中接收到差错报文后,会解析差错报文,并根据* 差错报文中原始的IP首部,调用对应传输层的异常处理* 函数err_handler。TCP协议为tcp_v4_err(),UDP为* udp_err(),IGMP则无。*/void          (*err_handler)(struct sk_buff *skb, u32 info);/** no_policy标识在路由时是否进行策略路由。TCP和UDP默认不进行* 策略路由。*/unsigned int     no_policy:1,netns_ok:1,/* does the protocol do more stringent* icmp tag validation than simple* socket lookup?*/icmp_strict_tag_validation:1;
};

初始化后的inet_protos 如下:

4、Internet协议族的初始化

Internet协议初始化函数为inet_init ,通过fs_initcall调用,加载到内核中;

/设备物理层的初始化net_dev_init
 TCP/IP协议栈初始化inet_init  传输层的协议初始化也在这里面
 传输层初始化proto_init  只是为了显示各种协议用的
 套接口层初始化sock_init  netfilter_init在套接口层初始化的时候也初始化了

static int __init inet_init(void)
{struct inet_protosw *q;struct list_head *r;int rc = -EINVAL;sock_skb_cb_check_size(sizeof(struct inet_skb_parm));rc = proto_register(&tcp_prot, 1);if (rc)goto out;rc = proto_register(&udp_prot, 1);if (rc)goto out_unregister_tcp_proto;rc = proto_register(&raw_prot, 1);if (rc)goto out_unregister_udp_proto;rc = proto_register(&ping_prot, 1);if (rc)goto out_unregister_raw_proto;/**    Tell SOCKET that we are alive...*/(void)sock_register(&inet_family_ops);#ifdef CONFIG_SYSCTLip_static_sysctl_init();
#endif/**    Add all the base protocols.*/
//这里面有每种协议传输层的接收函数,if (inet_add_protocol(&icmp_protocol, IPPROTO_ICMP) < 0)pr_crit("%s: Cannot add ICMP protocol\n", __func__);if (inet_add_protocol(&udp_protocol, IPPROTO_UDP) < 0)pr_crit("%s: Cannot add UDP protocol\n", __func__);if (inet_add_protocol(&tcp_protocol, IPPROTO_TCP) < 0)pr_crit("%s: Cannot add TCP protocol\n", __func__);
#ifdef CONFIG_IP_MULTICASTif (inet_add_protocol(&igmp_protocol, IPPROTO_IGMP) < 0)pr_crit("%s: Cannot add IGMP protocol\n", __func__);
#endif/* Register the socket-side information for inet_create. */for (r = &inetsw[0]; r < &inetsw[SOCK_MAX]; ++r)INIT_LIST_HEAD(r);for (q = inetsw_array; q < &inetsw_array[INETSW_ARRAY_LEN]; ++q)inet_register_protosw(q);//把inetsw_array结构中的节点添加到inetsw表中,以type为索引 为套接字层所用/**    Set the ARP module up*/arp_init();/**    Set the IP module up*/ip_init();tcp_v4_init()//创建一个tcp套接字用来发送rst ack 字段/* Setup TCP slab cache for open requests. */tcp_init();/* Setup UDP memory threshold */udp_init();/* Add UDP-Lite (RFC 3828) */udplite4_register();ping_init();/**    Set the ICMP layer up*/
/*由于协议栈本身有发送ICMP数据报的需求,所以,需要在协议栈中创建内核态的原始套接字,用于发送ICMP数据报,这个事情在协议栈初始化时,        由 icmp_init函数完成。它为每个CPU都创建一个icmp_socket,创建工作由sock_create_kern函数完成,创建流程跟应用层 创建socket完全一致。*/if (icmp_init() < 0)panic("Failed to create the ICMP control socket.\n");/**    Initialise the multicast router*/
#if defined(CONFIG_IP_MROUTE)if (ip_mr_init())pr_crit("%s: Cannot init ipv4 mroute\n", __func__);
#endifif (init_inet_pernet_ops())pr_crit("%s: Cannot init ipv4 inet pernet ops\n", __func__);/**    Initialise per-cpu ipv4 mibs*/if (init_ipv4_mibs())pr_crit("%s: Cannot init ipv4 mibs\n", __func__);ipv4_proc_init();ipfrag_init();dev_add_pack(&ip_packet_type);ip_tunnel_core_init();rc = 0;
out:return rc;
out_unregister_raw_proto:proto_unregister(&raw_prot);
out_unregister_udp_proto:proto_unregister(&udp_prot);
out_unregister_tcp_proto:proto_unregister(&tcp_prot);goto out;
}fs_initcall(inet_init);

转载于:https://www.cnblogs.com/codestack/p/9193533.html

Internet 网络协议族相关推荐

  1. [译]网络协议族(未完)

    原文:维基百科 Ps. 基本忠实于原文,追求知识正确传递的原则.欢迎大家纠错或有好的翻译方式也可提出! Internet 协议族是 Internet 和类似网络的通信协议集合,通常情况下是广域网的最流 ...

  2. Linux的网络协议族是什么,Linux 网络协议的概述

    网络层协议 网络层协议主要包括 IP.ICMP(网络控制报文协议).ARP(地址解析协议) IP协议 该协议被设计成互联分组交换通信网,以形成一个网际通信环境.它负责在源主机和目的地主机之间传输来自其 ...

  3. Linux网络编程 - 套接字与协议族

    一 理解网络编程和套接字(socket) 1.1 网络编程和套接字概要 网络编程就是编程程序使两台连网的计算机可以互相交换数据.那么,这两台计算机之间用什么传输数据呢?首先需要物理连接.如今大部分计算 ...

  4. 计算机网络学习--协议族、协议栈

    1. 协议族是一组协议的集合. 协议栈是协议的实现. 地址族是地址划分的标准集合. 协议族是一组协议的集合. 协议栈是协议的实现. 如 TCP/IP是一个协议族:Windows上用C实现了TCP/IP ...

  5. 网络协议和浏览器到网络简单攻防实现的探索(二)

    一.关于网络协议的整体梳理 1.1 客户端和服务端的通信 常见的架构,B/S和C/s架构.而在浏览器中运行王爷的属于B/S架构.网页浏览器通过地址栏的url获取服务器对应的资源文件.通过浏览器的处理后 ...

  6. 网络模型和TCP协议族

    网络模型 脑图链接 经典的OSI-7层模型 OSI 的全称是开放系统互连参考模型(Open System Interconnection/Reference Model,OSI/RM) ps: 超详细 ...

  7. 程序员必知必会网络传输之TCP/IP协议族,共864页的详解文档让你原地起飞!

    我们现实网络无处不在,我们被庞大的虚拟网络包围,但我们却对它是怎样把我们的信息传递并实现通信的,我们并没有了解过,那么当我们在浏览器中出入一段地址,按下回车这背后都会发生什么? 比如说一般场景下,客户 ...

  8. 网络协议 — IPSec 安全隧道协议族

    目录 文章目录 目录 IPSec 安全隧道协议族 封装协议 Authentication Header 协议 Encapsulating Security Payload 协议 封装模式 Transp ...

  9. 网络传输之TCP/IP协议族

    我们现实网络无处不在,我们被庞大的虚拟网络包围,但我们却对它是怎样把我们的信息传递并实现通信的,我们并没有了解过,那么当我们在浏览器中出入一段地址,按下回车这背后都会发生什么? 比如说一般场景下,客户 ...

最新文章

  1. AFF镜像工具集afflib-tools
  2. Quartus II调用modelsim无缝仿真
  3. python功能分享_Python中非常实用的一些功能和函数分享
  4. c语言编写期末考试成绩,C语言期末考试卷(A卷含答案).doc
  5. maven-compiler-plugin 插件详解
  6. 多方法接口回调_浅析接口定义和接口回调
  7. 【几个关于CSS的网站】
  8. 搜搜(www.soso.com),I 老虎油!
  9. 学习笔记(8):ArcGIS10.X入门实战视频教程(GIS思维)-矢量数据数量分级显示、图表显示,多属性、lyr保存
  10. Android 邮箱自动补全-MultiAutoCompleteTextView实现
  11. RGB_打开/获取颜色选择器(RGB)的几种方式/本地RGB查询/css颜色名参考
  12. 电影院传出的哭声《比悲伤更悲伤的故事》程序员们怎么看?
  13. 【HDU6608 Fansblog】求很大很大的数的阶乘
  14. 数据库系统原理与设计——投影运算、选择运算
  15. 类的静态成员与静态成员函数
  16. 2022电大国家开放大学网上形考任务-纳税筹划非免费(非答案)
  17. Bean Validation完结篇:你必须关注的边边角角(约束级联、自定义约束、自定义校验器、国际化失败消息...)【享学Spring】
  18. label-position--提问
  19. FS00 创建科目 GL_ACCT_MASTER_SAVE
  20. pos机顾显java控制打印内容_前台打印机和顾显设置说明

热门文章

  1. 闪屏,default
  2. Android中AVD(Android Virtual Device)不能启动的处理方法
  3. React-Amap-HOC组件封装
  4. OCT检查报告-光感受器COST线缺失与黄斑前膜
  5. Spark数据倾斜-采样倾斜key并分拆join操作-详细图解与代码
  6. java incompatible types: int cannot be converted to java.lang.Long
  7. 所有特征在不同分类之间、 train和test之间的列分布差异(图形绘制)
  8. 训练网络指定层pytorch实现方法
  9. php迭代器作用,PHP迭代器介绍
  10. Redis 一些高级用法