/**
* 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;
}
Linux内核协议栈(附3)udp_lib_get_port函数
最新推荐文章于 2023-02-03 17:44:58 发布