• IP输入 之 ip_local_deliver && ip_local_deliver_finish


    概述:

    当ip包收上来,查路由,发现是发往本地的数据包时,会调用ip_local_deliver函数;

    ip_local_deliver中对ip分片进行重组,经过LOCAL_IN钩子点,然后调用ip_local_deliver_finish;

    ip_local_deliver_finish函数处理原始套接字的数据接收,并调用上层协议的包接收函数,将数据包传递到传输层;

    以下为源码分析:

     1 /*
     2  *     Deliver IP Packets to the higher protocol layers.
     3  */
     4 int ip_local_deliver(struct sk_buff *skb)
     5 {
     6     /*
     7      *    Reassemble IP fragments.
     8      */
     9     struct net *net = dev_net(skb->dev);
    10 
    11     /* 分片重组 */
    12     if (ip_is_fragment(ip_hdr(skb))) {
    13         if (ip_defrag(net, skb, IP_DEFRAG_LOCAL_DELIVER))
    14             return 0;
    15     }
    16 
    17     /* 经过LOCAL_IN钩子点 */
    18     return NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_IN,
    19                net, NULL, skb, skb->dev, NULL,
    20                ip_local_deliver_finish);
    21 }
     1 static int ip_local_deliver_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
     2 {
     3     /* 去掉ip头 */
     4     __skb_pull(skb, skb_network_header_len(skb));
     5 
     6     rcu_read_lock();
     7     {
     8         /* 获取协议 */
     9         int protocol = ip_hdr(skb)->protocol;
    10         const struct net_protocol *ipprot;
    11         int raw;
    12 
    13     resubmit:
    14         /* 原始套接口,复制一个副本,输出到该套接口 */
    15         raw = raw_local_deliver(skb, protocol);
    16 
    17         /* 获取协议处理结构 */
    18         ipprot = rcu_dereference(inet_protos[protocol]);
    19         if (ipprot) {
    20             int ret;
    21 
    22             if (!ipprot->no_policy) {
    23                 if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
    24                     kfree_skb(skb);
    25                     goto out;
    26                 }
    27                 nf_reset(skb);
    28             }
    29 
    30             /* 协议上层收包处理函数 */
    31             ret = ipprot->handler(skb);
    32             if (ret < 0) {
    33                 protocol = -ret;
    34                 goto resubmit;
    35             }
    36             __IP_INC_STATS(net, IPSTATS_MIB_INDELIVERS);
    37         } 
    38         /* 没有协议接收该数据包 */
    39         else {
    40             /* 原始套接口未接收或接收异常 */
    41             if (!raw) {
    42                 if (xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
    43                     __IP_INC_STATS(net, IPSTATS_MIB_INUNKNOWNPROTOS);
    44                     /* 发送icmp */
    45                     icmp_send(skb, ICMP_DEST_UNREACH,
    46                           ICMP_PROT_UNREACH, 0);
    47                 }
    48                 /* 丢包 */
    49                 kfree_skb(skb);
    50             } 
    51             /* 原始套接口接收 */
    52             else {
    53                 __IP_INC_STATS(net, IPSTATS_MIB_INDELIVERS);
    54                 /* 释放包 */
    55                 consume_skb(skb);
    56             }
    57         }
    58     }
    59  out:
    60     rcu_read_unlock();
    61 
    62     return 0;
    63 }
  • 相关阅读:
    springmvc始终跳转至首页,不报404错误
    c3p0数据库连接池无法连接数据库—错误使用了username关键字
    maven无法下载依赖jar包—几种仓库的区别
    Goland开发工具安装教程
    Go语言代码规范指导
    go语言入门教程:基本语法之变量声明及注意事项
    为什么越来越多的人偏爱go语言
    go语言入门教程:基本语法—常量constant
    go语言入门教程:基本语法之数据类型
    三分钟了解Go语言的前世今生
  • 原文地址:https://www.cnblogs.com/wanpengcoder/p/7603702.html
Copyright © 2020-2023  润新知