TCP/IP协议栈初始化(十) ICMP带来的一段插曲 2
来源:互联网 发布:网络翻译 编辑:程序博客网 时间:2024/06/10 09:28
继续inet_create函数的下半部分。
321 rcu_read_unlock();323 BUG_TRAP(answer_prot->slab != NULL);325 err = -ENOBUFS;326 sk = sk_alloc(net, PF_INET, GFP_KERNEL, answer_prot);327 if (sk == NULL)328 goto out;330 err = 0;331 sk->sk_no_check = answer_no_check;332 if (INET_PROTOSW_REUSE & answer_flags)333 sk->sk_reuse = 1;335 inet = inet_sk(sk);336 inet->is_icsk = (INET_PROTOSW_ICSK & answer_flags) != 0;338 if (SOCK_RAW == sock->type) {339 inet->num = protocol;340 if (IPPROTO_RAW == protocol)341 inet->hdrincl = 1;342 }344 if (ipv4_config.no_pmtu_disc)345 inet->pmtudisc = IP_PMTUDISC_DONT;346 else347 inet->pmtudisc = IP_PMTUDISC_WANT;349 inet->id = 0;351 sock_init_data(sock, sk);353 sk->sk_destruct = inet_sock_destruct;354 sk->sk_family = PF_INET;355 sk->sk_protocol = protocol;356 sk->sk_backlog_rcv = sk->sk_prot->backlog_rcv;358 inet->uc_ttl = -1;359 inet->mc_loop = 1;360 inet->mc_ttl = 1;361 inet->mc_index = 0;362 inet->mc_list = NULL;364 sk_refcnt_debug_inc(sk);366 if (inet->num) {372 inet->sport = htons(inet->num);374 sk->sk_prot->hash(sk);375 }377 if (sk->sk_prot->init) {378 err = sk->sk_prot->init(sk);379 if (err)380 sk_common_release(sk);381 }382 out:383 return err;384 out_rcu_unlock:385 rcu_read_unlock();386 goto out;387 }
321 跟上半部分的rcu lock对应,这里表明已经读完了。可以解锁了。
323 一个指针判断。作为得到的协议,如果已经注册过了,如那么它的slab多半不会是空的,如果是空的,说明没有协议自身没有内存资源,就输出一个警告出来。
325 初始化一个错误码。这个我们不会用到,因为我们都是假设不会出错的,我们的流程都是正常的。:)
326 又来了一个sk_alloc函数。跟上一篇中遇到的sock_alloc,很相像。发现没有,内核中也是满满的套路。对应的是 struct socket与struct sock,善于分析总结的人已经发现了。socket比较长,是面向高层一些的,sock比较短,就是面向低层一些的。同样sock_alloc用于分配struct socket的,而sk_alloc是用来分配struct sock的。
有时候取舍很难,这个函数要不看下呢?看的话,与主线偏离的更远了,写的人一不注意,这成了主线。还是看下吧,毕竟关键的数据结构还没有串联起来。
326 sk = sk_alloc(net, PF_INET, GFP_KERNEL, answer_prot);
先看下,传入的参数。
- net,就是一开始传入的init_net的命名空间。
- PF_INET,表示inet协议子族,这个已经遇到过了。
- GFP_KERNEL,是分配内存时标识,表示我们需要是一般的内核内存。关于它还有许多类似的内存类型标识,有兴趣的可以去看下。
- anser_prot, 就是上回说到的raw_prot。
函数定义在net/core/sock.c中。
929 struct sock *sk_alloc(struct net *net, int family, gfp_t priority,930 struct proto *prot)931 {932 struct sock *sk;934 sk = sk_prot_alloc(prot, priority | __GFP_ZERO, family);935 if (sk) {936 sk->sk_family = family;941 sk->sk_prot = sk->sk_prot_creator = prot;942 sock_lock_init(sk);943 sk->sk_net = get_net(net);944 }946 return sk;947 }
函数很简单,调用sk_prot_alloc分配内存空间。分配到了就初始化一下。sk_prot_alloc更简单,判断协议的slab是不是为空,如果空的话,就从系统中另行分配内存空间。分配的空间的大小,是slab对应的单元的大小,去net/ipv4/raw.c中看下raw_prot定义,发现的它对象大小就是sizeof(struct raw_sock)。
注意到941行,把sk的两个成员变量赋以了传入的prot,这个后面还会遇到。
942,把sk的锁初始化了。
943, 把对net的引用加1。这是Linux中记录对象是否有人使用的方法,当没有人使用时,这个对象占用的资源就可以释放了。
函数执行完了。同样假定得到了一个正常有资源的sk。
回到inet_create函数中。327-334对sk的进行初始化。这当中需要注意以下2点:
answer_no_check其余是赋以了raw_prot对应的在inetsw中元素的no_check标识。这个值为0,表示每次数据包到达时,协议都要自己进行一次校验和计算。
同样answer_flags,是对应是INET_PROTOSW_REUSE。也就是sk要支持复用。这又是为什么呢?别忘记了,我们现在正在创建的是ICMP协议的内核socket,ICMP与IP一起工作,当然要支持复用了。
335, 这个函数仅仅是把struct sock类型转换成了struct inet_sock。为什么能这么转换,因为当在调用sk_prot_alloc生成的sk实例,其实大小是raw_sock,而raw_sock是内含了struct inet_sock,而struct inet_sock又内含了struct sock。可以参考我另一篇《 linux源码-TCP/IP协议栈学习预备(1) 数据结构之各socket之间的关系 》中描述的关系。
336, 我们的ICMP socket是非连接socket,is_icsk被置0。
338-349 完成对inet成员的进一步初始化。
inet->num 给inet socket的本地端口。这里被初始化为协议类型号。也就是IPPROTO_ICMP。我们只是知道系统会保留一些端口号,80留给http协议,并没有听说过会1号端口留给ICMP协议。
341,hdrincl选项用来指示数据中是否包含头部。ICMP是使用的IP协议,数据中包含了IP的包首部。也就收到的raw数据包减去IP的首部长度,剩下的部分才是ICMP协议的报文部分。
344-347,这当中的选项不太清楚,根据源码中注释猜测,是接受用户配置选项,来决定ICMP socket是否支持MTU(Maximum Transmit Unit)的发现机制。
349, 现在还没有开始工作,把记录分片包的数据的变量id置0。
351,进一步初始化sk。别看传入的是sock和sk,几乎全是针对sk的初始化。既然是init_data,多半是接受发送有关的数据结构。主要做了以下事情,具体的内容在遇到时再说下。
初始化三个队列:接受队列,写队列,出错队列。
初始化各个状态变量值
初始化各个锁
继续回到inet_create中。下面一直到364行,进一步初始化sk与协议相关的成员。
366-375 如果有端口号,上面已经看到过被赋1,给inet的源端口赋上,被把sk加入到协议的散列表中。这里的散列表是定义在net/ipv4/raw.c中raw_v4_htable。
377 如果协议自身定义了初始化函数就去执行它。这里我们执行的是来自net/ipv4/raw.c上的raw_init。这个函数只是置0了一个成员变量filter。
至此inet_create执行完成了。我们的ICMP socket从inet层、控制层都准备好了。也是该返回主线的时候了。
- TCP/IP协议栈初始化(十) ICMP带来的一段插曲 2
- TCP/IP协议栈初始化(九) ICMP带来的一段插曲
- TCP/IP 协议栈 ------ ICMP
- 分析TCP/IP协议栈代码之ARP->IP & ICMP->UDP->TCP(STM32-PDF+代码)
- 《TCP/IP详解-协议》(6)ICMP协议
- TCP/IP协议学习(3)-ICMP协议及应用
- TCP/IP协议栈初始化(二) tcp协议的内核表达
- 分析TCP/IP协议栈代码之IP & ICMP(STM32平台)
- TCP/IP/ICMP协议/UDP协议
- TCP/IP协议之ICMP协议
- TCP/IP协议栈初始化(六) 终于见到IP
- TCP/IP详解(六)ICMP:Internet控制报文协议
- TCP/IP(3.5)—网络控制报文协议ICMP
- TCP/IP详解(四)---ICMP:Internet控制报文协议
- TCP/IP illustrated 阅读笔记(六) ICMP协议
- TCP/IP协议栈初始化(四) 向下走,找到IP向上进阶的入口
- TCP/IP协议栈初始化(十一)完结篇-完成IP层与网卡的连接
- TCP/IP协议族学习(三):IP协议、ICMP协议
- Avoid non-default constructors in fragments: use a default constructor plus Fragment#setArguments(Bu
- jQuery中this与$(this)的区别
- APP开发实战146-减少预置图片的方案
- 编写程序阅读一条消息,然后逆序打印出该消息
- Java常用排序算法/程序员必须掌握的8大排序算法
- TCP/IP协议栈初始化(十) ICMP带来的一段插曲 2
- /proc/modules, /sys/module, /proc/devices, /dev
- 虚析构函数、纯虚析构函数、虚构造函数
- C++11新特性(一)
- Python Django学习和实践
- 将博客搬至CSDN
- ZooKeeper安装与部署
- LeetCode 2016 380,42,11,4,438,229,56,312
- 程序技术类基础资料整理