/*
* Create an inet socket.------->建立一个inet类型的套接字
*/
//sock
//__sock_create
static int inet_create(struct net *net, struct socket *sock, int protocol)
{
struct sock *sk; //INET地址族为上层提供的一个抽象
struct inet_protosw *answer; //协议的socket接口
struct inet_sock *inet; //代表INET地址族的 socket
struct proto *answer_prot;
unsigned char answer_flags;
char answer_no_check;
int try_loading_module = 0;
int err;
if (unlikely(!inet_ehash_secret))
if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM)
build_ehash_secret();
sock->state = SS_UNCONNECTED;
/* Look for the requested type/protocol pair. */
lookup_protocol:
err = -ESOCKTNOSUPPORT;
rcu_read_lock();
list_for_each_entry_rcu(answer, &inetsw[sock->type], list) {
err = 0;
/* Check the non-wild match. */
if (protocol == answer->protocol) {//--------------<SOCK_RAW,IPPROTO_IP>会走这里,但是不会break,导致 err = -EPROTONOSUPPORT;执行
if (protocol != IPPROTO_IP)
break;
} else {
/* Check for the two wild cases. */
//在ifconfig 应用程序中走这个分支
if (IPPROTO_IP == protocol) {
protocol = answer->protocol;
break;
}
//在ping 这种应用(后面章节会介绍)中走这个分支,传入的protocol 为ICMP(1),而且,如果你使用<SOCK_RAW, OSPF(89)>的组合时也会走这个分支,即使用IP 层数据传输。
if (IPPROTO_IP == answer->protocol)
break;
}
err = -EPROTONOSUPPORT;
}
if (unlikely(err)) {
if (try_loading_module < 2) {
rcu_read_unlock();
/*
* Be more specific, e.g. net-pf-2-proto-132-type-1
* (net-pf-PF_INET-proto-IPPROTO_SCTP-type-SOCK_STREAM)
*/
if (++try_loading_module == 1)
request_module("net-pf-%d-proto-%d-type-%d",
PF_INET, protocol, sock->type);
/*
* Fall back to generic, e.g. net-pf-2-proto-132
* (net-pf-PF_INET-proto-IPPROTO_SCTP)
*/
else
request_module("net-pf-%d-proto-%d",
PF_INET, protocol);
goto lookup_protocol;
} else
goto out_rcu_unlock;
}
/**/inet_init
err = -EPERM;
if (answer->capability > 0 && !capable(answer->capability))
goto out_rcu_unlock;
err = -EAFNOSUPPORT;
if (!inet_netns_ok(net, protocol))
goto out_rcu_unlock;
sock->ops = answer->ops;//特定协议的操作函数集,声明在net.h
answer_prot = answer->prot;//INET层协议描述块
answer_no_check = answer->no_check;/**/inetsw_array
answer_flags = answer->flags;
rcu_read_unlock();
WARN_ON(answer_prot->slab == NULL);
err = -ENOBUFS;
sk = sk_alloc(net, PF_INET, GFP_KERNEL, answer_prot);//-------->对应于tcp,是从tcp cache中分配的,构建对应网络层的sock,
if (sk == NULL)
goto out;
err = 0;
sk->sk_no_check = answer_no_check;
if (INET_PROTOSW_REUSE & answer_flags)
sk->sk_reuse = 1;
inet = inet_sk(sk);//强制转换为inet_sock----->对于tcp,tcp_sock包含inet_connection_sock --> inet_connection_sock包含inet_sock --> inet_sock包含sock,而分配是从协议高速cache中分配的
inet->is_icsk = (INET_PROTOSW_ICSK & answer_flags) != 0;
if (SOCK_RAW == sock->type) {
inet->num = protocol;
if (IPPROTO_RAW == protocol)
inet->hdrincl = 1;
}
if (ipv4_config.no_pmtu_disc)
inet->pmtudisc = IP_PMTUDISC_DONT;
else
inet->pmtudisc = IP_PMTUDISC_WANT;
inet->id = 0;
sock_init_data(sock, sk);
sk->sk_destruct = inet_sock_destruct;
sk->sk_protocol = protocol;//-------------对于ping,IPPROTO_ICMP
sk->sk_backlog_rcv = sk->sk_prot->backlog_rcv;
inet->uc_ttl = -1;
inet->mc_loop = 1;
inet->mc_ttl = 1;
inet->mc_all = 1;
inet->mc_index = 0;
inet->mc_list = NULL;
sk_refcnt_debug_inc(sk);
if (inet->num) { //建立socket的时候是没有的,所以不会执行
/* It assumes that any protocol which allows
* the user to assign a number at socket
* creation time automatically
* shares.
*/
inet->sport = htons(inet->num);
/* Add to protocol hash chains. */ inetsw_array
sk->sk_prot->hash(sk);//----------------------->将sk添加到相应协议的哈希表中,在udp中该函数是不能被调用的
}
//执行协议相关的初始化函数
if (sk->sk_prot->init) {
err = sk->sk_prot->init(sk); /**/tcp_v4_init_sock tcp_prot inetsw_array
if (err)
sk_common_release(sk);
}
out:
return err;
out_rcu_unlock:
rcu_read_unlock();
goto out;
}
Linux内核协议栈(附1)inet_create函数注释
最新推荐文章于 2023-07-06 14:51:46 发布