linux ip rcv,ip_rcv函数

/*

*         Main IP Receive routine.

*/

int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)

{

struct iphdr *iph;

u32 len;

/*

* When the interface is in promisc mode, drop all the crap

* that it receives, do not try to analyse it.

* 当interface处于混杂模式,那么目的MAC地址是其它主机的数据包也会被网卡收上来,传递给ip_rcv函数.

* 有两个问题:1、其它主机是什么意思?http://blog.csdn.net/nerdx/article/details/12450055,获知是非本机、非广播、非

*     多播的数据帧。2、利用brctl命令可将主机配置成虚拟网桥,由此看来,经过网桥传输的数据包没有到IP层。

*/

if (skb->pkt_type == PACKET_OTHERHOST)

goto drop;

IP_UPD_PO_STATS_BH(dev_net(dev), IPSTATS_MIB_IN, skb->len); //从IPSTATS_MIB_IN的字面意,可知是对接收的IP包信息的统计

/*

*  sk_buff结构有一个users成员,表示当前有users个模块在引用该sk_buff结构实体(注意是sk_buff本身,不包括它的数据缓冲

*  区)。具体谁引用的不需要都明白,至少,当前IPv4模块在引用它.

*

*  为了避免修改sk_buff实例时影响到其它模块,调用skb_share_check函数。它可以说做了三件小事:检查users的值是否等于1;

*  不等于1,则调用skb_clone整一个全新的sk_buff结构(不包括数据缓冲区); 最后,调用kfree_skb函数使得users-1。(当users

*  的值=0时,内存会被释放.)

*  问题:在利用netlink机制与用户态进行通信时,分别调用alloc_skb(不但分配sk_buff本身,还分配了数据缓冲区)、

*        nlmsg_put(放置要发送的数据)、netlink_unicast(发送出去). 因为该skb是自己申请的,本以为在最后需要调用

*        kfree_skb(skb)函数释放skb。结果程序崩溃了,原因由可知,

*          netlink_unicast内部已经释放了该skb.

*  NETfilter的回调函数是不需要释放skb的,即使返回了DROP也一样.

*/

if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {

IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INDISCARDS);

goto out;

}

/*

* pskb_may_pull的实现还是挺复杂的,但是它的目的很简单:确保线性数据缓冲区中有sizeof(struct iphdr))个字节.

* 这牵扯到了sk_buff中数据缓冲区中内容的移动,甚至有可能更换sk-buff的线性缓冲区(如果第二个参数的值大于len-skb_headle             * n + skb->tail - skb->end). skb中缓冲区内容的顺序是:线性缓冲区+skb_shinfo(skb)->frag+skb_shinfo(skb)->frag_list。

* 相当于重新组织了skb的数据缓冲区.

* 该函数的具体实现过程,参见http://blog.chinaunix.net/uid-22577711-id-3220155.html。

* 注意:pskb_may_pull是会修改sk_buff和数据缓冲区的.

*/

if (!pskb_may_pull(skb, sizeof(struct iphdr)))

goto inhdr_error;

iph = ip_hdr(skb);

/*

*        RFC1122: 3.2.1.2 MUST silently discard any IP frame that fails the checksum.

*

*        Is the datagram acceptable?

*

*        1.        Length at least the size of an ip header

*        2.        Version of 4

*        3.        Checksums correctly. [Speed optimisation for later, skip loopback checksums]

*        4.        Doesn't have a bogus length

*/

if (iph->ihl < 5 || iph->version != 4)                 //基本检查

goto inhdr_error;

if (!pskb_may_pull(skb, iph->ihl*4))                 //确保线性缓冲区中有完整的IP报头

goto inhdr_error;

iph = ip_hdr(skb);

/*

* 对IP层校验和进行检查. 等于0是正常的. 否则直接丢弃掉该数据包.

*/

if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl)))

goto inhdr_error;

/*

* skb->len < len : 不可能出现的状况。如果报文是被分段传输过来的, 那么len也只是代表了该分段的大小. 而skb也一定

*                   包含了整个分段的大小.

* len < (iph->ihl*4) :IP报文的tot_len值有问题

*

*/

len = ntohs(iph->tot_len);

if (skb->len < len) {

IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INTRUNCATEDPKTS);

goto drop;

} else if (len < (iph->ihl*4))

goto inhdr_error;

/* Our transport medium may have padded the buffer out. Now we know it

* is IP we can trim to the true length of the frame.

* Note this now means skb->len holds ntohs(iph->tot_len).

* 当传递给L2的载荷太小,数据帧大小小于发送的最小值。那么L2会有填充动作。所以IP报文的大小应该以iph->tot_len为准

* 裁剪的时候也要考虑到是否有非线性缓冲区存在.

*/

if (pskb_trim_rcsum(skb, len)) {

IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INDISCARDS);

goto drop;

}

/* Remove any debris in the socket control block */

memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));         //给cb缓冲区留下一块净土,以后用来存放ip options解析结果

/* Must drop socket now because of tproxy. */

skb_orphan(skb);        //make the @skb unowned, skb->destruct=NULL && skb->sk = NULL

return NF_HOOK(PF_INET, NF_INET_PRE_ROUTING, skb, dev, NULL,

ip_rcv_finish);

inhdr_error:

IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INHDRERRORS);         //统计IP报头有问题的包

drop:

kfree_skb(skb);                 //users-1

out:

return NET_RX_DROP;                //丢弃该报文

}

阅读(1332) | 评论(0) | 转发(0) |

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值