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()
       
       
    }
  }
  
}

你可能感兴趣的:(LINUX)