SKB路由缓存与SOCK路由缓存1

发送tcp报文时:

nc 10.10.10.2 80

tcp_v4_connect

  1.1--->ip_route_connect

static inline struct rtable *ip_route_connect(struct flowi4 *fl4,
                          __be32 dst, __be32 src, u32 tos,
                          int oif, u8 protocol,
                          __be16 sport, __be16 dport,
                          struct sock *sk)
{
    struct net *net = sock_net(sk);
    struct rtable *rt;

    ip_route_connect_init(fl4, dst, src, tos, oif, protocol,
                  sport, dport, sk);

    if (!dst || !src) {//发包的时候, 制定dst ip;但是src ip没有指定。
        rt = __ip_route_output_key(net, fl4); 查找路由
        if (IS_ERR(rt))
            return rt;
        ip_rt_put(rt);
        flowi4_update_output(fl4, oif, tos, fl4->daddr, fl4->saddr);// 使用路由的daddr saddr
    }
    security_sk_classify_flow(sk, flowi4_to_flowi(fl4));
    return ip_route_output_flow(net, fl4, sk); 然后重新查找路由
}

 

static inline struct rtable *__ip_route_output_key(struct net *net, struct flowi4 *flp)--->return ip_route_output_key_hash(net, flp, NULL);
struct rtable *ip_route_output_key_hash(struct net *net, struct flowi4 *fl4,
                    const struct sk_buff *skb)
{
    __u8 tos = RT_FL_TOS(fl4);
    struct fib_result res = {
        .type        = RTN_UNSPEC,
        .fi        = NULL,
        .table        = NULL,
        .tclassid    = 0,
    };
    struct rtable *rth;

    fl4->flowi4_iif = LOOPBACK_IFINDEX;
    fl4->flowi4_tos = tos & IPTOS_RT_MASK;
    fl4->flowi4_scope = ((tos & RTO_ONLINK) ?
             RT_SCOPE_LINK : RT_SCOPE_UNIVERSE);

    rcu_read_lock();
    rth = ip_route_output_key_hash_rcu(net, fl4, &res, skb);
    rcu_read_unlock();

    return rth;
}

 

 

可以看出:ip_route_connect 一开始只指定了dst ip;但是src ip为空,所以会去查找路由。获取源ip;

在获取到src ip后;会重新路由;重新路由的时候,明显会调用如下逻辑创建route

  1.2 ---->sk_setup_caps(sk, &rt->dst);--->sk_dst_set(sk, dst);也就是:设置SOCK路由缓存

 1.3 设置路由缓存

int __ip_queue_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
            __u8 tos)
{
    struct inet_sock *inet = inet_sk(sk);
    struct net *net = sock_net(sk);
    rt = skb_rtable(skb);
    if (rt)
        goto packet_routed;
    /* Make sure we can route this packet. 
   * 如果输出该数据包的传输控制块中
     * 缓存了输出路由缓存项,则需检测
     * 该路由缓存项是否过期。
     * 如果过期,重新通过输出网络设备、
     * 目的地址、源地址等信息查找输出
     * 路由缓存项。如果查找到对应的路
     * 由缓存项,则将其缓存到传输控制
     * 块中,否则丢弃该数据包。
     * 如果未过期,则直接使用缓存在
     * 传输控制块中的路由缓存项*/
    rt = (struct rtable *)__sk_dst_check(sk, 0);
    if (!rt) {
        __be32 daddr;
        /* Use correct destination address if we have options. */
        daddr = inet->inet_daddr;
        if (inet_opt && inet_opt->opt.srr)
            daddr = inet_opt->opt.faddr;
        sk_setup_caps(sk, &rt->dst);
    }
    skb_dst_set_noref(skb, &rt->dst);/* 将路由设置到skb中 */
packet_routed:

 首先查找SKB路由缓,没有在查找sk 缓存,通设置到skb路由缓存中;

如果sk 缓存  skb缓存都为null;则重新路由;然后设置到sk 以及skb 路由缓存中

 

posted @ 2024-10-14 21:58  codestacklinuxer  阅读(19)  评论(0)    收藏  举报