On 22 Mar 2022, at 13:04, Tao Liu wrote:

> If netdev goes away(i.e. qemu with a vnet shutdown), kernel delete all tc
> filters, those tcf_id related to the netdev will be left in ufid_to_tc
> hashmap.
> When qemu restart with a same vnet but different ifindex assigned,
> a dup ufid may add. Especially after hashmap_expand, the old entry will
> insert before the new one, delete or modify tc flow will always fail.
>
> So delete the stale entry to avoid a duplicated ufid in hashmap.

There are some comments below, as I still do not fully understand the fix.

> Fixes: dd8ca104acd7 ("netdev-tc-offloads: Don't delete ufid mapping if fail 
> to delete filter")))
> Signed-off-by: Tao Liu <thomas....@ucloud.cn>
> ---
>  lib/netdev-offload-tc.c | 37 ++++++++++++++++++++++---------------
>  1 file changed, 22 insertions(+), 15 deletions(-)
>
> diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c
> index 12d0a9af3..e9dd66790 100644
> --- a/lib/netdev-offload-tc.c
> +++ b/lib/netdev-offload-tc.c
> @@ -167,6 +167,9 @@ struct ufid_tc_data {
>      struct netdev *netdev;
>  };
>
> +static void parse_tc_flower_to_stats(struct tc_flower *flower,
> +                                     struct dpif_flow_stats *stats);
> +
>  static void
>  del_ufid_tc_mapping_unlocked(const ovs_u128 *ufid)
>  {
> @@ -200,11 +203,24 @@ del_ufid_tc_mapping(const ovs_u128 *ufid)
>
>  /* Wrapper function to delete filter and ufid tc mapping */
>  static int
> -del_filter_and_ufid_mapping(struct tcf_id *id, const ovs_u128 *ufid)
> +del_filter_and_ufid_mapping(struct tcf_id *id, const ovs_u128 *ufid,
> +                            struct dpif_flow_stats *stats)
>  {
> -    int err;
> +    struct tc_flower flower;
> +    int err = 0, get_err;
> +
> +    get_err = tc_get_flower(id, &flower);
> +    if (!get_err) {

We should definitely add a comment here explaining the reasoning behind doing 
the get first and then the delete!

However, it’s still not clear to me why this change does not undo, dd8ca104acd7?

Because tc_get_flower() just finds out if the entry with the ID exists in the 
kernel, and than only try to delete it.

For this can you just not check a specific return value in the tc_del_filter() 
call?

I assume dd8ca104acd7 just want to skip removing the del_ufid_tc_mapping() if 
the entry does NOT exist in the kernel?
If not maybe Jianbo can explain a bit more the corner case, or maybe has a test 
case for this?

> +        err = tc_del_filter(id);
> +    }
> +
> +    if (stats) {
> +        memset(stats, 0, sizeof *stats);
> +        if (!get_err) {
> +            parse_tc_flower_to_stats(&flower, stats);
> +        }
> +    }

I guess this was moved here to avoid the additional tc_get_flower() call below.

I would fold the stats part in the above if() case to avoid the need for the 
get_err variable, i.e.

    if (!tc_get_flower(id, &flower)) {
      err = tc_del_filter(id);
      if (stats) {
        memset(stats, 0, sizeof *stats);
        if (!get_err) {
            parse_tc_flower_to_stats(&flower, stats);
        }
      }


>
> -    err = tc_del_filter(id);
>      if (!err) {
>          del_ufid_tc_mapping(ufid);
>      }
> @@ -1946,7 +1962,8 @@ netdev_tc_flow_put(struct netdev *netdev, struct match 
> *match,
>      if (get_ufid_tc_mapping(ufid, &id) == 0) {
>          VLOG_DBG_RL(&rl, "updating old handle: %d prio: %d",
>                      id.handle, id.prio);
> -        info->tc_modify_flow_deleted = !del_filter_and_ufid_mapping(&id, 
> ufid);
> +        info->tc_modify_flow_deleted =
> +                    !del_filter_and_ufid_mapping(&id, ufid, NULL);
>      }
>
>      prio = get_prio_for_tc_flower(&flower);
> @@ -2017,7 +2034,6 @@ netdev_tc_flow_del(struct netdev *netdev OVS_UNUSED,
>                     const ovs_u128 *ufid,
>                     struct dpif_flow_stats *stats)
>  {
> -    struct tc_flower flower;
>      struct tcf_id id;
>      int error;
>
> @@ -2026,16 +2042,7 @@ netdev_tc_flow_del(struct netdev *netdev OVS_UNUSED,
>          return error;
>      }
>
> -    if (stats) {
> -        memset(stats, 0, sizeof *stats);
> -        if (!tc_get_flower(&id, &flower)) {
> -            parse_tc_flower_to_stats(&flower, stats);
> -        }
> -    }
> -
> -    error = del_filter_and_ufid_mapping(&id, ufid);
> -
> -    return error;
> +    return del_filter_and_ufid_mapping(&id, ufid, stats);
>  }
>
>  static int
> -- 
> 2.23.0
>
> _______________________________________________
> dev mailing list
> d...@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev

_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to