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的胖子
  • 相关阅读:
    1105 Spiral Matrix (25分)(蛇形填数)
    1104 Sum of Number Segments (20分)(long double)
    1026 Table Tennis (30分)(模拟)
    1091 Acute Stroke (30分)(bfs,连通块个数统计)
    1095 Cars on Campus (30分)(排序)
    1098 Insertion or Heap Sort (25分)(堆排序和插入排序)
    堆以及堆排序详解
    1089 Insert or Merge (25分)
    1088 Rational Arithmetic (20分)(模拟)
    1086 Tree Traversals Again (25分)(树的重构与遍历)
  • 原文地址:https://www.cnblogs.com/codestack/p/14485868.html
Copyright © 2011-2022 走看看