Linux内核协议栈(附3)udp_lib_get_port函数

/**
 *  udp_lib_get_port  -  UDP/-Lite port lookup for IPv4 and IPv6
 *
 *  @sk:          socket struct in question
 *  @snum:        port number to look up
 *  @saddr_comp:  AF-dependent comparison of bound local IP addresses
 */
int udp_lib_get_port(struct sock *sk, unsigned short snum,
		       int (*saddr_comp)(const struct sock *sk1,
					 const struct sock *sk2))
{
	struct udp_hslot *hslot;
	struct udp_table *udptable = sk->sk_prot->h.udp_table; /**/udp_table
	int    error = 1;
	struct net *net = sock_net(sk);//得到inet_sock

	if (!snum) {//--------------------------------------------------如果是0,表示要系统分配
		int low, high, remaining;
		unsigned rand;
		unsigned short first, last;
		DECLARE_BITMAP(bitmap, PORTS_PER_CHAIN);//--------------65535/128-------定义一个数组

		inet_get_local_port_range(&low, &high);//端口范围sysctl_local_ports
		remaining = (high - low) + 1;

		rand = net_random();
		first = (((u64)rand * remaining) >> 32) + low;//得到一个随机的端口
		/*
		 * force rand to be an odd multiple of UDP_HTABLE_SIZE
		 */
		rand = (rand | 1) * UDP_HTABLE_SIZE;//rand最后处理成哈希表大小的奇数倍,因为奇数+奇数=偶数,而偶数+偶数=偶数,强制为奇数,可以保证链表中所有值被访问
		
		for (last = first + UDP_HTABLE_SIZE; first != last; first++) {
			hslot = &udptable->hash[udp_hashfn(net, first)];//---------------->得到128项中的一项,hash公式可简写为num&mask。即本地端口对udptable大小取模
			
			bitmap_zero(bitmap, PORTS_PER_CHAIN);//bitmap置0
			
			spin_lock_bh(&hslot->lock);
			
			udp_lib_lport_inuse(net, snum, hslot, bitmap, sk,
					    saddr_comp);

			snum = first;
			/*
			 * Iterate on all possible values of snum for this hash.
			 * Using steps of an odd multiple of UDP_HTABLE_SIZE
			 * give us randomization and full range coverage.
			 *
			 *使用first值作为端口号,从udptable的hash表中找到hslot项,重置bitmap数组全0,调用函数udp_lib_lport_inuse()遍历hslot项的所有表项,将所有已经使用的sport对应于bitmap的位置置1。
			 */
			do {
				if (low <= snum && snum <= high &&
				    !test_bit(snum / UDP_HTABLE_SIZE, bitmap))
					goto found;//------------------------------------------------>如果对应的位没有置1,说明没有被使用,即找到了
				snum += rand;//哈希表大小的奇数倍UDP_HTABLE_SIZE,这样还在这个链表中找
			} while (snum != first);
			spin_unlock_bh(&hslot->lock);
		}
		goto fail;
	} else {
		hslot = &udptable->hash[udp_hashfn(net, snum)];//以本地端口号hash
		spin_lock_bh(&hslot->lock);
		if (udp_lib_lport_inuse(net, snum, hslot, NULL, sk, saddr_comp))//------------------------------------------------------>判断端口是否被占用
			goto fail_unlock;
	}
found:
	inet_sk(sk)->num = snum;//设置端口
	sk->sk_hash = snum;
	if (sk_unhashed(sk)) {
		sk_nulls_add_node_rcu(sk, &hslot->head);//将sk添加到hash表中
		sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
	}
	error = 0;
fail_unlock:
	spin_unlock_bh(&hslot->lock);
fail:
	return error;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值