linux 网关

// 调用用户态的send函数,发送数据 send() { // 进入内核态 sys_send() { __sock_sendmsg() { // 根据参数指定的协议族,调用匹配的相关函数 //如果使用的是PF_INET,函数指针sock->ops->sendmsg // 指向的就是inet_sendmsg。 inet_sendmsg() { //根据参数指定的套接字类型,调用匹配的相关函数 //如果使用的是SOCK_STREAM,函数指针sk->sk_prot-> sendmsg指向的就是tcp_sendmsg tcp_sendmsg() { //它的主要任务是创建sk_buff结构,并将用户态缓存 中的待发送数据拷贝到内核由sk_buff管理的数据区中} //流量控制、拥塞控制、超时重传....,// 构造TCP包的包头 tcp_transmit_skb()// 根据针tp->af_specific->queue_xmit调用IP层的接口函数 // 如果是IPv4,该函数指针指向向ip_queue_xmit函数。 // 如果是IPv6或其它协议,会调用其它函数 ip_queue_xmit() { //查找合适的路由信息,然后构造IP包头 if(没有路由缓存) { //选择路由,设置路由缓存 ip_route_ouput_flow() } } des_output() { //遍历skb->dst->output指针指向该链表,调用相关函数 //完成额外的处理,例如:增加隧道功能、IPSec包头等} ip_finish_output() ip_finish_output2() 调用完该函数,进入数据链路层的邻居子系统 if(以太网包头缓存) { 通过函数指针dst->hh->hh_output调用dev_queue_xmit函数,进入网络设备 层,发送报文. } else { if(下一跳IP地址到MAC地址的映射) { dst->neighbour->output调用neigh_connected_output 函数,直接从映射中获取与下一跳IP地址相对应的MAC 地址,创建以太网包头. neigh_connected_output() } else { 不存在,通过函数指针dst->neighbour->output 调用neigh_resolve_output函数,借助地址解析协议 (如ARP),获得与下一跳IP地址相对应的MAC地址, 创建以太网包头,形成以太网包 neigh_resolve_output(); } dev_queue_xmit() { Qos(); //流量控制 NICDriver(); //网络设备驱动, 驱动硬件,将发送数据出去 } } } } } }/// //报文接收 /// // 2.1 传输层从接收队列sk_receive_queue中获取数据 recv() { sys_recv() { __sock_recvmsg() { //如果是INET协议族,函数指针sock->ops->recvmsg指向 // sock_common_recvmsg sock_common_recvmsg() // 如果是套接字类型是SOCK_STREAM,调用tcp相关的函数 tcp_recvmsg() { 检查sk->sk_receive_queue指针指向的队列中有无数据 } } } } // 2.2 网络层将数据放到sk_receive_queue队列中 net_rx_action() { dev->poll; process_blcklog() { // 根据网卡驱动解析出的以太网包头,再解析出网络层的协议 // 类型,如果是IP协议,调用相关函数ip_rev()函数。 netif_receive_skb() { // 保存的是ip_rev函数 ptype_base[Hash[ETH_P_IP]]->packet_type->func ip_rev() ip_rcv_finish() // 从IP包头中解析出传输层的协议类型,如INET_P_TCP表示 TCP协议。根据协议,调用tcp_v4_rcv() ip_local_deliver_finish() //解析IP包头和TCP包头得到数据,填充sk_buff的sk数据, //将数据添加到sk_receive_queue中。 tcp_v4_rcv()} }}

    推荐阅读