linux net子系统-协议层(传输层与网络层)

先来一张协议层的框图
协议层框图


传输层

struct proto

struct tcp_prot位于文件net/ipv4/tcp_ipv4.c

struct proto tcp_prot = {
    .name           = "TCP",
    .owner          = THIS_MODULE,
    .close          = tcp_close,
    .connect        = tcp_v4_connect,
    .disconnect     = tcp_disconnect,
    .accept         = inet_csk_accept,
    .ioctl          = tcp_ioctl,
    .init           = tcp_v4_init_sock,
    .destroy        = tcp_v4_destroy_sock,
    .shutdown       = tcp_shutdown,
    .setsockopt     = tcp_setsockopt,
    .getsockopt     = tcp_getsockopt,
    .recvmsg        = tcp_recvmsg,
    .sendmsg        = tcp_sendmsg,
    .sendpage       = tcp_sendpage,
...
};

tcp_sendmsg

tcp_sendmsg
    //向队列尾添加一个struct sk_buff *skb
    struct sk_buff *skb = tcp_write_queue_tail(sk);
    //并使用sk中的数据初始化这个skb
    skb_add_data_nocache(sk, skb, from, copy);

tcp_init_xmit_timers
    inet_csk_init_xmit_timers(sk, &tcp_write_timer...) => tcp_write_timer
        tcp_write_timer_handler(sk)
            tcp_retransmit_timer(sk)
                //从发送队列取出一块skb进行传输
                struct sk_buff *skb = skb_peek_tail(&sk->sk_write_queue)
                tcp_retransmit_skb(sk, skb...)
                    __tcp_retransmit_skb(sk, skb)
                        tcp_transmit_skb(sk, skb, 1, GFP_ATOMIC)
                            struct inet_connection_sock *icsk = inet_csk(sk);
                            icsk->icsk_af_ops->queue_xmit(skb, ...)

tcp_recvmsg

tcp_recvmsg
    //从接收skb队列中取出一块skb
    struct sk_buff *skb = skb_peek_tail(&sk->sk_receive_queue);
    //将skb中的数据赋值到msg中,供用户空间使用
    skb_copy_datagram_iovec(skb, offset, msg->msg_iov, used);

网络层

struct inet_connection_sock_af_ops

tcp_sendmsg最终调用了结构体icsk_af_ops中queue_xmit来传输队列中的skb,结构体icsk_af_ops是这么来的:

const struct inet_connection_sock_af_ops ipv4_specific = {
    .queue_xmit    = ip_queue_xmit,
    .send_check    = tcp_v4_send_check,
    .rebuild_header    = inet_sk_rebuild_header,
    .sk_rx_dst_set     = inet_sk_rx_dst_set,
    .conn_request      = tcp_v4_conn_request,
    .syn_recv_sock     = tcp_v4_syn_recv_sock,
    .net_header_len    = sizeof(struct iphdr),
    .setsockopt    = ip_setsockopt,
    .getsockopt    = ip_getsockopt,
    .addr2sockaddr     = inet_csk_addr2sockaddr,
    .sockaddr_len      = sizeof(struct sockaddr_in),
    .bind_conflict     = inet_csk_bind_conflict,
};

tcp_v4_init_sock(struct sock *sk)
    struct inet_connection_sock *icsk = inet_csk(sk);
    icsk->icsk_af_ops = &ipv4_specific;

ip_queue_xmit

//dst.output赋值
tcp_v4_conn_request
    inet_csk_route_req
        ip_route_output_flow
            __ip_route_output_key
                __mkroute_output
                    rth->dst.output = ip_output

//使用dsp.output=ip_out来发送数据
ip_queue_xmit
    ip_local_out(skb)
        dst_output(skb)
            skb_dst(skb)->output(skb) ==> ip_out
                ip_finish_output
                    ip_fragment(skb, ip_finish_output2)
                    ip_finish_output2(skb)
                        dst_neigh_output
                            neigh_hh_output
                                dev_queue_xmit(skb)

ip_rcv

//dst.input赋值
tcp_v4_conn_request
    inet_csk_route_req
        ip_route_output_flow
            __ip_route_output_key
                __mkroute_output
                    rth->dst.input = ip_local_deliver

ip_rcv
    ip_rcv_finish
        dst_input(skb)
            skb_dst(skb)->input(skb) ==> ip_local_deliver
                ip_local_deliver_finish
                    //这个handler便是上面struct net_protocol中的handler
                    ipprot->handler(skb)

在上面ip_local_deliver中最终会调用ipprot->handler,这个handler就是之前在net/ipv4/af_inet.c文件中注册的他会将底层接收的skb放到接收skb队列中去。

static const struct net_protocol tcp_protocol = {
    .handler    =   tcp_v4_rcv,
...
};
tcp_v4_rcv(struct sk_buff *skb)
    tcp_v4_do_rcv(sk, skb)
        tcp_rcv_established
            tcp_queue_rcv
                //将底层接收的skb放到接收skb队列中
                __skb_queue_tail(&sk->sk_receive_queue, skb);

然而ip_rcv又是在哪里被调用的?

net/ipv4/af_inet.c
static struct packet_type ip_packet_type __read_mostly = {
...
    .func = ip_rcv,
};

/net/core/dev.c
netif_receive_skb
    __netif_receive_skb(skb)
        __netif_receive_skb_core
            pt_prev->func ⇒ ip_rcv

当底层(数据链路层)ethernet driver收到网络数据包后会调用在net/core/dev.c文件中的函数netif_receive_skb,最终会调用ip_rcv将skb传递给上层使用。


参考文章

  1. 理解 Linux 网络栈(1):Linux 网络协议栈简单总结
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

luckywang1103

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值