sock结构体中的入口路由缓存

在sock结构体成员sk_rx_dst中缓存入口路由,目的主要用于early_demux功能,执行一次查找即可找到数据包所属的sock和缓存的路由。


入口路由缓存之TCP

a)作为服务端,三次握手完成时,在函数tcp_v4_syn_recv_sock中创建子sock时赋值;
b)作为客户端在函数tcp_finish_connect;

c)在函数tcp_rcv_established中sock处于established状态时,更新其值;

struct sock *tcp_v4_syn_recv_sock()
{
    newsk = tcp_create_openreq_child(sk, req, skb);
    inet_sk_rx_dst_set(newsk, skb);
}
void tcp_finish_connect()
{
	//IPv4v6两个回调函数inet_sk_rx_dst_set与inet6_sk_rx_dst_set
    if (skb)
        icsk->icsk_af_ops->sk_rx_dst_set(sk, skb);
}
void tcp_rcv_established()
{
    if (unlikely(!sk->sk_rx_dst))
        inet_csk(sk)->icsk_af_ops->sk_rx_dst_set(sk, skb);
}


sk_rx_dst合法判断

在函数tcp_v4_early_demux与tcp_v4_do_rcv中判断sk_rx_dst的合法性,此判断仅在sock状态为TCP_ESTABLISHED时进行。由于作为服务端,会接收到来自于多个接口的客户端请求,所以除需判断缓存路由是否过期外(dst->ops->check(dst, 0)),还需要判断其接口索引(rx_dst_ifindex)是否与此时报文的入接口相同(skb_iif)。两个条件有一个不满足,就释放缓存的路由项。其后会在tcp_rcv_established函数中更新。


int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
{
    struct sock *rsk;

    if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */
        struct dst_entry *dst = sk->sk_rx_dst;

        if (dst) {
            if (inet_sk(sk)->rx_dst_ifindex != skb->skb_iif ||
                dst->ops->check(dst, 0) == NULL) {
                dst_release(dst);
                sk->sk_rx_dst = NULL;
            }
        }
        tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len);
        return 0;
    }
}


入口路由之UDP

UDP不区分客户端或服务端,都于接收报文时,初始化sk_rx_dst缓存,与TCP不同,udp不记录此路由缓存的入接口索引(rx_dst_ifindex),在合法性检查时仅看是否过期(dst_check)。


static void udp_sk_rx_dst_set(struct sock *sk, struct dst_entry *dst)
{
    old = xchg(&sk->sk_rx_dst, dst);
}

void udp_v4_early_demux(struct sk_buff *skb)
{
    dst = READ_ONCE(sk->sk_rx_dst);
    if (dst)
        dst = dst_check(dst, 0);
}

int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
           int proto)
{
    sk = skb_steal_sock(skb);
    if (sk) {
        struct dst_entry *dst = skb_dst(skb);

        if (unlikely(sk->sk_rx_dst != dst))
            udp_sk_rx_dst_set(sk, dst);
    }
}

在__udp4_lib_rcv函数中sk_rx_dst更新判断使用unlikely定义,表明udp路由缓存几乎不更新。


入口路由缓存释放

在用户层应用关闭socket时,于inet层释放缓存的入口路由缓存:


void inet_sock_destruct(struct sock *sk)
{
    dst_release(sk->sk_rx_dst);
}


内核版本

linux-3.10.0



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值