浅析ethx网卡发送函数sys_write简易流程
sys_write= > vfs_write= > do_sync_write= >
filp- > f_op- > aio_write( & kiocb, & iov, 1, kiocb. ki_pos) ;
{ 也就是对应socket_file_ops中的sock_aio_write}
sock_aio_write= > do_sock_write= > __sock_sendmsg= >
sock- > ops- > sendmsg ( iocb, sock, msg, size) ;
{ 也就是对应inetsw_array[ ] 中的inet_stream_ops下的tcp_sendmsg}
tcp_sendmsg= > 经过skb拷贝之后, 最终在退出之前调用tcp_push, 将数据发送到网络= >
tcp_push= > __tcp_push_pending_frames= > tcp_write_xmit= > tcp_transmit_skb= >
icsk- > icsk_af_ops- > queue_xmit( skb, 0) ;
/*
在tcp_v4_init_sock中初始化的如下方法:
icsk->icsk_af_ops = &ipv4_specific;
icsk->icsk_ca_ops = &tcp_init_congestion_ops;
tp->reordering = sysctl_tcp_reordering;
sk->sk_write_space = sk_stream_write_space;
icsk->icsk_sync_mss = tcp_sync_mss;
tp->af_specific = &tcp_sock_ipv4_specific;
所以icsk_af_ops就是ipv4_specific,
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,
.conn_request = tcp_v4_conn_request,
.syn_recv_sock = tcp_v4_syn_recv_sock,
.remember_stamp = tcp_v4_remember_stamp,
.net_header_len = sizeof(struct iphdr),
.setsockopt = ip_setsockopt,
.getsockopt = ip_getsockopt,
.addr2sockaddr = inet_csk_addr2sockaddr,
.sockaddr_len = sizeof(struct sockaddr_in),
#ifdef CONFIG_COMPAT
.compat_setsockopt = compat_ip_setsockopt,
.compat_getsockopt = compat_ip_getsockopt,
#endif
};
*/
ip_queue_xmit= >
return NF_HOOK( PF_INET , NF_IP_LOCAL_OUT, skb, NULL , rt- > u. dst. dev,
dst_output) ;
也就是调用dst_output将package发送到网络中出去.
/* Output packet to network from transport. */
static inline int dst_output( struct sk_buff * skb)
{
return skb- > dst- > output( skb) ;
}
__mkroute_output= > dst_alloc= >
rth = dst_alloc( & ipv4_dst_ops) ; 然后dst- > ops = ipv4_dst_ops;
rth- > u. dst. output= ip_output;
ip_output= >
return NF_HOOK_COND( PF_INET , NF_IP_POST_ROUTING, skb, NULL , dev,
ip_finish_output,
! ( IPCB( skb) - > flags & IPSKB_REROUTED) ) ;
ip_finish_output= > ip_finish_output2= >
/*
if (dst->hh)
return neigh_hh_output(dst->hh, skb);
else if (dst->neighbour)
return dst->neighbour->output(skb);
*/
/*
static struct neigh_ops arp_generic_ops = {
.family = AF_INET,
.solicit = arp_solicit,
.error_report = arp_error_report,
.output = neigh_resolve_output,
.connected_output = neigh_connected_output,
.hh_output = dev_queue_xmit,
.queue_xmit = dev_queue_xmit,
};
static struct neigh_ops arp_hh_ops = {
.family = AF_INET,
.solicit = arp_solicit,
.error_report = arp_error_report,
.output = neigh_resolve_output,
.connected_output = neigh_resolve_output,
.hh_output = dev_queue_xmit,
.queue_xmit = dev_queue_xmit,
};
static struct neigh_ops arp_direct_ops = {
.family = AF_INET,
.output = dev_queue_xmit,
.connected_output = dev_queue_xmit,
.hh_output = dev_queue_xmit,
.queue_xmit = dev_queue_xmit,
};
struct neigh_ops arp_broken_ops = {
.family = AF_INET,
.solicit = arp_solicit,
.error_report = arp_error_report,
.output = neigh_compat_output,
.connected_output = neigh_compat_output,
.hh_output = dev_queue_xmit,
.queue_xmit = dev_queue_xmit,
};
*/
因为ip通信都是以arp开始来获取通信对端的mac地址, 所以arp应该是网络通信的第一步,
这样就调用到了dev_queue_xmit( ) 想物理网卡发送网络数据包,
dev_queue_xmit= > dev_hard_start_xmit= >
return dev- > hard_start_xmit( skb, dev) ;
就是网卡驱动的发送函数wlan_hard_start_xmit, 比较粗糙, 凑活着看吧【gliethttp. Leith】
看看sys_socket( ) 对空间结构的申请步骤:
sk- > sk_prot = tcp_prot;
他的. obj_size = sizeof ( struct tcp_sock) , 所以
struct tcp_sock {
/* inet_connection_sock has to be the first member of tcp_sock */
struct inet_connection_sock inet_conn;
. . .
}
struct inet_connection_sock {
/* inet_sock has to be the first member! */
struct inet_sock icsk_inet;
. . .
}
struct inet_sock {
/* sk and pinet6 has to be the first two members of inet_sock */
struct sock sk;
. . .
}
所以sk_alloc申请到的sk, 指向的是tcp_sock下inet_connection_sock下inet_sock中的sk,
然后
__sock_create= >
pf- > create( net, sock, protocol) ;
inet_create= >
sk- > sk_prot- > init( sk) 也就是调用tcp_prot的init, 也就是tcp_v4_init_sock【gliethttp. Leith】.