用户态在创建了套接字后,接下来就调用bind函数,绑定套接字,而PF_RING实际做的就是为RING分配相应的空间。也就是说,一个套接字,都有一个与之对应的RING。在前面我们已经提到 sock->ops = &ring_ops;这样当应用空间调用bind函数中,内核调用ring_bind函数;即当系统调用bind触发时,内核ring_bind函数就触发了。下面讲解ring_bind函数;
/* Bind to a device */
static int ring_bind(struct socket*sock, struct sockaddr *sa, int addr_len)
{
struct sock *sk = sock->sk;
if(enable_debug)
printk("[PF_RING] ring_bind() called\n");
/*
* Check legality
*/
if(addr_len != sizeof(struct sockaddr))
return -EINVAL;
if(sa->sa_family != PF_RING)
return -EINVAL;
if(sa->sa_data == NULL)
return -EINVAL;
/* Safety check: add trailing zero if missing*/
sa->sa_data[sizeof(sa->sa_data) - 1] = '\0';
if(enable_debug)
printk("[PF_RING] searching device %s\n", sa->sa_data);
#if 0
if(strcmp(sa->sa_data, "any") == 0)
dev = &any_dev;
else {
if((dev = __dev_get_by_name(
#if(LINUX_VERSION_CODE >=KERNEL_VERSION(2,6,24))
&init_net,
#endif
sa->sa_data))== NULL) {
if(enable_debug)
printk("[PF_RING]search failed\n");
return(-EINVAL);
}
}
#endif
return(packet_ring_bind(sk,sa->sa_data));
}
ring_bind 函数前面都是一系列的判断,主要起作用的还是packet_ring_bind函数,函数定义如下:
static int packet_ring_bind(structsock *sk, char *dev_name)
{
struct pf_ring_socket *pfr = ring_sk(sk);
struct list_head *ptr, *tmp_ptr;
ring_device_element *dev = NULL;
if(dev_name == NULL)
return(-EINVAL);
list_for_each_safe(ptr, tmp_ptr, &ring_aware_device_list) {
ring_device_element *dev_ptr = list_entry(ptr, ring_device_element,device_list);
if(strcmp(dev_ptr->dev->name, dev_name) == 0) {
dev = dev_ptr;
break;
}
}
if((dev == NULL) || (dev->dev->type != ARPHRD_ETHER))
return(-EINVAL);
if(enable_debug)
printk("[PF_RING] packet_ring_bind(%s, bucket_len=%d)called\n",
dev->dev->name, pfr->bucket_len);
/* Remove old binding (by default binding tonone)
BEFORE binding to a new device
*/
ring_proc_remove(pfr);
/*
IMPORTANT
Leave this statementhere as last one. In fact when
the ring_netdev != &none_device_elementthe socket is ready to be used.
*/
pfr->ring_netdev = dev;
/* Timeto rebind to a new device */
ring_proc_add(pfr);
/*As the 'struct net_device' does not containthe number
of RX queues, we can guess that its numberis the same as the number
of TX queues. After the first packet hasbeen received by the adapter
the num of RX queues is updated with thereal value
*/
#if(LINUX_VERSION_CODE >=KERNEL_VERSION(2,6,31))
pfr->num_rx_channels =pfr->ring_netdev->dev->real_num_tx_queues;
#else
pfr->num_rx_channels = 1;
#endif
if(dev == &any_device_element)
num_any_rings++;
else {
if(dev->dev->ifindex < MAX_NUM_IFIDX)
num_rings_per_device[dev->dev->ifindex]++;
else
printk("[PF_RING] INTERNAL ERROR:ifindex %d for %s is > than MAX_NUM_IFIDX\n",
dev->dev->ifindex, dev->dev->name);
}
return(0);
}
这个函数的主要作用是创建一个环状缓冲区的socket,然后对socket进行绑定。