Linux内核协议栈(附1)inet_create函数注释

本文解析了inet_create函数,详细介绍了如何创建一个INET类型的套接字,包括查找协议、权限检查、内存分配等步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

/*
 *	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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值