zoukankan      html  css  js  c++  java
  • dst_output发包

    不管是收到报文转发还是本机发送报文,最后都会调用dst_output

    /* Output packet to network from transport.  */
    static inline int dst_output(struct net *net, struct sock *sk, struct sk_buff *skb)
    {
       /*
         * 如果是单播数据包,设置的是ip_output(),
         * 如果是组播数据包,设置的是ip_mc_output().dev_queue_xmit
         */
        return skb_dst(skb)->output(net, sk, skb);
    }

     单播:

    /*
     * 对于单播数据包,目的路由缓存项中的输出接口是ip_output().
     */
    int ip_output(struct net *net, struct sock *sk, struct sk_buff *skb)
    {
    	struct net_device *dev = skb_dst(skb)->dev;
    
    	IP_UPD_PO_STATS(net, IPSTATS_MIB_OUT, skb->len);
    	/*
    	 * 设置数据包的输出网络设备和数据包网络
    	 * 层协议类型。
    	 */
    	skb->dev = dev;
    	skb->protocol = htons(ETH_P_IP);
    /*
    	 * 经netfilter处理后,调用ip_finish_output()继续IP数据包的输出
    	 */
    	return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING,
    			    net, sk, skb, NULL, dev,
    			    ip_finish_output,
    			    !(IPCB(skb)->flags & IPSKB_REROUTED));
    }
    
    static int ip_finish_output(struct net *net, struct sock *sk, struct sk_buff *skb)
    {
    	unsigned int mtu;
    
    #if defined(CONFIG_NETFILTER) && defined(CONFIG_XFRM)
    	/* Policy lookup after SNAT yielded a new policy */
    	if (skb_dst(skb)->xfrm) {
    		IPCB(skb)->flags |= IPSKB_REROUTED;
    		return dst_output(net, sk, skb);
    	}
    #endif
    /*
    //如果不支持TSO或者GSO,tcp发送的时候是按照mss来组织skb的,
    所以skb->len会等于mtu  所以TCP叫分段,和IP分片不一样,只有UDP才有IP分片
    //SKB不是gso类型,并且skb->len大于mtu则需要分片  
    对方接受后的分片重组在netfilter中的ipv4_conntrack_defrag
    */
    	mtu = ip_skb_dst_mtu(sk, skb);
    	if (skb_is_gso(skb))
    		return ip_finish_output_gso(net, sk, skb, mtu);
     /* 如果数据包长度大于MTU,则调用ip_fragment()
    	 * 对IP数据包进行分片。
    	 */
    	if (skb->len > mtu || (IPCB(skb)->flags & IPSKB_FRAG_PMTU))
    		return ip_fragment(net, sk, skb, mtu, ip_finish_output2);
    
    	return ip_finish_output2(net, sk, skb);
    }
    
    /* ip send the packet  by ip_finish_output2*/
    static int ip_finish_output2(struct net *net, struct sock *sk, struct sk_buff *skb)
    {
    	struct dst_entry *dst = skb_dst(skb);
    	struct rtable *rt = (struct rtable *)dst;
    	struct net_device *dev = dst->dev;
    	unsigned int hh_len = LL_RESERVED_SPACE(dev);
    	struct neighbour *neigh;
    	u32 nexthop;
    
    	if (rt->rt_type == RTN_MULTICAST) {
    		IP_UPD_PO_STATS(net, IPSTATS_MIB_OUTMCAST, skb->len);
    	} else if (rt->rt_type == RTN_BROADCAST)
    		IP_UPD_PO_STATS(net, IPSTATS_MIB_OUTBCAST, skb->len);
    
    	/* Be paranoid, rather than too clever. */
    	 /* skb头部空间不能存储链路头 */
    	if (unlikely(skb_headroom(skb) < hh_len && dev->header_ops)) {
    		struct sk_buff *skb2;
    		 /* 重新分配skb */
    		skb2 = skb_realloc_headroom(skb, LL_RESERVED_SPACE(dev));
    		if (!skb2) {
    			kfree_skb(skb);
    			return -ENOMEM;
    		}
    		if (skb->sk)/* 关联控制块 */
    			skb_set_owner_w(skb2, skb->sk);
    		consume_skb(skb); /* 释放skb */
    		skb = skb2; /* 指向新的skb */
    	}
    
    	rcu_read_lock_bh();
    	/* 获取下一跳 */
    	nexthop = (__force u32) rt_nexthop(rt, ip_hdr(skb)->daddr);// get the dst ip address (u32)
    	neigh = __ipv4_neigh_lookup_noref(dev, nexthop); 
    	//根据目的IP查找邻居项是否存在  
    	//如果没有则创建邻居项,然后通过dst_neigh_output  发包
    	if (unlikely(!neigh))
    		neigh = __neigh_create(&arp_tbl, &nexthop, dev, false);
    	if (!IS_ERR(neigh)) {/* 成功 */
    		int res = dst_neigh_output(dst, neigh, skb); /* 通过邻居子系统输出 */
    
    		rcu_read_unlock_bh();
    		return res;
    	}
    	rcu_read_unlock_bh();
    
    	net_dbg_ratelimited("%s: No header cache and no neighbour!\n",
    			    __func__);
    	kfree_skb(skb);
    	return -EINVAL;
    }
    

    最后通过令邻居子系统,调用dev_queue_xmit 将数据报文发送给链路层驱动

    http代理服务器(3-4-7层代理)-网络事件库公共组件、内核kernel驱动 摄像头驱动 tcpip网络协议栈、netfilter、bridge 好像看过!!!! 但行好事 莫问前程 --身高体重180的胖子
  • 相关阅读:
    【git】------git开发过程中的使用流程------
    js原型链的深度理解!
    mvc框架模式
    node环境下express路由,
    前后端 分离及不分离
    node中间件概念
    JS-------DOM0级事件处理和DOM2级事件处理-------简单记法
    call、apply、bind的区别
    移动端Click300毫秒点击延迟
    JS 详解 Cookie、 LocalStorage 与 SessionStorage
  • 原文地址:https://www.cnblogs.com/codestack/p/9292122.html
Copyright © 2011-2022 走看看