目前在处理盒子产品时,发现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 功能收包时 可以不需要路由逻辑,即可以去掉相关冗余逻辑!!!