2012-09-27 23:29:05 +04:00
# ifndef _NET_GRO_CELLS_H
# define _NET_GRO_CELLS_H
# include <linux/skbuff.h>
# include <linux/slab.h>
# include <linux/netdevice.h>
struct gro_cell {
struct sk_buff_head napi_skbs ;
struct napi_struct napi ;
2015-01-16 21:11:00 +03:00
} ;
2012-09-27 23:29:05 +04:00
struct gro_cells {
2015-01-16 21:11:00 +03:00
struct gro_cell __percpu * cells ;
2012-09-27 23:29:05 +04:00
} ;
static inline void gro_cells_receive ( struct gro_cells * gcells , struct sk_buff * skb )
{
2015-01-16 21:11:00 +03:00
struct gro_cell * cell ;
2012-09-27 23:29:05 +04:00
struct net_device * dev = skb - > dev ;
2015-01-16 21:11:00 +03:00
if ( ! gcells - > cells | | skb_cloned ( skb ) | | ! ( dev - > features & NETIF_F_GRO ) ) {
2012-09-27 23:29:05 +04:00
netif_rx ( skb ) ;
return ;
}
2015-01-16 21:11:00 +03:00
cell = this_cpu_ptr ( gcells - > cells ) ;
2012-09-27 23:29:05 +04:00
if ( skb_queue_len ( & cell - > napi_skbs ) > netdev_max_backlog ) {
atomic_long_inc ( & dev - > rx_dropped ) ;
kfree_skb ( skb ) ;
return ;
}
__skb_queue_tail ( & cell - > napi_skbs , skb ) ;
if ( skb_queue_len ( & cell - > napi_skbs ) = = 1 )
napi_schedule ( & cell - > napi ) ;
}
2015-08-31 23:57:34 +03:00
/* called under BH context */
2012-09-27 23:29:05 +04:00
static inline int gro_cell_poll ( struct napi_struct * napi , int budget )
{
struct gro_cell * cell = container_of ( napi , struct gro_cell , napi ) ;
struct sk_buff * skb ;
int work_done = 0 ;
while ( work_done < budget ) {
2012-12-10 16:32:03 +04:00
skb = __skb_dequeue ( & cell - > napi_skbs ) ;
2012-09-27 23:29:05 +04:00
if ( ! skb )
break ;
napi_gro_receive ( napi , skb ) ;
work_done + + ;
}
if ( work_done < budget )
2015-08-31 23:57:34 +03:00
napi_complete_done ( napi , work_done ) ;
2012-09-27 23:29:05 +04:00
return work_done ;
}
static inline int gro_cells_init ( struct gro_cells * gcells , struct net_device * dev )
{
int i ;
2015-01-16 21:11:00 +03:00
gcells - > cells = alloc_percpu ( struct gro_cell ) ;
2012-09-27 23:29:05 +04:00
if ( ! gcells - > cells )
return - ENOMEM ;
2015-01-16 21:11:00 +03:00
for_each_possible_cpu ( i ) {
struct gro_cell * cell = per_cpu_ptr ( gcells - > cells , i ) ;
2012-09-27 23:29:05 +04:00
2015-08-31 23:57:34 +03:00
__skb_queue_head_init ( & cell - > napi_skbs ) ;
2012-09-27 23:29:05 +04:00
netif_napi_add ( dev , & cell - > napi , gro_cell_poll , 64 ) ;
napi_enable ( & cell - > napi ) ;
}
return 0 ;
}
static inline void gro_cells_destroy ( struct gro_cells * gcells )
{
int i ;
2015-01-16 21:11:00 +03:00
if ( ! gcells - > cells )
2012-09-27 23:29:05 +04:00
return ;
2015-01-16 21:11:00 +03:00
for_each_possible_cpu ( i ) {
struct gro_cell * cell = per_cpu_ptr ( gcells - > cells , i ) ;
2015-08-31 23:57:34 +03:00
2012-09-27 23:29:05 +04:00
netif_napi_del ( & cell - > napi ) ;
2015-08-31 23:57:34 +03:00
__skb_queue_purge ( & cell - > napi_skbs ) ;
2012-09-27 23:29:05 +04:00
}
2015-01-16 21:11:00 +03:00
free_percpu ( gcells - > cells ) ;
2012-09-27 23:29:05 +04:00
gcells - > cells = NULL ;
}
# endif