Thu, Jul 26, 2018 at 09:59:30PM CEST, jakub.kicin...@netronome.com wrote:
>On Thu, 26 Jul 2018 18:31:01 +0200, Jiri Pirko wrote:
>> From: Jiri Pirko <j...@mellanox.com>
>> 
>> In case a chain is empty and not explicitly created by a user,
>> such chain should not exist. The only exception is if there is
>> an action "goto chain" pointing to it. In that case, don't show the
>> chain in the dump. Track the chain references held by actions and
>> use them to find out if a chain should or should not be shown
>> in chain dump.
>> 
>> Signed-off-by: Jiri Pirko <j...@mellanox.com>
>
>I don't have any better ideas :)
>
>One question below.
>
>> diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
>> index 75cce2819de9..76035cd6e3bf 100644
>> --- a/net/sched/cls_api.c
>> +++ b/net/sched/cls_api.c
>> @@ -262,6 +262,25 @@ static void tcf_chain_hold(struct tcf_chain *chain)
>>      ++chain->refcnt;
>>  }
>>  
>> +static void tcf_chain_hold_by_act(struct tcf_chain *chain)
>> +{
>> +    ++chain->action_refcnt;
>> +}
>> +
>> +static void tcf_chain_release_by_act(struct tcf_chain *chain)
>> +{
>> +    --chain->action_refcnt;
>> +}
>> +
>> +static bool tcf_chain_is_zombie(struct tcf_chain *chain)
>> +{
>> +    /* In case all the references are action references, this
>> +     * chain is a zombie and should not be listed in the chain
>> +     * dump list.
>> +     */
>> +    return chain->refcnt == chain->action_refcnt;
>> +}
>> +
>>  static struct tcf_chain *tcf_chain_lookup(struct tcf_block *block,
>>                                        u32 chain_index)
>>  {
>> @@ -298,6 +317,15 @@ struct tcf_chain *tcf_chain_get(struct tcf_block 
>> *block, u32 chain_index,
>>  }
>>  EXPORT_SYMBOL(tcf_chain_get);
>>  
>> +struct tcf_chain *tcf_chain_get_by_act(struct tcf_block *block, u32 
>> chain_index)
>> +{
>> +    struct tcf_chain *chain = tcf_chain_get(block, chain_index, true);
>> +
>> +    tcf_chain_hold_by_act(chain);
>> +    return chain;
>> +}
>> +EXPORT_SYMBOL(tcf_chain_get_by_act);
>> +
>>  static void tc_chain_tmplt_del(struct tcf_chain *chain);
>>  
>>  void tcf_chain_put(struct tcf_chain *chain)
>> @@ -310,6 +338,13 @@ void tcf_chain_put(struct tcf_chain *chain)
>>  }
>>  EXPORT_SYMBOL(tcf_chain_put);
>>  
>> +void tcf_chain_put_by_act(struct tcf_chain *chain)
>> +{
>> +    tcf_chain_release_by_act(chain);
>> +    tcf_chain_put(chain);
>> +}
>> +EXPORT_SYMBOL(tcf_chain_put_by_act);
>> +
>>  static void tcf_chain_put_explicitly_created(struct tcf_chain *chain)
>>  {
>>      if (chain->explicitly_created)
>> @@ -1803,17 +1838,26 @@ static int tc_ctl_chain(struct sk_buff *skb, struct 
>> nlmsghdr *n,
>>      chain = tcf_chain_lookup(block, chain_index);
>>      if (n->nlmsg_type == RTM_NEWCHAIN) {
>>              if (chain) {
>> -                    NL_SET_ERR_MSG(extack, "Filter chain already exists");
>> -                    return -EEXIST;
>> -            }
>> -            if (!(n->nlmsg_flags & NLM_F_CREATE)) {
>> -                    NL_SET_ERR_MSG(extack, "Need both RTM_NEWCHAIN and 
>> NLM_F_CREATE to create a new chain");
>> -                    return -ENOENT;
>> -            }
>> -            chain = tcf_chain_create(block, chain_index);
>> -            if (!chain) {
>> -                    NL_SET_ERR_MSG(extack, "Failed to create filter chain");
>> -                    return -ENOMEM;
>> +                    if (tcf_chain_is_zombie(chain)) {
>> +                            /* The chain exists only because there is
>> +                             * some action referencing it, meaning it
>> +                             * is a zombie.
>> +                             */
>> +                            tcf_chain_hold(chain);
>
>I'm not 100% sure why this is needed?  In my tree below I see:
>
>       switch (n->nlmsg_type) {
>       case RTM_NEWCHAIN:
>               err = tc_chain_tmplt_add(chain, net, tca, extack);
>               if (err)
>                       goto errout;
>               /* In case the chain was successfully added, take a reference
>                * to the chain. This ensures that an empty chain
>                * does not disappear at the end of this function.
>                */
>               tcf_chain_hold(chain);
>               chain->explicitly_created = true;
>
>so one reference will be taken..  do we need two? 

There is a put at the end of this function.

>
>> +                    } else {
>> +                            NL_SET_ERR_MSG(extack, "Filter chain already 
>> exists");
>> +                            return -EEXIST;
>> +                    }
>> +            } else {
>> +                    if (!(n->nlmsg_flags & NLM_F_CREATE)) {
>> +                            NL_SET_ERR_MSG(extack, "Need both RTM_NEWCHAIN 
>> and NLM_F_CREATE to create a new chain");
>> +                            return -ENOENT;
>> +                    }
>> +                    chain = tcf_chain_create(block, chain_index);
>> +                    if (!chain) {
>> +                            NL_SET_ERR_MSG(extack, "Failed to create filter 
>> chain");
>> +                            return -ENOMEM;
>> +                    }
>>              }
>>      } else {
>>              if (!chain) {
>> @@ -1944,6 +1988,8 @@ static int tc_dump_chain(struct sk_buff *skb, struct 
>> netlink_callback *cb)
>>                      index++;
>>                      continue;
>>              }
>> +            if (tcf_chain_is_zombie(chain))
>> +                    continue;
>>              err = tc_chain_fill_node(chain, net, skb, block,
>>                                       NETLINK_CB(cb->skb).portid,
>>                                       cb->nlh->nlmsg_seq, NLM_F_MULTI,
>

Reply via email to