欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

linux 网关

程序员文章站 2022-06-03 19:07:39
...
// 调用用户态的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