zoukankan      html  css  js  c++  java
  • 盒子设备接口收发包的思考1

      目前在处理盒子产品时,发现wan口和lan口收发报文时还在走内核路由逻辑,因为从wan口进来的包如果转发只能从lan口转发出去,所以此时路由查找是个多余动作!!此处应该是一个可以优化点,来试一试吧!!mark,也不想不通为啥一个产品这么多年都没有人去思考这些!!!

      工作中还是要多想一想为什么?不要随波逐流的接受!! 思考内在的原因,说不定这些看起来正确的东西实际上是错误!最起码在目前场景下是错误的!!

    收包:

     

    //从这里进入L4传输层
    /*
     * ip_local_deliver_finish()将输入数据包从网络层传递
     * 到传输层。过程如下:
     * 1)首先,在数据包传递给传输层之前,去掉IP首部
     * 2)接着,如果是RAW套接字接收数据包,则需要
     * 复制一份副本,输入到接收该数据包的套接字。
     * 3)最后,通过传输层的接收例程,将数据包传递
     * 到传输层,由传输层进行处理。
     */
     /* 
     ip 层处理报文过程中,回复制一份报文到raw_socket中去;有的是IPPROTO_TCP/IPPROTO_RAW
     当 socket(AF_INET, SOCK_RAW, IPPROTO_RAW)时,它会接收所有协议的数据包,并且
    IP_HDRINCL 是默认打开的,即是说应用层要提供 L3 和 L4 层的头。再如,如果是
    IPPROTO_TCP 时,它只接收到 TCP 包。而 IP_HDRINCL 是默认不打开的,即系统会处理 L3
    的头部
    */
    static int ip_local_deliver_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
    {
    /*
         * 在数据包传递给传输层之前,先去掉
         * IP首部。
         */
        __skb_pull(skb, skb_network_header_len(skb));
    
        rcu_read_lock();
        {
            int protocol = ip_hdr(skb)->protocol;
            const struct net_protocol *ipprot;
            int raw;
    /*
             * 处理RAW套接字,先根据传输层协议号
             * 得到哈希值,然后查看raw_v4_htable散列表
             * 中以该值为关键字的哈希桶是否为空,
             * 如果不为空,则说明创建了RAW套接字,
             * 复制该数据包的副本输入到注册到
             * 该桶中的所有套接字。
             */
             /*
    ip_local_deliver_finish函数会先检查哈希表raw_v4_htable。
    因为在创建 socket时,inet_create会把协议号IPPROTO_ICMP的值赋给socket的成员num,
    并以num为键值,把socket存入哈 项表raw_v4_htable?瑀aw_v4_htable[IPPROTO_ICMP&(MAX_INET_PROTOS-1)]上即存放了 这个socket,实际上是一个socket的链表,
    如果其它还有socket要处理这个回显应答,也会被放到这里,组成一个链 表,
    ip_local_deliver_finish收到数据报后,取出这个socket链表(目前实际上只有一项),
    调用raw_v4_input,把 skb交给每一个socket进行处理。
    然后,还需要把数据报交给inet_protos[IPPROTO_ICMP& (MAX_INET_PROTOS-1)],即icmp_rcv处理,
    因为对于icmp报文,每一个都是需要经过协议栈处理的,
    但对回显应 答,icmp_rcv只是简单丢弃,并未实际处理。
    */
        resubmit:
        //之前开巨帧的时候,icmp不通就是在这里面的函数中sock_queue_rcv_skb丢的
            raw = raw_local_deliver(skb, protocol);
    //如果是raw套接字,则则该函数里面会复制一份skb,然后送到  ,例如用ping 1.2.2.2的时候,会走这里面,不会走icmp_recv*/
            ipprot = rcu_dereference(inet_protos[protocol]);
            if (ipprot) {
                int ret;
    /*
             * 通过查找inet_portos数组,确定是否
             * 注册了与IP首部中传输层协议号
             * 一致的传输层协议。若查找命中,
             * 则执行对应的传输层协议例程。
             */
                if (!ipprot->no_policy) {
                    if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
                        kfree_skb(skb);
                        goto out;
                    }
                    nf_reset(skb);
                }
                ret = ipprot->handler(skb);//这里面会进入udp tcp传输层
                if (ret < 0) {
                    protocol = -ret;
                    goto resubmit;
                }
                __IP_INC_STATS(net, IPSTATS_MIB_INDELIVERS);
            } else {
                if (!raw) {
                    /*
                 * 如果没有响应的协议传输层接收该数据包,
                 * 则释放该数据包。在释放前,如果是RAW
                 * 套接字没有接收或接收异常,则还需产生
                 * 一个目的不可达ICMP报文给发送方。表示该包raw没有接收并且inet_protos中没有注册该协议
                 */
                    if (xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
                        __IP_INC_STATS(net, IPSTATS_MIB_INUNKNOWNPROTOS);
                        icmp_send(skb, ICMP_DEST_UNREACH,
                              ICMP_PROT_UNREACH, 0);
                    }
                    kfree_skb(skb);
                } else {
                    __IP_INC_STATS(net, IPSTATS_MIB_INDELIVERS);
                    consume_skb(skb);
                }
            }
        }
     out:
        rcu_read_unlock();
    
        return 0;
    }

    可以看到:ip_rcv_finish ip_local_deliver_finish 涉及到路由的逻辑主要是:

    • 检测是否可以使用early_demux
    • 检测skb的路由缓存是否存在,没有则通过路由来查找
    • 根据查找的路由是否deliver_to_stack 还是forward_out

    对于此时产品下:可以判定的是报文肯定会上tcp/ip协议栈,所以对transparent 流量,我们可以直接简单的忽略掉路由系统,直接上传报文到协议栈!!!

    对于tcp L4来说 不会涉及到路由功能;

    所以:可知对于tproxy 功能收包时 可以不需要路由逻辑,即可以去掉相关冗余逻辑!!!

    http代理服务器(3-4-7层代理)-网络事件库公共组件、内核kernel驱动 摄像头驱动 tcpip网络协议栈、netfilter、bridge 好像看过!!!! 但行好事 莫问前程 --身高体重180的胖子
  • 相关阅读:
    基于NFS实现多WEB服务器负载均衡
    CentOS 6编译安装lamp,并分别安装event模块方式和FPM方式的PHP
    CentOS 7 下的LAMP实现以及基于https的虚拟主机
    ssh 免密码设置失败原因总结
    任督二脉之进程管理(3)
    任督二脉之进程管理(4)
    任督二脉之进程管理(1)
    任督二脉之进程管理(2)
    VIRTIO概述和基本原理
    图解 TCMalloc
  • 原文地址:https://www.cnblogs.com/codestack/p/14485868.html
Copyright © 2011-2022 走看看