On 10/10/23 16:12, Ales Musil wrote:
> Make sure that if any zone limit was set via DB
> all zones are forced to be set there also. This
> is done by tracking which datapath has zone limit
> protection and it is reflected in the dpctl command.
> 
> If the datapath is protected the dpctl command will
> return permission error.
> 
> Signed-off-by: Ales Musil <amu...@redhat.com>
> ---
> v4: Rebase on top of current master.
>     Make the protection datapath wide.
> ---
>  lib/ct-dpif.c              | 27 +++++++++++++++++++++++++++
>  lib/ct-dpif.h              |  2 ++
>  lib/dpctl.c                | 10 ++++++++++
>  ofproto/ofproto-dpif.c     | 14 ++++++++++++++
>  ofproto/ofproto-provider.h |  5 +++++
>  ofproto/ofproto.c          | 11 +++++++++++
>  ofproto/ofproto.h          |  2 ++
>  tests/system-traffic.at    | 36 ++++++++++++++++++++++++++++++++++++
>  vswitchd/bridge.c          |  9 +++++++++
>  9 files changed, 116 insertions(+)
> 
> diff --git a/lib/ct-dpif.c b/lib/ct-dpif.c
> index 686e95c92..a75a8c532 100644
> --- a/lib/ct-dpif.c
> +++ b/lib/ct-dpif.c
> @@ -23,6 +23,7 @@
>  #include "openvswitch/ofp-ct.h"
>  #include "openvswitch/ofp-parse.h"
>  #include "openvswitch/vlog.h"
> +#include "sset.h"
>  
>  VLOG_DEFINE_THIS_MODULE(ct_dpif);
>  
> @@ -32,6 +33,10 @@ struct flags {
>      const char *name;
>  };
>  
> +/* Protection for CT zone limit per datapath. */
> +static struct sset ct_limit_protection =
> +        SSET_INITIALIZER(&ct_limit_protection);
> +
>  static void ct_dpif_format_counters(struct ds *,
>                                      const struct ct_dpif_counters *);
>  static void ct_dpif_format_timestamp(struct ds *,
> @@ -1064,3 +1069,25 @@ ct_dpif_get_features(struct dpif *dpif, enum 
> ct_features *features)
>              ? dpif->dpif_class->ct_get_features(dpif, features)
>              : EOPNOTSUPP);
>  }
> +
> +void
> +ct_dpif_set_zone_limit_protection(struct dpif *dpif, bool protected)
> +{
> +    if (sset_contains(&ct_limit_protection, dpif->full_name) == protected) {
> +        return;
> +    }
> +
> +    if (protected) {
> +        sset_add(&ct_limit_protection, dpif->full_name);
> +    } else {
> +        sset_find_and_delete(&ct_limit_protection, dpif->full_name);
> +    }
> +    VLOG_INFO("The CT zone limit protection is %s for \"%s\".",
> +              protected ? "enabled" : "disabled", dpif->full_name);
> +}
> +
> +bool
> +ct_dpif_is_zone_limit_protected(struct dpif *dpif)
> +{
> +    return sset_contains(&ct_limit_protection, dpif->full_name);
> +}
> diff --git a/lib/ct-dpif.h b/lib/ct-dpif.h
> index c90dc9476..feb8b166a 100644
> --- a/lib/ct-dpif.h
> +++ b/lib/ct-dpif.h
> @@ -352,5 +352,7 @@ int ct_dpif_get_timeout_policy_name(struct dpif *dpif, 
> uint32_t tp_id,
>                                      uint16_t dl_type, uint8_t nw_proto,
>                                      char **tp_name, bool *is_generic);
>  int ct_dpif_get_features(struct dpif *dpif, enum ct_features *features);
> +void ct_dpif_set_zone_limit_protection(struct dpif *dpif, bool protected);
> +bool ct_dpif_is_zone_limit_protected(struct dpif *dpif);

No need for the 'dpif' variable name.

>  
>  #endif /* CT_DPIF_H */
> diff --git a/lib/dpctl.c b/lib/dpctl.c
> index 7113c2c12..3627d37d1 100644
> --- a/lib/dpctl.c
> +++ b/lib/dpctl.c
> @@ -2234,6 +2234,11 @@ dpctl_ct_set_limits(int argc, const char *argv[],
>          ct_dpif_push_zone_limit(&zone_limits, zone, limit, 0);
>      }
>  
> +    if (ct_dpif_is_zone_limit_protected(dpif)) {
> +        error = EPERM;

Some meaningful message directing users to use ovs-vsctl instead
might be nice here.

> +        goto error;
> +    }
> +
>      error = ct_dpif_set_limits(dpif, &zone_limits);
>      if (!error) {
>          ct_dpif_free_zone_limits(&zone_limits);
> @@ -2309,6 +2314,11 @@ dpctl_ct_del_limits(int argc, const char *argv[],
>          }
>      }
>  
> +    if (ct_dpif_is_zone_limit_protected(dpif)) {
> +        error = EPERM;

And here.

> +        goto error;
> +    }
> +
>      error = ct_dpif_del_limits(dpif, &zone_limits);
>      if (!error) {
>          goto out;
> diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
> index 4fdbf0ef0..4ea70f722 100644
> --- a/ofproto/ofproto-dpif.c
> +++ b/ofproto/ofproto-dpif.c
> @@ -5665,6 +5665,19 @@ ct_zone_limits_commit(struct dpif_backer *backer)
>      }
>  }
>  
> +static void
> +ct_zone_limit_protection_update(const char *datapath_type, bool protected)
> +{
> +    struct dpif_backer *backer = shash_find_data(&all_dpif_backers,
> +                                                 datapath_type);
> +    if (!backer) {
> +        return;
> +    }
> +
> +    ct_dpif_set_zone_limit_protection(backer->dpif, protected);
> +}
> +
> +
>  static void
>  get_datapath_cap(const char *datapath_type, struct smap *cap)
>  {
> @@ -6955,4 +6968,5 @@ const struct ofproto_class ofproto_dpif_class = {
>      ct_set_zone_timeout_policy,
>      ct_del_zone_timeout_policy,
>      ct_zone_limit_update,
> +    ct_zone_limit_protection_update,
>  };
> diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h
> index 33fb99280..e1d72b6df 100644
> --- a/ofproto/ofproto-provider.h
> +++ b/ofproto/ofproto-provider.h
> @@ -1925,6 +1925,11 @@ struct ofproto_class {
>      /* Updates the CT zone limit for specified zone. */
>      void (*ct_zone_limit_update)(const char *dp_type, int32_t zone,
>                                   int64_t *limit);
> +
> +    /* Sets the CT zone limit protection to "protected" for the specified
> +     * datapath type. */
> +    void (*ct_zone_limit_protection_update)(const char *dp_type,
> +                                            bool protected);
>  };
>  
>  extern const struct ofproto_class ofproto_dpif_class;
> diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
> index 6df3f1b27..06624006a 100644
> --- a/ofproto/ofproto.c
> +++ b/ofproto/ofproto.c
> @@ -1038,6 +1038,17 @@ ofproto_ct_zone_limit_update(const char 
> *datapath_type, int32_t zone_id,
>      }
>  }
>  
> +void
> +ofproto_ct_zone_limit_protection_update(const char *datapath_type,
> +                                        bool protected)
> +{
> +    datapath_type = ofproto_normalize_type(datapath_type);
> +    const struct ofproto_class *class = ofproto_class_find__(datapath_type);
> +
> +    if (class && class->ct_zone_limit_protection_update) {
> +        class->ct_zone_limit_protection_update(datapath_type, protected);
> +    }
> +}
>  
>  /* Spanning Tree Protocol (STP) configuration. */
>  
> diff --git a/ofproto/ofproto.h b/ofproto/ofproto.h
> index bba4a9e0e..0212ed062 100644
> --- a/ofproto/ofproto.h
> +++ b/ofproto/ofproto.h
> @@ -388,6 +388,8 @@ void ofproto_ct_del_zone_timeout_policy(const char 
> *datapath_type,
>                                          uint16_t zone);
>  void ofproto_ct_zone_limit_update(const char *datapath_type, int32_t zone_id,
>                                    int64_t *limit);
> +void ofproto_ct_zone_limit_protection_update(const char *datapath_type,
> +                                             bool protected);
>  void ofproto_get_datapath_cap(const char *datapath_type,
>                                struct smap *dp_cap);
>  
> diff --git a/tests/system-traffic.at b/tests/system-traffic.at
> index d2897feb6..00a682a7e 100644
> --- a/tests/system-traffic.at
> +++ b/tests/system-traffic.at
> @@ -5274,6 +5274,42 @@ OVS_WAIT_UNTIL_EQUAL([ovs-appctl dpctl/ct-get-limits], 
> [dnl
>  default limit=0
>  zone=0,limit=3,count=0])
>  
> +dnl Try to overwrite the zone limit via dpctl command.
> +AT_CHECK([ovs-appctl dpctl/ct-set-limits default=15 zone=3,limit=5 
> zone=0,limit=5], [2], [ignore], [ignore])
> +
> +AT_CHECK([ovs-appctl dpctl/ct-get-limits], [0], [dnl
> +default limit=0
> +zone=0,limit=3,count=0
> +])
> +
> +AT_CHECK([ovs-appctl dpctl/ct-del-limits zone=0], [2], [ignore], [ignore])
> +AT_CHECK([ovs-appctl dpctl/ct-get-limits], [0], [dnl
> +default limit=0
> +zone=0,limit=3,count=0
> +])
> +
> +AT_CHECK([ovs-vsctl del-zone-limit $DP_TYPE zone=0])
> +AT_CHECK([ovs-vsctl set-zone-default-limit $DP_TYPE limit=10])
> +AT_CHECK([ovs-appctl dpctl/ct-get-limits], [0], [dnl
> +default limit=10
> +])
> +
> +AT_CHECK([ovs-appctl dpctl/ct-set-limits default=15 zone=1,limit=5], [2], 
> [ignore], [ignore])
> +
> +dnl Delete all zones from DB, that should remove the protection.
> +AT_CHECK([ovs-vsctl del-zone-default-limit $DP_TYPE])
> +
> +AT_CHECK([ovs-appctl dpctl/ct-set-limits default=15 zone=1,limit=5])
> +AT_CHECK([ovs-appctl dpctl/ct-get-limits], [0], [dnl
> +default limit=15
> +zone=1,limit=5,count=0
> +])
> +
> +AT_CHECK([ovs-appctl dpctl/ct-del-limits zone=1])
> +AT_CHECK([ovs-appctl dpctl/ct-get-limits], [0], [dnl
> +default limit=15
> +])
> +
>  OVS_TRAFFIC_VSWITCHD_STOP(["dnl
>  /could not create datapath/d
>  /(Cannot allocate memory) on packet/d"])
> diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
> index 1e02cc8df..0868f27c3 100644
> --- a/vswitchd/bridge.c
> +++ b/vswitchd/bridge.c
> @@ -729,6 +729,7 @@ datapath_destroy(struct datapath *dp)
>                                           NULL);
>          }
>  
> +        ofproto_ct_zone_limit_protection_update(dp->type, false);
>          hmap_remove(&all_datapaths, &dp->node);
>          hmap_destroy(&dp->ct_zones);
>          free(dp->type);
> @@ -742,6 +743,8 @@ ct_zones_reconfigure(struct datapath *dp, struct 
> ovsrec_datapath *dp_cfg)
>  {
>      struct ct_zone *ct_zone;
>  

No need for the empty line here.

> +    bool protected = false;
> +
>      /* Add new 'ct_zone's or update existing 'ct_zone's based on the database
>       * state. */
>      for (size_t i = 0; i < dp_cfg->n_ct_zones; i++) {
> @@ -774,6 +777,8 @@ ct_zones_reconfigure(struct datapath *dp, struct 
> ovsrec_datapath *dp_cfg)
>  
>          ct_zone->limit = desired_limit;
>          ct_zone->last_used = idl_seqno;
> +
> +        protected |= !!zone_cfg->limit;

Don't use bit operations on booleans.

>      }
>  
>      /* Purge 'ct_zone's no longer found in the database. */
> @@ -804,6 +809,10 @@ ct_zones_reconfigure(struct datapath *dp, struct 
> ovsrec_datapath *dp_cfg)
>      }
>  
>      dp->ct_default_limit = default_limit;
> +
> +    protected |= !!dp_cfg->ct_zone_default_limit;

Bit operation on a boolean.

> +
> +    ofproto_ct_zone_limit_protection_update(dp->type, protected);
>  }
>  
>  static void

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

Reply via email to