@@ -375,6 +375,7 @@ static struct tcf_block *tcf_block_create(struct net *net, struct Qdisc *q,
375375 }
376376 INIT_LIST_HEAD (& block -> chain_list );
377377 INIT_LIST_HEAD (& block -> cb_list );
378+ INIT_LIST_HEAD (& block -> owner_list );
378379
379380 /* Create chain 0 by default, it has to be always present. */
380381 chain = tcf_chain_create (block , 0 );
@@ -406,6 +407,65 @@ static struct tcf_chain *tcf_block_chain_zero(struct tcf_block *block)
406407 return list_first_entry (& block -> chain_list , struct tcf_chain , list );
407408}
408409
410+ struct tcf_block_owner_item {
411+ struct list_head list ;
412+ struct Qdisc * q ;
413+ enum tcf_block_binder_type binder_type ;
414+ };
415+
416+ static void
417+ tcf_block_owner_netif_keep_dst (struct tcf_block * block ,
418+ struct Qdisc * q ,
419+ enum tcf_block_binder_type binder_type )
420+ {
421+ if (block -> keep_dst &&
422+ binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS &&
423+ binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_EGRESS )
424+ netif_keep_dst (qdisc_dev (q ));
425+ }
426+
427+ void tcf_block_netif_keep_dst (struct tcf_block * block )
428+ {
429+ struct tcf_block_owner_item * item ;
430+
431+ block -> keep_dst = true;
432+ list_for_each_entry (item , & block -> owner_list , list )
433+ tcf_block_owner_netif_keep_dst (block , item -> q ,
434+ item -> binder_type );
435+ }
436+ EXPORT_SYMBOL (tcf_block_netif_keep_dst );
437+
438+ static int tcf_block_owner_add (struct tcf_block * block ,
439+ struct Qdisc * q ,
440+ enum tcf_block_binder_type binder_type )
441+ {
442+ struct tcf_block_owner_item * item ;
443+
444+ item = kmalloc (sizeof (* item ), GFP_KERNEL );
445+ if (!item )
446+ return - ENOMEM ;
447+ item -> q = q ;
448+ item -> binder_type = binder_type ;
449+ list_add (& item -> list , & block -> owner_list );
450+ return 0 ;
451+ }
452+
453+ static void tcf_block_owner_del (struct tcf_block * block ,
454+ struct Qdisc * q ,
455+ enum tcf_block_binder_type binder_type )
456+ {
457+ struct tcf_block_owner_item * item ;
458+
459+ list_for_each_entry (item , & block -> owner_list , list ) {
460+ if (item -> q == q && item -> binder_type == binder_type ) {
461+ list_del (& item -> list );
462+ kfree (item );
463+ return ;
464+ }
465+ }
466+ WARN_ON (1 );
467+ }
468+
409469int tcf_block_get_ext (struct tcf_block * * p_block , struct Qdisc * q ,
410470 struct tcf_block_ext_info * ei ,
411471 struct netlink_ext_ack * extack )
@@ -435,6 +495,12 @@ int tcf_block_get_ext(struct tcf_block **p_block, struct Qdisc *q,
435495 }
436496 }
437497
498+ err = tcf_block_owner_add (block , q , ei -> binder_type );
499+ if (err )
500+ goto err_block_owner_add ;
501+
502+ tcf_block_owner_netif_keep_dst (block , q , ei -> binder_type );
503+
438504 err = tcf_chain_head_change_cb_add (tcf_block_chain_zero (block ),
439505 ei , extack );
440506 if (err )
@@ -444,6 +510,8 @@ int tcf_block_get_ext(struct tcf_block **p_block, struct Qdisc *q,
444510 return 0 ;
445511
446512err_chain_head_change_cb_add :
513+ tcf_block_owner_del (block , q , ei -> binder_type );
514+ err_block_owner_add :
447515 if (created ) {
448516 if (tcf_block_shared (block ))
449517 tcf_block_remove (block , net );
@@ -489,6 +557,7 @@ void tcf_block_put_ext(struct tcf_block *block, struct Qdisc *q,
489557 if (!block )
490558 return ;
491559 tcf_chain_head_change_cb_del (tcf_block_chain_zero (block ), ei );
560+ tcf_block_owner_del (block , q , ei -> binder_type );
492561
493562 if (-- block -> refcnt == 0 ) {
494563 if (tcf_block_shared (block ))
0 commit comments