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

来源:互联网 发布:微信爬虫拦截域名 编辑:程序博客网 时间:2024/06/03 16:44
/** *  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_tableint    error = 1;struct net *net = sock_net(sk);//得到inet_sockif (!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_portsremaining = (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置0spin_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)];//以本地端口号hashspin_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;}

0 0