On 6 Feb 2023, at 8:48, Tianyu Yuan wrote:

> On Fri 2/3/2023 8:35 PM, Eelco Chaudron wrote:
>>
>> On 30 Jan 2023, at 17:42, Simon Horman wrote:
>>
>>> From: Tianyu Yuan <tianyu.y...@corigine.com>
>>>
>>> Allow revalidator to continuously delete police in kernel tc datapath
>>> until it is deleted.
>>>
>>> In current implementation, polices in tc datapath will not deleted
>>> when they are being used and these remaining polices will be cleared
>>> when the openvswitch restarts.
>>>
>>> This patch supports revalidator to delete remaining polices in tc
>>> datapath by storing meter_id deleted unsuccessfully in a hmap and
>>> continuously deleting them in revalidator until success.
>>
>> Hi Tianyu,
>>
>> Thanks for the new revision of the patch...
>>
>> Were you able to figure out if we really need to do this during revalidating
>> flows?
>>
>> I was wondering if there would be a different way, i.e. on flow deletion see 
>> if
>> it was the last flow using this meter and if so remove it then. I guess this 
>> can
>> be done with the meter having a flag that it has been deleted.
>>
>> This would be way more elegant than doing this in the revalidator thread.
>>
>> See some inline comments below. This was a quick review/tests, as the
>> above might require a different approach.
>>
>> Cheers,
>>
>> Eelco
>>
>
> Hi Eelco,
>
> Thanks for your review and comments. I've got your point of view:
> 1. Another approach that trigger tc police deletion only when the last flow 
> using this
> meter.

Not sure if this is possible, but if, it will be more clean and hidden in the 
tc layers.

> 2. depend the deletion on fail deletion of police_index rather than that of 
> meter_id,
> keep the operation in dpif layer and this should be invisible from ofproto 
> layer.

Yes, if the above is not possible, we should keep all this handling in the 
offload layer for TC.

> Please point me out if I misunderstood.
>
> The AT test of system-offload is attached at the end of this mail.
> The error "9: offloads - check_pkt_len action - offloads disabled" also 
> happens on
> Upstream master branch so it is unrelated to this patch

I’m asking for a new test case that shows this problem. i.e. it will fail 
without your patch applied but will pass with it.

Thanks,

Eelco

> Cheers
> Tianyu
>
>>> Signed-off-by: Tianyu Yuan <tianyu.y...@corigine.com>
>>> Signed-off-by: Simon Horman <simon.hor...@corigine.com>
>>>
>>> ---
>>>  lib/dpif-netdev.c             |  1 +
>>>  lib/dpif-netlink.c            | 26 +++++++++++++++++++++++++-
>>>  lib/dpif-provider.h           |  4 ++++
>>>  lib/dpif.c                    |  7 +++++++
>>>  lib/dpif.h                    |  2 ++
>>>  lib/netdev-offload-tc.c       |  5 ++++-
>>>  lib/netdev-offload.c          |  8 +++++---
>>>  ofproto/ofproto-dpif-upcall.c |  6 ++++++
>>>  ofproto/ofproto-dpif.c        | 10 +++++++++-
>>>  ofproto/ofproto-dpif.h        |  3 +++
>>>  10 files changed, 66 insertions(+), 6 deletions(-)
>>>
>>> diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index
>>> c9f7179c3b4c..878fe5933d1a 100644
>>> --- a/lib/dpif-netdev.c
>>> +++ b/lib/dpif-netdev.c
>>> @@ -9689,6 +9689,7 @@ const struct dpif_class dpif_netdev_class = {
>>>      dpif_netdev_meter_set,
>>>      dpif_netdev_meter_get,
>>>      dpif_netdev_meter_del,
>>> +    NULL,
>>>      dpif_netdev_bond_add,
>>>      dpif_netdev_bond_del,
>>>      dpif_netdev_bond_stats_get,
>>> diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c index
>>> 026b0daa8d83..8b95912aea97 100644
>>> --- a/lib/dpif-netlink.c
>>> +++ b/lib/dpif-netlink.c
>>> @@ -25,6 +25,7 @@
>>>  #include <net/if.h>
>>>  #include <linux/types.h>
>>>  #include <linux/pkt_sched.h>
>>> +#include <linux/rtnetlink.h>
>>>  #include <poll.h>
>>>  #include <stdlib.h>
>>>  #include <strings.h>
>>> @@ -37,6 +38,7 @@
>>>  #include "dpif-provider.h"
>>>  #include "fat-rwlock.h"
>>>  #include "flow.h"
>>> +#include "id-pool.h"
>>>  #include "netdev-linux.h"
>>>  #include "netdev-offload.h"
>>>  #include "netdev-provider.h"
>>> @@ -61,6 +63,7 @@
>>>  #include "packets.h"
>>>  #include "random.h"
>>>  #include "sset.h"
>>> +#include "tc.h"
>>>  #include "timeval.h"
>>>  #include "unaligned.h"
>>>  #include "util.h"
>>> @@ -4363,12 +4366,32 @@ dpif_netlink_meter_del(struct dpif *dpif,
>> ofproto_meter_id meter_id,
>>>      err  = dpif_netlink_meter_get_stats(dpif, meter_id, stats,
>>>                                          max_bands, OVS_METER_CMD_DEL);
>>>      if (!err && netdev_is_flow_api_enabled()) {
>>> -        meter_offload_del(meter_id, stats);
>>> +        return meter_offload_del(meter_id, stats);
>>>      }
>>>
>>>      return err;
>>>  }
>>>
>>> +static void
>>> +dpif_netlink_meter_revalidate(struct dpif *dpif_ OVS_UNUSED,
>>> +                              struct hmap *meter_map) {
>>> +    static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
>>> +    ofproto_meter_id meter_id;
>>> +    struct id_node *id_node;
>>> +
>>> +    HMAP_FOR_EACH_POP (id_node, node, meter_map) {
>>> +        meter_id.uint32 = id_node->id;
>>> +
>>> +        if (meter_offload_del(meter_id, NULL) == EPERM) {
>>> +            id_hmap_add(meter_map, meter_id.uint32);
>>> +        } else {
>>> +            VLOG_DBG_RL(&rl, "Delete meter %u in datapath success",
>>> +                        meter_id.uint32);
>>> +        }
>>> +    }
>>> +}
>>> +
>>>  static bool
>>>  probe_broken_meters__(struct dpif *dpif)  { @@ -4588,6 +4611,7 @@
>>> const struct dpif_class dpif_netlink_class = {
>>>      dpif_netlink_meter_set,
>>>      dpif_netlink_meter_get,
>>>      dpif_netlink_meter_del,
>>> +    dpif_netlink_meter_revalidate,
>>>      NULL,                       /* bond_add */
>>>      NULL,                       /* bond_del */
>>>      NULL,                       /* bond_stats_get */
>>> diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h index
>>> 12477a24feee..794fbc21686a 100644
>>> --- a/lib/dpif-provider.h
>>> +++ b/lib/dpif-provider.h
>>> @@ -631,6 +631,10 @@ struct dpif_class {
>>>      int (*meter_del)(struct dpif *, ofproto_meter_id meter_id,
>>>                       struct ofputil_meter_stats *, uint16_t n_bands);
>>>
>>> +    /* Checks unneeded meters from 'dpif' and removes them. They may
>>> +     * be caused by deleting in-use meters. */
>>> +    void (*meter_revalidate)(struct dpif *, struct hmap *meter_map);
>>> +
>>
>> I guess this is not really a revalidate action, it's more of a cleanup.
>> So maybe also call it something like meter_cleanup(), or
>> meter_garbage_collection.
>>
>> Or maybe even better, why not use the existing periodic 'bool (*run)(struct
>> dpif *dpif)' callback and handle it there?
>>
>>>      /* Adds a bond with 'bond_id' and the member-map to 'dpif'. */
>>>      int (*bond_add)(struct dpif *dpif, uint32_t bond_id,
>>>                      odp_port_t *member_map); diff --git a/lib/dpif.c
>>> b/lib/dpif.c index fe4db83fbfee..c8718239117d 100644
>>> --- a/lib/dpif.c
>>> +++ b/lib/dpif.c
>>> @@ -2028,6 +2028,13 @@ dpif_meter_del(struct dpif *dpif,
>> ofproto_meter_id meter_id,
>>>      return error;
>>>  }
>>>
>>> +void
>>> +dpif_meter_revalidate(struct dpif *dpif, struct hmap *meter_map){
>>> +    if (dpif->dpif_class->meter_revalidate) {
>>> +        dpif->dpif_class->meter_revalidate(dpif, meter_map);
>>> +    }
>>> +}
>>> +
>>>  int
>>>  dpif_bond_add(struct dpif *dpif, uint32_t bond_id, odp_port_t
>>> *member_map)  { diff --git a/lib/dpif.h b/lib/dpif.h index
>>> 6cb4dae6d8d7..e181e4ee1d6c 100644
>>> --- a/lib/dpif.h
>>> +++ b/lib/dpif.h
>>> @@ -378,6 +378,7 @@
>>>
>>>  #include "dpdk.h"
>>>  #include "dp-packet.h"
>>> +#include "id-pool.h"
>>>  #include "netdev.h"
>>>  #include "openflow/openflow.h"
>>>  #include "openvswitch/ofp-meter.h"
>>> @@ -905,6 +906,7 @@ int dpif_meter_get(const struct dpif *,
>> ofproto_meter_id meter_id,
>>>                     struct ofputil_meter_stats *, uint16_t n_bands);
>>> int dpif_meter_del(struct dpif *, ofproto_meter_id meter_id,
>>>                     struct ofputil_meter_stats *, uint16_t n_bands);
>>> +void dpif_meter_revalidate(struct dpif *dpif, struct hmap
>>> +*meter_map);
>>>
>>>  /* Bonding. */
>>>
>>> diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c index
>>> 15d1c36aa04e..f87a5e05e202 100644
>>> --- a/lib/netdev-offload-tc.c
>>> +++ b/lib/netdev-offload-tc.c
>>> @@ -2980,8 +2980,11 @@ meter_tc_del_policer(ofproto_meter_id
>> meter_id,
>>>                          police_index, meter_id.uint32, ovs_strerror(err));
>>>          } else {
>>>              meter_free_police_index(police_index);
>>> +            /* Do not remove the mapping between meter_id and police_index
>>> +             * until this meter is deleted successfully in datapath. This
>>> +             * mapping will be used in meter deletion in revalidator. */
>>> +            meter_id_remove(meter_id.uint32);
>>
>> This approach might have problem, what if the policy gets deleted, and re-
>> added with a new configuration?
>> The datapath flows are not cleared, and the add will fail as the meter_id is
>> still in use.
>>
>> Guess we need to keep the police index as this is tc specific, the meter_id 
>> is
>> global.
>>
>>>          }
>>> -        meter_id_remove(meter_id.uint32);
>>>      }
>>>
>>>      return err;
>>> diff --git a/lib/netdev-offload.c b/lib/netdev-offload.c index
>>> 4592262bd34e..0769f796e5b7 100644
>>> --- a/lib/netdev-offload.c
>>> +++ b/lib/netdev-offload.c
>>> @@ -241,19 +241,21 @@ int
>>>  meter_offload_del(ofproto_meter_id meter_id, struct
>>> ofputil_meter_stats *stats)  {
>>>      struct netdev_registered_flow_api *rfa;
>>> +    int ret = 0;
>>>
>>>      CMAP_FOR_EACH (rfa, cmap_node, &netdev_flow_apis) {
>>>          if (rfa->flow_api->meter_del) {
>>> -            int ret = rfa->flow_api->meter_del(meter_id, stats);
>>> -            if (ret) {
>>> +            int err = rfa->flow_api->meter_del(meter_id, stats);
>>> +            if (err) {
>>>                  VLOG_DBG_RL(&rl, "Failed deleting meter %u for flow api 
>>> %s, "
>>>                              "error %d", meter_id.uint32, 
>>> rfa->flow_api->type,
>>>                              ret);
>>> +                ret = err;
>>>              }
>>>          }
>>>      }
>>>
>>> -    return 0;
>>> +    return ret;
>>>  }
>>>
>>>  int
>>> diff --git a/ofproto/ofproto-dpif-upcall.c
>>> b/ofproto/ofproto-dpif-upcall.c index 31ac02d116fc..b802c9c7f13a
>>> 100644
>>> --- a/ofproto/ofproto-dpif-upcall.c
>>> +++ b/ofproto/ofproto-dpif-upcall.c
>>> @@ -2828,6 +2828,12 @@ revalidate(struct revalidator *revalidator)
>>>          }
>>>          ovsrcu_quiesce();
>>>      }
>>> +    /* When fail_meter_hmap is not empty, revalidate to delete meters in
>> this
>>> +     * hashmap. */
>>> +    if (hmap_count(&udpif->backer->fail_meter_hmap)) {
>>> +        dpif_meter_revalidate(udpif->dpif,
>>> + &udpif->backer->fail_meter_hmap);
>>
>> This could be removed with the general run() implementation. But in general
>> we should not have this hmap, just call the callback. See below.
>>
>>> +    }
>>> +
>>>      dpif_flow_dump_thread_destroy(dump_thread);
>>>      ofpbuf_uninit(&odp_actions);
>>>  }
>>> diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index
>>> f87e27a8cd7f..591af5503765 100644
>>> --- a/ofproto/ofproto-dpif.c
>>> +++ b/ofproto/ofproto-dpif.c
>>> @@ -835,6 +835,7 @@ open_dpif_backer(const char *type, struct
>> dpif_backer **backerp)
>>>      dpif_meter_get_features(backer->dpif, &features);
>>>      if (features.max_meters) {
>>>          backer->meter_ids = id_pool_create(0, features.max_meters);
>>> +        hmap_init(&backer->fail_meter_hmap);
>>>      } else {
>>>          backer->meter_ids = NULL;
>>>      }
>>> @@ -6790,8 +6791,15 @@ static void
>>>  free_meter_id(struct free_meter_id_args *args)  {
>>>      struct ofproto_dpif *ofproto = args->ofproto;
>>> +    int err;
>>> +
>>> +    err = dpif_meter_del(ofproto->backer->dpif, args->meter_id, NULL, 0);
>>> +    /* Add fail deleted meter to fail_meter_hmap and waiting to be
>> deleted in
>>> +     * revalidator. */
>>> +    if (err == EPERM) {
>>> +        id_hmap_add(&ofproto->backer->fail_meter_hmap, args-
>>> meter_id.uint32);
>>> +    }
>>
>> I think we should not track any of this in the ofproto layer. As this is a 
>> dpif
>> problem, it should be completely hidden in the dpif layer. This should be 
>> easy
>> if you remove the dependency on meter_id as suggested above.
>>
>>>
>>> -    dpif_meter_del(ofproto->backer->dpif, args->meter_id, NULL, 0);
>>>      id_pool_free_id(ofproto->backer->meter_ids, args->meter_id.uint32);
>>>      free(args);
>>>  }
>>> diff --git a/ofproto/ofproto-dpif.h b/ofproto/ofproto-dpif.h index
>>> d8e0cd37ac5b..befc68d13baa 100644
>>> --- a/ofproto/ofproto-dpif.h
>>> +++ b/ofproto/ofproto-dpif.h
>>> @@ -61,6 +61,7 @@ struct ofproto_dpif;  struct uuid;  struct
>>> xlate_cache;  struct xlate_ctx;
>>> +struct id_pool;
>>>
>>>  /* Number of implemented OpenFlow tables. */  enum { N_TABLES = 255
>>> }; @@ -260,6 +261,8 @@ struct dpif_backer {
>>>
>>>      /* Meter. */
>>>      struct id_pool *meter_ids;     /* Datapath meter allocation. */
>>> +    struct hmap fail_meter_hmap;   /* Hashmap for meter with failed
>> deletion
>>> +                                    * in datapath */
>>>
>>>      /* Connection tracking. */
>>>      struct id_pool *tp_ids;             /* Datapath timeout policy id
>>> --
>>> 2.30.2
>>
>> Please add a test to 'make check-offloads'.
>
> ``````
> ## ------------------------------ ##
> ## openvswitch 3.1.90 test suite. ##
> ## ------------------------------ ##
>
> datapath offloads
>
>   1: offloads - ping between two ports - offloads disabled ok
>   2: offloads - ping between two ports - offloads enabled ok
>   3: offloads - set ingress_policing_rate and ingress_policing_burst - 
> offloads disabled ok
>   4: offloads - set ingress_policing_rate and ingress_policing_burst - 
> offloads enabled ok
>   5: offloads - set ingress_policing_kpkts_rate and 
> ingress_policing_kpkts_burst - offloads disabled ok
>   6: offloads - set ingress_policing_kpkts_rate and 
> ingress_policing_kpkts_burst - offloads enabled ok
>   7: offloads - check interface meter offloading -  offloads disabled ok
>   8: offloads - check interface meter offloading -  offloads enabled ok
>   9: offloads - check_pkt_len action - offloads disabled FAILED 
> (system-offloads-traffic.at:328)
>  10: offloads - check_pkt_len action - offloads enabled ok
>
> ## ------------- ##
> ## Test results. ##
> ## ------------- ##
>
> ERROR: All 10 tests were run,
> 1 failed unexpectedly.
> ## ------------------------------------------ ##
> ## system-offloads-testsuite.log was created. ##
> ## ------------------------------------------ ##
>
> Please send `tests/system-offloads-testsuite.log' and all information you 
> think might help:
>
>    To: <b...@openvswitch.org>
>    Subject: [openvswitch 3.1.90] system-offloads-testsuite: 9 failed
>
> You may investigate any problem if you feel able to do so, in which
> case the test suite provides a good starting point.  Its output may
> be found below `tests/system-offloads-testsuite.dir'.
>
> make: *** [Makefile:7034: check-offloads] Error 1
> ``````

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

Reply via email to