@@ -265,31 +265,66 @@ void tcf_chain_put(struct tcf_chain *chain)
265265}
266266EXPORT_SYMBOL (tcf_chain_put );
267267
268- static void tcf_block_offload_cmd (struct tcf_block * block , struct Qdisc * q ,
269- struct tcf_block_ext_info * ei ,
270- enum tc_block_command command )
268+ static bool tcf_block_offload_in_use (struct tcf_block * block )
269+ {
270+ return block -> offloadcnt ;
271+ }
272+
273+ static int tcf_block_offload_cmd (struct tcf_block * block ,
274+ struct net_device * dev ,
275+ struct tcf_block_ext_info * ei ,
276+ enum tc_block_command command )
271277{
272- struct net_device * dev = q -> dev_queue -> dev ;
273278 struct tc_block_offload bo = {};
274279
275- if (!dev -> netdev_ops -> ndo_setup_tc )
276- return ;
277280 bo .command = command ;
278281 bo .binder_type = ei -> binder_type ;
279282 bo .block = block ;
280- dev -> netdev_ops -> ndo_setup_tc (dev , TC_SETUP_BLOCK , & bo );
283+ return dev -> netdev_ops -> ndo_setup_tc (dev , TC_SETUP_BLOCK , & bo );
281284}
282285
283- static void tcf_block_offload_bind (struct tcf_block * block , struct Qdisc * q ,
284- struct tcf_block_ext_info * ei )
286+ static int tcf_block_offload_bind (struct tcf_block * block , struct Qdisc * q ,
287+ struct tcf_block_ext_info * ei )
285288{
286- tcf_block_offload_cmd (block , q , ei , TC_BLOCK_BIND );
289+ struct net_device * dev = q -> dev_queue -> dev ;
290+ int err ;
291+
292+ if (!dev -> netdev_ops -> ndo_setup_tc )
293+ goto no_offload_dev_inc ;
294+
295+ /* If tc offload feature is disabled and the block we try to bind
296+ * to already has some offloaded filters, forbid to bind.
297+ */
298+ if (!tc_can_offload (dev ) && tcf_block_offload_in_use (block ))
299+ return - EOPNOTSUPP ;
300+
301+ err = tcf_block_offload_cmd (block , dev , ei , TC_BLOCK_BIND );
302+ if (err == - EOPNOTSUPP )
303+ goto no_offload_dev_inc ;
304+ return err ;
305+
306+ no_offload_dev_inc :
307+ if (tcf_block_offload_in_use (block ))
308+ return - EOPNOTSUPP ;
309+ block -> nooffloaddevcnt ++ ;
310+ return 0 ;
287311}
288312
289313static void tcf_block_offload_unbind (struct tcf_block * block , struct Qdisc * q ,
290314 struct tcf_block_ext_info * ei )
291315{
292- tcf_block_offload_cmd (block , q , ei , TC_BLOCK_UNBIND );
316+ struct net_device * dev = q -> dev_queue -> dev ;
317+ int err ;
318+
319+ if (!dev -> netdev_ops -> ndo_setup_tc )
320+ goto no_offload_dev_dec ;
321+ err = tcf_block_offload_cmd (block , dev , ei , TC_BLOCK_UNBIND );
322+ if (err == - EOPNOTSUPP )
323+ goto no_offload_dev_dec ;
324+ return ;
325+
326+ no_offload_dev_dec :
327+ WARN_ON (block -> nooffloaddevcnt -- == 0 );
293328}
294329
295330static int
@@ -502,10 +537,16 @@ int tcf_block_get_ext(struct tcf_block **p_block, struct Qdisc *q,
502537 ei , extack );
503538 if (err )
504539 goto err_chain_head_change_cb_add ;
505- tcf_block_offload_bind (block , q , ei );
540+
541+ err = tcf_block_offload_bind (block , q , ei );
542+ if (err )
543+ goto err_block_offload_bind ;
544+
506545 * p_block = block ;
507546 return 0 ;
508547
548+ err_block_offload_bind :
549+ tcf_chain_head_change_cb_del (tcf_block_chain_zero (block ), ei );
509550err_chain_head_change_cb_add :
510551 tcf_block_owner_del (block , q , ei -> binder_type );
511552err_block_owner_add :
@@ -637,9 +678,16 @@ struct tcf_block_cb *__tcf_block_cb_register(struct tcf_block *block,
637678{
638679 struct tcf_block_cb * block_cb ;
639680
681+ /* At this point, playback of previous block cb calls is not supported,
682+ * so forbid to register to block which already has some offloaded
683+ * filters present.
684+ */
685+ if (tcf_block_offload_in_use (block ))
686+ return ERR_PTR (- EOPNOTSUPP );
687+
640688 block_cb = kzalloc (sizeof (* block_cb ), GFP_KERNEL );
641689 if (!block_cb )
642- return NULL ;
690+ return ERR_PTR ( - ENOMEM ) ;
643691 block_cb -> cb = cb ;
644692 block_cb -> cb_ident = cb_ident ;
645693 block_cb -> cb_priv = cb_priv ;
@@ -655,7 +703,7 @@ int tcf_block_cb_register(struct tcf_block *block,
655703 struct tcf_block_cb * block_cb ;
656704
657705 block_cb = __tcf_block_cb_register (block , cb , cb_ident , cb_priv );
658- return block_cb ? 0 : - ENOMEM ;
706+ return IS_ERR ( block_cb ) ? PTR_ERR ( block_cb ) : 0 ;
659707}
660708EXPORT_SYMBOL (tcf_block_cb_register );
661709
@@ -685,6 +733,10 @@ static int tcf_block_cb_call(struct tcf_block *block, enum tc_setup_type type,
685733 int ok_count = 0 ;
686734 int err ;
687735
736+ /* Make sure all netdevs sharing this block are offload-capable. */
737+ if (block -> nooffloaddevcnt && err_stop )
738+ return - EOPNOTSUPP ;
739+
688740 list_for_each_entry (block_cb , & block -> cb_list , list ) {
689741 err = block_cb -> cb (type , type_data , block_cb -> cb_priv );
690742 if (err ) {
0 commit comments