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()
}
}
}
上一篇: 网关
下一篇: 为什么没有更多的开发者使用Flex