Linux解析内核源代码——传输控制块诞生

原创文章是freas_1990,转载请注明出处:http://blog.csdn.net/freas_1990/article/details/23795587


在Linux 2.6一旦(不包含2.6,对于更详细的调查是不是版本号),控制块的概念,各种协议的状态管理还出于比較混乱的状态。

Linux 2.6以后。传输控制块机制使代码看起来比較规整了。

创建传输控制块:

/*
 *	Create an inet socket.
 */

static int inet_create(struct socket *sock, int protocol)
{
	struct sock *sk;
	struct list_head *p;
	struct inet_protosw *answer;
	struct inet_opt *inet;
	int err = -ENOBUFS;

	sock->state = SS_UNCONNECTED;
	sk = sk_alloc(PF_INET, GFP_KERNEL, inet_sk_size(protocol),
		      inet_sk_slab(protocol));
	if (!sk)
		goto out;

	/* Look for the requested type/protocol pair. */
	answer = NULL;
	rcu_read_lock();
	list_for_each_rcu(p, &inetsw[sock->type]) {
		answer = list_entry(p, struct inet_protosw, list);

		/* Check the non-wild match. */
		if (protocol == answer->protocol) {
			if (protocol != IPPROTO_IP)
				break;
		} else {
			/* Check for the two wild cases. */
			if (IPPROTO_IP == protocol) {
				protocol = answer->protocol;
				break;
			}
			if (IPPROTO_IP == answer->protocol)
				break;
		}
		answer = NULL;
	}

	err = -ESOCKTNOSUPPORT;
	if (!answer)
		goto out_sk_free;
	err = -EPERM;
	if (answer->capability > 0 && !capable(answer->capability))
		goto out_sk_free;
	err = -EPROTONOSUPPORT;
	if (!protocol)
		goto out_sk_free;
	err = 0;
	sock->ops = answer->ops;
	sk->sk_prot = answer->prot;
	sk->sk_no_check = answer->no_check;
	if (INET_PROTOSW_REUSE & answer->flags)
		sk->sk_reuse = 1;
	rcu_read_unlock();

	inet = inet_sk(sk);

	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_set_owner(sk, THIS_MODULE);

	sk->sk_destruct	   = inet_sock_destruct;
	sk->sk_zapped	   = 0;
	sk->sk_family	   = PF_INET;
	sk->sk_protocol	   = protocol;
	sk->sk_backlog_rcv = sk->sk_prot->backlog_rcv;

	inet->uc_ttl	= -1;
	inet->mc_loop	= 1;
	inet->mc_ttl	= 1;
	inet->mc_index	= 0;
	inet->mc_list	= NULL;

#ifdef INET_REFCNT_DEBUG
	atomic_inc(&inet_sock_nr);
#endif

	if (inet->num) {
		/* 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. */
		sk->sk_prot->hash(sk);
	}

	if (sk->sk_prot->init) {
		err = sk->sk_prot->init(sk);
		if (err)
			inet_sock_release(sk);
	}
out:
	return err;
out_sk_free:
	rcu_read_unlock();
	sk_free(sk);
	goto out;
}

这里的sk_alloc是重点:

sk = sk_alloc(PF_INET, GFP_KERNEL, inet_sk_size(protocol),
		      inet_sk_slab(protocol));

inet_sk_size定义例如以下:

static __inline__ int inet_sk_size(int protocol)
{
	int rc = sizeof(struct tcp_sock);

	if (protocol == IPPROTO_UDP)
		rc = sizeof(struct udp_sock);
	else if (protocol == IPPROTO_RAW)
		rc = sizeof(struct raw_sock);
	return rc;
}

它会依据详细的传输层协议定义返回对应的传输控制块的大小。

在socket里,sock指针仅仅是一个“泛型”,它可能指向struct sock,struct tcp_sock,struct udp_sock,根据该协议的细节。

版权声明:本文博客原创文章,博客,未经同意,不得转载。

posted @ 2015-08-06 17:45  blfshiye  阅读(273)  评论(0编辑  收藏  举报