diff mbox series

[net] tuntap: synchronize through tfiles array instead of tun->numqueues

Message ID 1557199416-55253-1-git-send-email-jasowang@redhat.com
State Superseded
Delegated to: David Miller
Headers show
Series [net] tuntap: synchronize through tfiles array instead of tun->numqueues | expand

Commit Message

Jason Wang May 7, 2019, 3:23 a.m. UTC
When a queue(tfile) is detached through __tun_detach(), we move the
last enabled tfile to the position where detached one sit but don't
NULL out last position. We expect to synchronize the datapath through
tun->numqueues. Unfortunately, this won't work since we're lacking
sufficient mechanism to order or synchronize the access to
tun->numqueues.

To fix this, NULL out the last position during detaching and check
RCU protected tfile against NULL instead of checking tun->numqueues in
datapath.

Cc: YueHaibing <yuehaibing@huawei.com>
Cc: Cong Wang <xiyou.wangcong@gmail.com>
Cc: weiyongjun (A) <weiyongjun1@huawei.com>
Fixes: c8d68e6be1c3b ("tuntap: multiqueue support")
Signed-off-by: Jason Wang <jasowang@redhat.com>
---
 drivers/net/tun.c | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

Comments

Eric Dumazet May 7, 2019, 3:41 a.m. UTC | #1
On 5/6/19 11:23 PM, Jason Wang wrote:
> When a queue(tfile) is detached through __tun_detach(), we move the
> last enabled tfile to the position where detached one sit but don't
> NULL out last position. We expect to synchronize the datapath through
> tun->numqueues. Unfortunately, this won't work since we're lacking
> sufficient mechanism to order or synchronize the access to
> tun->numqueues.
> 
> To fix this, NULL out the last position during detaching and check
> RCU protected tfile against NULL instead of checking tun->numqueues in
> datapath.
> 
> Cc: YueHaibing <yuehaibing@huawei.com>
> Cc: Cong Wang <xiyou.wangcong@gmail.com>
> Cc: weiyongjun (A) <weiyongjun1@huawei.com>
> Fixes: c8d68e6be1c3b ("tuntap: multiqueue support")
> Signed-off-by: Jason Wang <jasowang@redhat.com>
> ---
>  drivers/net/tun.c | 12 +++++++-----
>  1 file changed, 7 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/net/tun.c b/drivers/net/tun.c
> index e9ca1c0..a64c928 100644
> --- a/drivers/net/tun.c
> +++ b/drivers/net/tun.c
> @@ -700,6 +700,8 @@ static void __tun_detach(struct tun_file *tfile, bool clean)
>  				   tun->tfiles[tun->numqueues - 1]);
>  		ntfile = rtnl_dereference(tun->tfiles[index]);
>  		ntfile->queue_index = index;
> +		rcu_assign_pointer(tun->tfiles[tun->numqueues - 1],
> +				   NULL);
>  
>  		--tun->numqueues;
>  		if (clean) {
> @@ -1082,7 +1084,7 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
>  	tfile = rcu_dereference(tun->tfiles[txq]);
>  
>  	/* Drop packet if interface is not attached */
> -	if (txq >= tun->numqueues)
> +	if (!tfile)
>  		goto drop;
>  
>  	if (!rcu_dereference(tun->steering_prog))
> @@ -1306,13 +1308,13 @@ static int tun_xdp_xmit(struct net_device *dev, int n,
>  	rcu_read_lock();
>  
>  	numqueues = READ_ONCE(tun->numqueues);
> -	if (!numqueues) {
> -		rcu_read_unlock();
> -		return -ENXIO; /* Caller will free/return all frames */
> -	}
>  

If you remove the test on (!numqueues),
the following might crash with a divide by zero...

>  	tfile = rcu_dereference(tun->tfiles[smp_processor_id() %
>  					    numqueues]);
Jason Wang May 7, 2019, 3:54 a.m. UTC | #2
On 2019/5/7 上午11:41, Eric Dumazet wrote:
>
> On 5/6/19 11:23 PM, Jason Wang wrote:
>> When a queue(tfile) is detached through __tun_detach(), we move the
>> last enabled tfile to the position where detached one sit but don't
>> NULL out last position. We expect to synchronize the datapath through
>> tun->numqueues. Unfortunately, this won't work since we're lacking
>> sufficient mechanism to order or synchronize the access to
>> tun->numqueues.
>>
>> To fix this, NULL out the last position during detaching and check
>> RCU protected tfile against NULL instead of checking tun->numqueues in
>> datapath.
>>
>> Cc: YueHaibing <yuehaibing@huawei.com>
>> Cc: Cong Wang <xiyou.wangcong@gmail.com>
>> Cc: weiyongjun (A) <weiyongjun1@huawei.com>
>> Fixes: c8d68e6be1c3b ("tuntap: multiqueue support")
>> Signed-off-by: Jason Wang <jasowang@redhat.com>
>> ---
>>   drivers/net/tun.c | 12 +++++++-----
>>   1 file changed, 7 insertions(+), 5 deletions(-)
>>
>> diff --git a/drivers/net/tun.c b/drivers/net/tun.c
>> index e9ca1c0..a64c928 100644
>> --- a/drivers/net/tun.c
>> +++ b/drivers/net/tun.c
>> @@ -700,6 +700,8 @@ static void __tun_detach(struct tun_file *tfile, bool clean)
>>   				   tun->tfiles[tun->numqueues - 1]);
>>   		ntfile = rtnl_dereference(tun->tfiles[index]);
>>   		ntfile->queue_index = index;
>> +		rcu_assign_pointer(tun->tfiles[tun->numqueues - 1],
>> +				   NULL);
>>   
>>   		--tun->numqueues;
>>   		if (clean) {
>> @@ -1082,7 +1084,7 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
>>   	tfile = rcu_dereference(tun->tfiles[txq]);
>>   
>>   	/* Drop packet if interface is not attached */
>> -	if (txq >= tun->numqueues)
>> +	if (!tfile)
>>   		goto drop;
>>   
>>   	if (!rcu_dereference(tun->steering_prog))
>> @@ -1306,13 +1308,13 @@ static int tun_xdp_xmit(struct net_device *dev, int n,
>>   	rcu_read_lock();
>>   
>>   	numqueues = READ_ONCE(tun->numqueues);
>> -	if (!numqueues) {
>> -		rcu_read_unlock();
>> -		return -ENXIO; /* Caller will free/return all frames */
>> -	}
>>   
> If you remove the test on (!numqueues),
> the following might crash with a divide by zero...


Indeed, let me post V2.

Thanks


>
>>   	tfile = rcu_dereference(tun->tfiles[smp_processor_id() %
>>   					    numqueues]);
Eric Dumazet May 7, 2019, 2:47 p.m. UTC | #3
On 5/6/19 11:54 PM, Jason Wang wrote:
> 
> On 2019/5/7 上午11:41, Eric Dumazet wrote:
>>
>>>   
>> If you remove the test on (!numqueues),
>> the following might crash with a divide by zero...
> 
> 
> Indeed, let me post V2.

You probably want to fix tun_ebpf_select_queue() as well.
Jason Wang May 8, 2019, 2:54 a.m. UTC | #4
On 2019/5/7 下午10:47, Eric Dumazet wrote:
>
> On 5/6/19 11:54 PM, Jason Wang wrote:
>> On 2019/5/7 上午11:41, Eric Dumazet wrote:
>>>>    
>>> If you remove the test on (!numqueues),
>>> the following might crash with a divide by zero...
>>
>> Indeed, let me post V2.
> You probably want to fix tun_ebpf_select_queue() as well.
>

Yes, will fix this in V3.

Thanks
diff mbox series

Patch

diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index e9ca1c0..a64c928 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -700,6 +700,8 @@  static void __tun_detach(struct tun_file *tfile, bool clean)
 				   tun->tfiles[tun->numqueues - 1]);
 		ntfile = rtnl_dereference(tun->tfiles[index]);
 		ntfile->queue_index = index;
+		rcu_assign_pointer(tun->tfiles[tun->numqueues - 1],
+				   NULL);
 
 		--tun->numqueues;
 		if (clean) {
@@ -1082,7 +1084,7 @@  static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
 	tfile = rcu_dereference(tun->tfiles[txq]);
 
 	/* Drop packet if interface is not attached */
-	if (txq >= tun->numqueues)
+	if (!tfile)
 		goto drop;
 
 	if (!rcu_dereference(tun->steering_prog))
@@ -1306,13 +1308,13 @@  static int tun_xdp_xmit(struct net_device *dev, int n,
 	rcu_read_lock();
 
 	numqueues = READ_ONCE(tun->numqueues);
-	if (!numqueues) {
-		rcu_read_unlock();
-		return -ENXIO; /* Caller will free/return all frames */
-	}
 
 	tfile = rcu_dereference(tun->tfiles[smp_processor_id() %
 					    numqueues]);
+	if (!tfile) {
+		rcu_read_unlock();
+		return -ENXIO; /* Caller will free/return all frames */
+	}
 
 	spin_lock(&tfile->tx_ring.producer_lock);
 	for (i = 0; i < n; i++) {