diff mbox series

[ovs-dev,08/12] datapath-config: Consume datapath, CT_Zone, and CT_Timeout_Policy tables

Message ID 1564097054-72663-9-git-send-email-yihung.wei@gmail.com
State Changes Requested
Headers show
Series Support zone-based conntrack timeout policy | expand

Commit Message

Yi-Hung Wei July 25, 2019, 11:24 p.m. UTC
This patch reads the datapath, CT_Zone, and CT_Timeout_Policy tables
from ovsdb, stores the information in a per datapath internal datapath
structure, and pushes down the conntrack timeout policy into the
datapath via dpif interface.

The per datapath internal data structure will be used in
ofproto-dpif-xlate to implement the zone-based timeout policy.

Signed-off-by: Yi-Hung Wei <yihung.wei@gmail.com>
---
 lib/automake.mk       |   2 +
 lib/datapath-config.c | 379 ++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/datapath-config.h |  25 ++++
 vswitchd/bridge.c     |   3 +
 4 files changed, 409 insertions(+)
 create mode 100644 lib/datapath-config.c
 create mode 100644 lib/datapath-config.h

Comments

William Tu July 26, 2019, 8:22 p.m. UTC | #1
I only have some minor comments inline below.

On Thu, Jul 25, 2019 at 04:24:10PM -0700, Yi-Hung Wei wrote:
> This patch reads the datapath, CT_Zone, and CT_Timeout_Policy tables
> from ovsdb, stores the information in a per datapath internal datapath
> structure, and pushes down the conntrack timeout policy into the
> datapath via dpif interface.
> 
> The per datapath internal data structure will be used in
> ofproto-dpif-xlate to implement the zone-based timeout policy.
> 
> Signed-off-by: Yi-Hung Wei <yihung.wei@gmail.com>
> ---
>  lib/automake.mk       |   2 +
>  lib/datapath-config.c | 379 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  lib/datapath-config.h |  25 ++++
>  vswitchd/bridge.c     |   3 +
>  4 files changed, 409 insertions(+)
>  create mode 100644 lib/datapath-config.c
>  create mode 100644 lib/datapath-config.h
> 
> diff --git a/lib/automake.mk b/lib/automake.mk
> index 17b36b43d9d7..7532153f5d02 100644
> --- a/lib/automake.mk
> +++ b/lib/automake.mk
> @@ -67,6 +67,8 @@ lib_libopenvswitch_la_SOURCES = \
>  	lib/daemon.c \
>  	lib/daemon.h \
>  	lib/daemon-private.h \
> +	lib/datapath-config.c \
> +	lib/datapath-config.h \
>  	lib/db-ctl-base.c \
>  	lib/db-ctl-base.h \
>  	lib/dhcp.h \
> diff --git a/lib/datapath-config.c b/lib/datapath-config.c
> new file mode 100644
> index 000000000000..cdd2128a60bc
> --- /dev/null
> +++ b/lib/datapath-config.c
> @@ -0,0 +1,379 @@
> +/* Copyright (c) 2019 Nicira, Inc.
> + *
> + * Licensed under the Apache License, Version 2.0 (the "License");
> + * you may not use this file except in compliance with the License.
> + * You may obtain a copy of the License at:
> + *
> + *     http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing, software
> + * distributed under the License is distributed on an "AS IS" BASIS,
> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> + * See the License for the specific language governing permissions and
> + * limitations under the License.
> + */
> +
> +#include <config.h>
> +#include "datapath-config.h"
> +
> +#include "cmap.h"
> +#include "ct-dpif.h"
> +#include "dpif.h"
> +#include "openvswitch/vlog.h"
> +
> +VLOG_DEFINE_THIS_MODULE(datapath_config);
> +
> +struct ct_timeout_policy {
> +    struct uuid uuid;
> +    unsigned int last_used_seqno;
> +    unsigned int last_updated_seqno;
> +    struct ct_dpif_timeout_policy cdtp;
> +    struct cmap_node node;          /* Element in struct datapath's
> +                                     * "ct_timeout_policies" cmap. */
> +};
> +
> +struct ct_zone {
> +    uint16_t id;
> +    unsigned int last_used_seqno;
> +    struct uuid tp_uuid;            /* uuid that identifies a timeout policy in
> +                                     * struct datapaths's "ct_tps cmap. */
> +    struct cmap_node node;          /* Element in struct datapath's "ct_zones"
> +                                     * cmap. */
> +};
> +
> +struct datapath {
> +    char *type;                     /* Datapath type. */
> +    char *dpif_backer_name;
> +    const struct ovsrec_datapath *cfg;
> +
> +    struct hmap_node node;          /* In 'all_datapaths'. */
> +    struct cmap ct_zones;           /* "struct ct_zone"s indexed by zone id. */
> +    struct cmap ct_tps;             /* "struct ct_timeout_policy"s indexed by
> +                                     * uuid. */
> +};
> +
> +/* All datapaths, indexed by type. */
> +static struct hmap all_datapaths = HMAP_INITIALIZER(&all_datapaths);
> +
> +static void ct_zone_destroy(struct datapath *, struct ct_zone *);
> +static void ct_timeout_policy_destroy(struct datapath *,
> +                                      struct ct_timeout_policy *,
> +                                      struct dpif *);
> +
> +static struct datapath *
> +datapath_lookup(const char *type)
> +{
> +    struct datapath *dp;
> +
> +    HMAP_FOR_EACH_WITH_HASH (dp, node, hash_string(type, 0), &all_datapaths) {
> +        if (!strcmp(dp->type, type)) {
> +            return dp;
> +        }
> +    }
> +    return NULL;
> +}
> +
> +static void
> +datapath_clear_timeout_policy(struct datapath *dp)
> +{
> +    struct ct_dpif_timeout_policy *tp;
> +    struct dpif *dpif;
> +    void *state;
> +    int err;
> +
> +    dpif_open(dp->dpif_backer_name, dp->type, &dpif);
> +    if (!dpif) {
> +        return;
> +    }
> +
> +    err = ct_dpif_timeout_policy_dump_start(dpif, &state);
> +    if (err) {
> +        return ;
> +    }
> +
> +    while (!(err = ct_dpif_timeout_policy_dump_next(dpif, state, &tp))) {
> +        ct_dpif_del_timeout_policy(dpif, tp->id);
> +        free(tp);
> +    }
> +
> +    ct_dpif_timeout_policy_dump_done(dpif, state);
> +    dpif_close(dpif);
> +}
> +
> +static struct datapath *
> +datapath_create(const struct ovsrec_datapath *dp_cfg, const char *type)
> +{
> +    struct datapath *dp;
> +
> +    ovs_assert(!datapath_lookup(type));
> +    dp = xzalloc(sizeof *dp);
> +
> +    dp->type = xstrdup(type);
> +    dp->dpif_backer_name = xasprintf("ovs-%s", type);
> +    dp->cfg = dp_cfg;
> +
> +    cmap_init(&dp->ct_zones);
> +    cmap_init(&dp->ct_tps);
> +
> +    datapath_clear_timeout_policy(dp);
> +    hmap_insert(&all_datapaths, &dp->node, hash_string(dp->type, 0));
> +    return dp;
> +}
> +
> +static void
> +datapath_destroy(struct datapath *dp)
> +{
> +    struct ct_zone *zone;
> +    struct ct_timeout_policy *tp;
> +    struct dpif *dpif;
> +
> +    if (dp) {
> +        CMAP_FOR_EACH (zone, node, &dp->ct_zones) {
> +            ct_zone_destroy(dp, zone);
> +        }
> +
> +        dpif_open(dp->dpif_backer_name, dp->type, &dpif);
> +
> +        CMAP_FOR_EACH (tp, node, &dp->ct_tps) {
> +            ct_timeout_policy_destroy(dp, tp, dpif);
> +        }
> +
> +        dpif_close(dpif);
> +        hmap_remove(&all_datapaths, &dp->node);
> +        cmap_destroy(&dp->ct_zones);
> +        cmap_destroy(&dp->ct_tps);
> +        free(dp->type);
> +        free(dp->dpif_backer_name);
> +        free(dp);
> +    }
> +}
> +
> +static void
> +add_del_datapaths(const struct ovsrec_open_vswitch *cfg)
> +{
> +    struct datapath *dp, *next;
> +    struct shash_node *node;
> +    struct shash new_dp;
> +    size_t i;
> +
> +    /* Collect new datapaths' type. */
> +    shash_init(&new_dp);
> +    for (i = 0; i < cfg->n_datapaths; i++) {
> +        const struct ovsrec_datapath *dp_cfg = cfg->value_datapaths[i];
> +        char *key = cfg->key_datapaths[i];
> +
> +        if (!strcmp(key, "system") || !strcmp(key, "netdev")) {
> +            shash_add(&new_dp, key, dp_cfg);
> +        } else {
> +            VLOG_WARN("Unsupported dpatapath type %s\n", key);
> +        }
> +    }
> +
> +    /* Get rid of deleted datapath. */
> +    HMAP_FOR_EACH_SAFE (dp, next, node, &all_datapaths) {
> +        dp->cfg = shash_find_data(&new_dp, dp->type);
> +        if (!dp->cfg) {
> +            datapath_destroy(dp);
> +        }
> +    }
> +
> +    /* Add new datapaths */
comment should end wit dot

> +    SHASH_FOR_EACH (node, &new_dp) {
> +        const struct ovsrec_datapath *dp_cfg = node->data;
> +        if (!datapath_lookup(node->name)) {
> +            datapath_create(dp_cfg, node->name);
> +        }
> +    }
> +
> +    shash_destroy(&new_dp);
> +}
> +
> +static struct ct_zone *
> +ct_zone_lookup(struct cmap *ct_zones, uint16_t zone_id)
> +{
> +    struct ct_zone *zone;
> +
> +    CMAP_FOR_EACH_WITH_HASH (zone, node, hash_int(zone_id, 0), ct_zones) {
> +        if (zone->id == zone_id) {
> +            return zone;
> +        }
> +    }
> +    return NULL;
> +}
> +
> +static struct ct_zone *
> +ct_zone_alloc(uint16_t zone_id)
> +{
> +    struct ct_zone *zone;
> +
> +    zone = xzalloc(sizeof *zone);
> +    zone->id = zone_id;
> +
> +    return zone;
> +}
> +
> +static void
> +ct_zone_destroy(struct datapath *dp, struct ct_zone *zone)
> +{
> +    cmap_remove(&dp->ct_zones, &zone->node, hash_int(zone->id, 0));
> +    ovsrcu_postpone(free, zone);
> +}
> +
> +static struct ct_timeout_policy *
> +ct_timeout_policy_lookup(struct cmap *ct_tps, struct uuid *uuid)
> +{
> +    struct ct_timeout_policy *tp;
> +
> +    CMAP_FOR_EACH_WITH_HASH (tp, node, uuid_hash(uuid), ct_tps) {
> +        if (uuid_equals(&tp->uuid, uuid)) {
> +            return tp;
> +        }
> +    }
> +    return NULL;
> +}
> +
> +static struct ct_timeout_policy *
> +ct_timeout_policy_alloc(struct ovsrec_ct_timeout_policy *tp_cfg,
> +                        unsigned int idl_seqno)
> +{
> +    struct ct_timeout_policy *tp;
> +    size_t i;
> +
> +    tp = xzalloc(sizeof *tp);
> +    tp->uuid = tp_cfg->header_.uuid;
> +    for (i = 0; i < tp_cfg->n_timeouts; i++) {
> +        ct_dpif_set_timeout_policy_attr_by_name(&tp->cdtp,
> +            tp_cfg->key_timeouts[i], tp_cfg->value_timeouts[i]);
> +    }
> +    tp->cdtp.id = idl_seqno;
> +    tp->last_updated_seqno = idl_seqno;
> +
> +    return tp;
> +}
> +
> +static bool
> +ct_timeout_policy_update(struct ovsrec_ct_timeout_policy *tp_cfg,
> +                         struct ct_timeout_policy *tp,
> +                         unsigned int idl_seqno)
> +{
> +    size_t i;
> +    bool changed = false;
> +
> +    for (i = 0; i < tp_cfg->n_timeouts; i++) {
> +        changed |= ct_dpif_set_timeout_policy_attr_by_name(&tp->cdtp,
> +                        tp_cfg->key_timeouts[i], tp_cfg->value_timeouts[i]);
> +    }
> +    if (changed) {
> +        tp->last_updated_seqno = idl_seqno;
> +    }
> +    return changed;
> +}
> +
> +static void
> +ct_timeout_policy_destroy(struct datapath *dp, struct ct_timeout_policy *tp,
> +                          struct dpif *dpif)
> +{
> +    cmap_remove(&dp->ct_tps, &tp->node, uuid_hash(&tp->uuid));
> +    if (dpif) {
> +        ct_dpif_del_timeout_policy(dpif, tp->cdtp.id);
> +    }
> +    ovsrcu_postpone(free, tp);
> +}
> +
> +static void
> +datapath_update_ct_zone_config(struct datapath *dp, struct dpif *dpif,
> +                               unsigned int idl_seqno)
> +{
> +    const struct ovsrec_datapath *dp_cfg = dp->cfg;
> +    struct ovsrec_ct_timeout_policy *tp_cfg;
> +    struct ovsrec_ct_zone *zone_cfg;
> +    struct ct_timeout_policy *tp;
> +    struct ct_zone *zone;
> +    uint16_t zone_id;
> +    bool new_zone;
> +    size_t i;
> +
> +    for (i = 0; i < dp_cfg->n_ct_zones; i++) {
> +        /* Update ct_zone config */
> +        zone_cfg = dp_cfg->value_ct_zones[i];
> +        zone_id = dp_cfg->key_ct_zones[i];
> +        zone = ct_zone_lookup(&dp->ct_zones, zone_id);
> +        if (!zone) {
> +            new_zone = true;
> +            zone = ct_zone_alloc(zone_id);
> +        } else {
> +            new_zone = false;
> +        }
> +        zone->last_used_seqno = idl_seqno;
> +
> +        /* Update timeout policy */
missing .
> +        tp_cfg = zone_cfg->timeout_policy;
> +        tp = ct_timeout_policy_lookup(&dp->ct_tps, &tp_cfg->header_.uuid);
> +        if (!tp) {
> +            tp = ct_timeout_policy_alloc(tp_cfg, idl_seqno);
> +            cmap_insert(&dp->ct_tps, &tp->node, uuid_hash(&tp->uuid));
> +            if (dpif) {
> +                ct_dpif_add_timeout_policy(dpif, false, &tp->cdtp);
> +            }
> +        } else {
> +            if (ct_timeout_policy_update(tp_cfg, tp, idl_seqno)) {
> +                if (dpif) {
> +                    ct_dpif_add_timeout_policy(dpif, false, &tp->cdtp);
> +                }
> +            }
> +        }
> +        tp->last_used_seqno = idl_seqno;
> +
> +        /* Update default timeout policy */

missing . and some places below

> +        if (!zone_id && tp->last_updated_seqno == idl_seqno) {
> +            ct_dpif_add_timeout_policy(dpif, true, &tp->cdtp);

Do we need to check 'if (dpif)' here?
You have the checking above, but not here. Or should we just return
error when dpif is NULL.

> +        }
> +
> +        /* Link zone with new timeout policy */
> +        zone->tp_uuid = tp_cfg->header_.uuid;
> +        if (new_zone) {
> +            cmap_insert(&dp->ct_zones, &zone->node, hash_int(zone_id, 0));
> +        }
> +    }
> +}
> +
> +void
> +reconfigure_datapath(const struct ovsrec_open_vswitch *cfg,
> +                     unsigned int idl_seqno)
> +{
> +    struct ct_timeout_policy *tp;
> +    struct ct_zone *zone;
> +    struct datapath *dp;
> +    struct dpif *dpif;
> +
> +    add_del_datapaths(cfg);
> +    HMAP_FOR_EACH (dp, node, &all_datapaths) {
> +        dpif_open(dp->dpif_backer_name, dp->type, &dpif);
> +
> +        datapath_update_ct_zone_config(dp, dpif, idl_seqno);
> +
> +        /* Garbage colleciton */
> +        CMAP_FOR_EACH (zone, node, &dp->ct_zones) {
> +            if (zone->last_used_seqno != idl_seqno) {
> +                ct_zone_destroy(dp, zone);
> +            }
> +        }
> +        CMAP_FOR_EACH (tp, node, &dp->ct_tps) {
> +            if (tp->last_used_seqno != idl_seqno) {
> +                ct_timeout_policy_destroy(dp, tp, dpif);
> +            }
> +        }
> +
> +        dpif_close(dpif);
> +    }
> +}
> +
> +void
> +destroy_all_datapaths(void)
> +{
> +    struct datapath *dp, *next_dp;
> +
> +    HMAP_FOR_EACH_SAFE (dp, next_dp, node, &all_datapaths) {
> +        datapath_destroy(dp);
> +    }
> +}
> diff --git a/lib/datapath-config.h b/lib/datapath-config.h
> new file mode 100644
> index 000000000000..d9a90e4f8312
> --- /dev/null
> +++ b/lib/datapath-config.h
> @@ -0,0 +1,25 @@
> +/* Copyright (c) 2019 Nicira, Inc.
> + *
> + * Licensed under the Apache License, Version 2.0 (the "License");
> + * you may not use this file except in compliance with the License.
> + * You may obtain a copy of the License at:
> + *
> + *     http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing, software
> + * distributed under the License is distributed on an "AS IS" BASIS,
> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> + * See the License for the specific language governing permissions and
> + * limitations under the License.
> + */
> +
> +#ifndef DATAPATH_CONFIG_H
> +#define DATAPATH_CONFIG_H 1
> +
> +#include "vswitch-idl.h"
> +
> +void reconfigure_datapath(const struct ovsrec_open_vswitch *,
> +                          unsigned int idl_seqno);
> +void destroy_all_datapaths(void);
> +
> +#endif /* datapath-config.h */
> diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
> index 2976771aeaba..e8ac24a50ff2 100644
> --- a/vswitchd/bridge.c
> +++ b/vswitchd/bridge.c
> @@ -26,6 +26,7 @@
>  #include "connectivity.h"
>  #include "coverage.h"
>  #include "daemon.h"
> +#include "datapath-config.h"
>  #include "dirs.h"
>  #include "dpif.h"
>  #include "dpdk.h"
> @@ -508,6 +509,7 @@ bridge_exit(bool delete_datapath)
>      HMAP_FOR_EACH_SAFE (br, next_br, node, &all_bridges) {
>          bridge_destroy(br, delete_datapath);
>      }
> +    destroy_all_datapaths();
>      ovsdb_idl_destroy(idl);
>  }
>  
> @@ -669,6 +671,7 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
>      }
>  
>      reconfigure_system_stats(ovs_cfg);
> +    reconfigure_datapath(ovs_cfg, idl_seqno);
>  
>      /* Complete the configuration. */
>      sflow_bridge_number = 0;
> -- 
> 2.7.4
> 
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
Darrell Ball July 27, 2019, 12:44 a.m. UTC | #2
Thanks for the patch; not a full review

On Thu, Jul 25, 2019 at 4:29 PM Yi-Hung Wei <yihung.wei@gmail.com> wrote:

> This patch reads the datapath, CT_Zone, and CT_Timeout_Policy tables
> from ovsdb, stores the information in a per datapath internal datapath
> structure, and pushes down the conntrack timeout policy into the
> datapath via dpif interface.
>
> The per datapath internal data structure will be used in
> ofproto-dpif-xlate to implement the zone-based timeout policy.
>
> Signed-off-by: Yi-Hung Wei <yihung.wei@gmail.com>
> ---
>  lib/automake.mk       |   2 +
>  lib/datapath-config.c | 379
> ++++++++++++++++++++++++++++++++++++++++++++++++++
>  lib/datapath-config.h |  25 ++++
>  vswitchd/bridge.c     |   3 +
>  4 files changed, 409 insertions(+)
>  create mode 100644 lib/datapath-config.c
>  create mode 100644 lib/datapath-config.h
>
> diff --git a/lib/automake.mk b/lib/automake.mk
> index 17b36b43d9d7..7532153f5d02 100644
> --- a/lib/automake.mk
> +++ b/lib/automake.mk
> @@ -67,6 +67,8 @@ lib_libopenvswitch_la_SOURCES = \
>         lib/daemon.c \
>         lib/daemon.h \
>         lib/daemon-private.h \
> +       lib/datapath-config.c \
> +       lib/datapath-config.h \
>         lib/db-ctl-base.c \
>         lib/db-ctl-base.h \
>         lib/dhcp.h \
> diff --git a/lib/datapath-config.c b/lib/datapath-config.c
> new file mode 100644
> index 000000000000..cdd2128a60bc
> --- /dev/null
> +++ b/lib/datapath-config.c
> @@ -0,0 +1,379 @@
> +/* Copyright (c) 2019 Nicira, Inc.
> + *
> + * Licensed under the Apache License, Version 2.0 (the "License");
> + * you may not use this file except in compliance with the License.
> + * You may obtain a copy of the License at:
> + *
> + *     http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing, software
> + * distributed under the License is distributed on an "AS IS" BASIS,
> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
> implied.
> + * See the License for the specific language governing permissions and
> + * limitations under the License.
> + */
> +
> +#include <config.h>
> +#include "datapath-config.h"
> +
> +#include "cmap.h"
> +#include "ct-dpif.h"
> +#include "dpif.h"
> +#include "openvswitch/vlog.h"
> +
> +VLOG_DEFINE_THIS_MODULE(datapath_config);
> +
> +struct ct_timeout_policy {
> +    struct uuid uuid;
> +    unsigned int last_used_seqno;
> +    unsigned int last_updated_seqno;
>

Can you add a usage comment for 'last_updated_seqno' and explain why it is
needed
in addition to 'last_used_seqno'  ?



> +    struct ct_dpif_timeout_policy cdtp;
> +    struct cmap_node node;          /* Element in struct datapath's
> +                                     * "ct_timeout_policies" cmap. */
> +};
> +
> +struct ct_zone {
> +    uint16_t id;
> +    unsigned int last_used_seqno;
> +    struct uuid tp_uuid;            /* uuid that identifies a timeout
> policy in
> +                                     * struct datapaths's "ct_tps cmap. */
> +    struct cmap_node node;          /* Element in struct datapath's
> "ct_zones"
> +                                     * cmap. */
> +};
> +
> +struct datapath {
> +    char *type;                     /* Datapath type. */
> +    char *dpif_backer_name;
> +    const struct ovsrec_datapath *cfg;
> +
> +    struct hmap_node node;          /* In 'all_datapaths'. */
> +    struct cmap ct_zones;           /* "struct ct_zone"s indexed by zone
> id. */
> +    struct cmap ct_tps;             /* "struct ct_timeout_policy"s
> indexed by
> +                                     * uuid. */
> +};
> +
> +/* All datapaths, indexed by type. */
> +static struct hmap all_datapaths = HMAP_INITIALIZER(&all_datapaths);
> +
> +static void ct_zone_destroy(struct datapath *, struct ct_zone *);
> +static void ct_timeout_policy_destroy(struct datapath *,
> +                                      struct ct_timeout_policy *,
> +                                      struct dpif *);
> +
> +static struct datapath *
> +datapath_lookup(const char *type)
> +{
> +    struct datapath *dp;
> +
> +    HMAP_FOR_EACH_WITH_HASH (dp, node, hash_string(type, 0),
> &all_datapaths) {
> +        if (!strcmp(dp->type, type)) {
> +            return dp;
> +        }
> +    }
> +    return NULL;
> +}
> +
> +static void
> +datapath_clear_timeout_policy(struct datapath *dp)
> +{
> +    struct ct_dpif_timeout_policy *tp;
> +    struct dpif *dpif;
> +    void *state;
> +    int err;
> +
> +    dpif_open(dp->dpif_backer_name, dp->type, &dpif);
> +    if (!dpif) {
> +        return;
> +    }
> +
> +    err = ct_dpif_timeout_policy_dump_start(dpif, &state);
> +    if (err) {
> +        return ;
> +    }
> +
> +    while (!(err = ct_dpif_timeout_policy_dump_next(dpif, state, &tp))) {
> +        ct_dpif_del_timeout_policy(dpif, tp->id);
> +        free(tp);
> +    }
> +
> +    ct_dpif_timeout_policy_dump_done(dpif, state);
> +    dpif_close(dpif);
> +}
> +
> +static struct datapath *
> +datapath_create(const struct ovsrec_datapath *dp_cfg, const char *type)
> +{
> +    struct datapath *dp;
> +
> +    ovs_assert(!datapath_lookup(type));
> +    dp = xzalloc(sizeof *dp);
> +
> +    dp->type = xstrdup(type);
> +    dp->dpif_backer_name = xasprintf("ovs-%s", type);
> +    dp->cfg = dp_cfg;
> +
> +    cmap_init(&dp->ct_zones);
> +    cmap_init(&dp->ct_tps);
> +
> +    datapath_clear_timeout_policy(dp);
> +    hmap_insert(&all_datapaths, &dp->node, hash_string(dp->type, 0));
> +    return dp;
> +}
> +
> +static void
> +datapath_destroy(struct datapath *dp)
> +{
> +    struct ct_zone *zone;
> +    struct ct_timeout_policy *tp;
> +    struct dpif *dpif;
> +
> +    if (dp) {
> +        CMAP_FOR_EACH (zone, node, &dp->ct_zones) {
> +            ct_zone_destroy(dp, zone);
> +        }
> +
> +        dpif_open(dp->dpif_backer_name, dp->type, &dpif);
> +
> +        CMAP_FOR_EACH (tp, node, &dp->ct_tps) {
> +            ct_timeout_policy_destroy(dp, tp, dpif);
> +        }
> +
> +        dpif_close(dpif);
> +        hmap_remove(&all_datapaths, &dp->node);
> +        cmap_destroy(&dp->ct_zones);
> +        cmap_destroy(&dp->ct_tps);
> +        free(dp->type);
> +        free(dp->dpif_backer_name);
> +        free(dp);
> +    }
> +}
> +
> +static void
> +add_del_datapaths(const struct ovsrec_open_vswitch *cfg)
> +{
> +    struct datapath *dp, *next;
> +    struct shash_node *node;
> +    struct shash new_dp;
> +    size_t i;
> +
> +    /* Collect new datapaths' type. */
> +    shash_init(&new_dp);
> +    for (i = 0; i < cfg->n_datapaths; i++) {
> +        const struct ovsrec_datapath *dp_cfg = cfg->value_datapaths[i];
> +        char *key = cfg->key_datapaths[i];
> +
> +        if (!strcmp(key, "system") || !strcmp(key, "netdev")) {
> +            shash_add(&new_dp, key, dp_cfg);
> +        } else {
> +            VLOG_WARN("Unsupported dpatapath type %s\n", key);
> +        }
> +    }
> +
> +    /* Get rid of deleted datapath. */
> +    HMAP_FOR_EACH_SAFE (dp, next, node, &all_datapaths) {
> +        dp->cfg = shash_find_data(&new_dp, dp->type);
> +        if (!dp->cfg) {
> +            datapath_destroy(dp);
> +        }
> +    }
> +
> +    /* Add new datapaths */
> +    SHASH_FOR_EACH (node, &new_dp) {
> +        const struct ovsrec_datapath *dp_cfg = node->data;
> +        if (!datapath_lookup(node->name)) {
> +            datapath_create(dp_cfg, node->name);
> +        }
> +    }
> +
> +    shash_destroy(&new_dp);
> +}
> +
> +static struct ct_zone *
> +ct_zone_lookup(struct cmap *ct_zones, uint16_t zone_id)
> +{
> +    struct ct_zone *zone;
> +
> +    CMAP_FOR_EACH_WITH_HASH (zone, node, hash_int(zone_id, 0), ct_zones) {
> +        if (zone->id == zone_id) {
> +            return zone;
> +        }
> +    }
> +    return NULL;
> +}
> +
> +static struct ct_zone *
> +ct_zone_alloc(uint16_t zone_id)
> +{
> +    struct ct_zone *zone;
> +
> +    zone = xzalloc(sizeof *zone);
> +    zone->id = zone_id;
> +
> +    return zone;
> +}
> +
> +static void
> +ct_zone_destroy(struct datapath *dp, struct ct_zone *zone)
> +{
> +    cmap_remove(&dp->ct_zones, &zone->node, hash_int(zone->id, 0));
> +    ovsrcu_postpone(free, zone);
> +}
> +
> +static struct ct_timeout_policy *
> +ct_timeout_policy_lookup(struct cmap *ct_tps, struct uuid *uuid)
> +{
> +    struct ct_timeout_policy *tp;
> +
> +    CMAP_FOR_EACH_WITH_HASH (tp, node, uuid_hash(uuid), ct_tps) {
> +        if (uuid_equals(&tp->uuid, uuid)) {
> +            return tp;
> +        }
> +    }
> +    return NULL;
> +}
> +
> +static struct ct_timeout_policy *
> +ct_timeout_policy_alloc(struct ovsrec_ct_timeout_policy *tp_cfg,
> +                        unsigned int idl_seqno)
> +{
> +    struct ct_timeout_policy *tp;
> +    size_t i;
> +
> +    tp = xzalloc(sizeof *tp);
> +    tp->uuid = tp_cfg->header_.uuid;
> +    for (i = 0; i < tp_cfg->n_timeouts; i++) {
> +        ct_dpif_set_timeout_policy_attr_by_name(&tp->cdtp,
> +            tp_cfg->key_timeouts[i], tp_cfg->value_timeouts[i]);
> +    }
> +    tp->cdtp.id = idl_seqno;
> +    tp->last_updated_seqno = idl_seqno;
> +
> +    return tp;
> +}
> +
> +static bool
> +ct_timeout_policy_update(struct ovsrec_ct_timeout_policy *tp_cfg,
> +                         struct ct_timeout_policy *tp,
> +                         unsigned int idl_seqno)
> +{
> +    size_t i;
> +    bool changed = false;
> +
> +    for (i = 0; i < tp_cfg->n_timeouts; i++) {
> +        changed |= ct_dpif_set_timeout_policy_attr_by_name(&tp->cdtp,
> +                        tp_cfg->key_timeouts[i],
> tp_cfg->value_timeouts[i]);
> +    }
> +    if (changed) {
> +        tp->last_updated_seqno = idl_seqno;
> +    }
> +    return changed;
> +}
> +
> +static void
> +ct_timeout_policy_destroy(struct datapath *dp, struct ct_timeout_policy
> *tp,
> +                          struct dpif *dpif)
> +{
> +    cmap_remove(&dp->ct_tps, &tp->node, uuid_hash(&tp->uuid));
> +    if (dpif) {
> +        ct_dpif_del_timeout_policy(dpif, tp->cdtp.id);
> +    }
> +    ovsrcu_postpone(free, tp);
> +}
> +
> +static void
> +datapath_update_ct_zone_config(struct datapath *dp, struct dpif *dpif,
> +                               unsigned int idl_seqno)
> +{
> +    const struct ovsrec_datapath *dp_cfg = dp->cfg;
> +    struct ovsrec_ct_timeout_policy *tp_cfg;
> +    struct ovsrec_ct_zone *zone_cfg;
> +    struct ct_timeout_policy *tp;
> +    struct ct_zone *zone;
> +    uint16_t zone_id;
> +    bool new_zone;
> +    size_t i;
> +
> +    for (i = 0; i < dp_cfg->n_ct_zones; i++) {
> +        /* Update ct_zone config */
> +        zone_cfg = dp_cfg->value_ct_zones[i];
> +        zone_id = dp_cfg->key_ct_zones[i];
> +        zone = ct_zone_lookup(&dp->ct_zones, zone_id);
> +        if (!zone) {
> +            new_zone = true;
> +            zone = ct_zone_alloc(zone_id);
> +        } else {
> +            new_zone = false;
> +        }
> +        zone->last_used_seqno = idl_seqno;
> +
> +        /* Update timeout policy */
> +        tp_cfg = zone_cfg->timeout_policy;
> +        tp = ct_timeout_policy_lookup(&dp->ct_tps, &tp_cfg->header_.uuid);
> +        if (!tp) {
> +            tp = ct_timeout_policy_alloc(tp_cfg, idl_seqno);
> +            cmap_insert(&dp->ct_tps, &tp->node, uuid_hash(&tp->uuid));
> +            if (dpif) {
> +                ct_dpif_add_timeout_policy(dpif, false, &tp->cdtp);
> +            }
> +        } else {
> +            if (ct_timeout_policy_update(tp_cfg, tp, idl_seqno)) {
> +                if (dpif) {
> +                    ct_dpif_add_timeout_policy(dpif, false, &tp->cdtp);
> +                }
> +            }
> +        }
> +        tp->last_used_seqno = idl_seqno;
> +
> +        /* Update default timeout policy */
> +        if (!zone_id && tp->last_updated_seqno == idl_seqno) {
>


If zone==0, we will configure a default timeout policy.
In Netfilter this will be nw_proto scope and shared across V4/V6
i.e. the global Netfilter values

I eluded to this in a previous patch.
We need to document it
Maybe we need to present it better.


+            ct_dpif_add_timeout_policy(dpif, true, &tp->cdtp);
> +        }
> +
> +        /* Link zone with new timeout policy */
> +        zone->tp_uuid = tp_cfg->header_.uuid;
> +        if (new_zone) {
> +            cmap_insert(&dp->ct_zones, &zone->node, hash_int(zone_id, 0));
> +        }
> +    }
> +}
> +
> +void
> +reconfigure_datapath(const struct ovsrec_open_vswitch *cfg,
> +                     unsigned int idl_seqno)
> +{
> +    struct ct_timeout_policy *tp;
> +    struct ct_zone *zone;
> +    struct datapath *dp;
> +    struct dpif *dpif;
> +
> +    add_del_datapaths(cfg);
> +    HMAP_FOR_EACH (dp, node, &all_datapaths) {
> +        dpif_open(dp->dpif_backer_name, dp->type, &dpif);
> +
> +        datapath_update_ct_zone_config(dp, dpif, idl_seqno);
> +
> +        /* Garbage colleciton */
> +        CMAP_FOR_EACH (zone, node, &dp->ct_zones) {
> +            if (zone->last_used_seqno != idl_seqno) {
> +                ct_zone_destroy(dp, zone);
> +            }
> +        }
> +        CMAP_FOR_EACH (tp, node, &dp->ct_tps) {
> +            if (tp->last_used_seqno != idl_seqno) {
> +                ct_timeout_policy_destroy(dp, tp, dpif);
> +            }
> +        }
> +
> +        dpif_close(dpif);
> +    }
> +}
> +
> +void
> +destroy_all_datapaths(void)
> +{
> +    struct datapath *dp, *next_dp;
> +
> +    HMAP_FOR_EACH_SAFE (dp, next_dp, node, &all_datapaths) {
> +        datapath_destroy(dp);
> +    }
> +}
> diff --git a/lib/datapath-config.h b/lib/datapath-config.h
> new file mode 100644
> index 000000000000..d9a90e4f8312
> --- /dev/null
> +++ b/lib/datapath-config.h
> @@ -0,0 +1,25 @@
> +/* Copyright (c) 2019 Nicira, Inc.
> + *
> + * Licensed under the Apache License, Version 2.0 (the "License");
> + * you may not use this file except in compliance with the License.
> + * You may obtain a copy of the License at:
> + *
> + *     http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing, software
> + * distributed under the License is distributed on an "AS IS" BASIS,
> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
> implied.
> + * See the License for the specific language governing permissions and
> + * limitations under the License.
> + */
> +
> +#ifndef DATAPATH_CONFIG_H
> +#define DATAPATH_CONFIG_H 1
> +
> +#include "vswitch-idl.h"
> +
> +void reconfigure_datapath(const struct ovsrec_open_vswitch *,
> +                          unsigned int idl_seqno);
> +void destroy_all_datapaths(void);
> +
> +#endif /* datapath-config.h */
> diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
> index 2976771aeaba..e8ac24a50ff2 100644
> --- a/vswitchd/bridge.c
> +++ b/vswitchd/bridge.c
> @@ -26,6 +26,7 @@
>  #include "connectivity.h"
>  #include "coverage.h"
>  #include "daemon.h"
> +#include "datapath-config.h"
>  #include "dirs.h"
>  #include "dpif.h"
>  #include "dpdk.h"
> @@ -508,6 +509,7 @@ bridge_exit(bool delete_datapath)
>      HMAP_FOR_EACH_SAFE (br, next_br, node, &all_bridges) {
>          bridge_destroy(br, delete_datapath);
>      }
> +    destroy_all_datapaths();
>      ovsdb_idl_destroy(idl);
>  }
>
> @@ -669,6 +671,7 @@ bridge_reconfigure(const struct ovsrec_open_vswitch
> *ovs_cfg)
>      }
>
>      reconfigure_system_stats(ovs_cfg);
> +    reconfigure_datapath(ovs_cfg, idl_seqno);
>
>      /* Complete the configuration. */
>      sflow_bridge_number = 0;
> --
> 2.7.4
>
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
Darrell Ball July 29, 2019, 5:48 a.m. UTC | #3
One more comment

Not a full review; just focusing on the more important parts for now.


On Fri, Jul 26, 2019 at 5:44 PM Darrell Ball <dlu998@gmail.com> wrote:

> Thanks for the patch; not a full review
>
> On Thu, Jul 25, 2019 at 4:29 PM Yi-Hung Wei <yihung.wei@gmail.com> wrote:
>
>> This patch reads the datapath, CT_Zone, and CT_Timeout_Policy tables
>> from ovsdb, stores the information in a per datapath internal datapath
>> structure, and pushes down the conntrack timeout policy into the
>> datapath via dpif interface.
>>
>> The per datapath internal data structure will be used in
>> ofproto-dpif-xlate to implement the zone-based timeout policy.
>>
>> Signed-off-by: Yi-Hung Wei <yihung.wei@gmail.com>
>> ---
>>  lib/automake.mk       |   2 +
>>  lib/datapath-config.c | 379
>> ++++++++++++++++++++++++++++++++++++++++++++++++++
>>  lib/datapath-config.h |  25 ++++
>>  vswitchd/bridge.c     |   3 +
>>  4 files changed, 409 insertions(+)
>>  create mode 100644 lib/datapath-config.c
>>  create mode 100644 lib/datapath-config.h
>>
>> diff --git a/lib/automake.mk b/lib/automake.mk
>> index 17b36b43d9d7..7532153f5d02 100644
>> --- a/lib/automake.mk
>> +++ b/lib/automake.mk
>> @@ -67,6 +67,8 @@ lib_libopenvswitch_la_SOURCES = \
>>         lib/daemon.c \
>>         lib/daemon.h \
>>         lib/daemon-private.h \
>> +       lib/datapath-config.c \
>> +       lib/datapath-config.h \
>>         lib/db-ctl-base.c \
>>         lib/db-ctl-base.h \
>>         lib/dhcp.h \
>> diff --git a/lib/datapath-config.c b/lib/datapath-config.c
>> new file mode 100644
>> index 000000000000..cdd2128a60bc
>> --- /dev/null
>> +++ b/lib/datapath-config.c
>> @@ -0,0 +1,379 @@
>> +/* Copyright (c) 2019 Nicira, Inc.
>> + *
>> + * Licensed under the Apache License, Version 2.0 (the "License");
>> + * you may not use this file except in compliance with the License.
>> + * You may obtain a copy of the License at:
>> + *
>> + *     http://www.apache.org/licenses/LICENSE-2.0
>> + *
>> + * Unless required by applicable law or agreed to in writing, software
>> + * distributed under the License is distributed on an "AS IS" BASIS,
>> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
>> implied.
>> + * See the License for the specific language governing permissions and
>> + * limitations under the License.
>> + */
>> +
>> +#include <config.h>
>> +#include "datapath-config.h"
>> +
>> +#include "cmap.h"
>> +#include "ct-dpif.h"
>> +#include "dpif.h"
>> +#include "openvswitch/vlog.h"
>> +
>> +VLOG_DEFINE_THIS_MODULE(datapath_config);
>> +
>> +struct ct_timeout_policy {
>> +    struct uuid uuid;
>> +    unsigned int last_used_seqno;
>> +    unsigned int last_updated_seqno;
>>
>
> Can you add a usage comment for 'last_updated_seqno' and explain why it is
> needed
> in addition to 'last_used_seqno'  ?
>
>
>
>> +    struct ct_dpif_timeout_policy cdtp;
>> +    struct cmap_node node;          /* Element in struct datapath's
>> +                                     * "ct_timeout_policies" cmap. */
>> +};
>> +
>> +struct ct_zone {
>> +    uint16_t id;
>> +    unsigned int last_used_seqno;
>> +    struct uuid tp_uuid;            /* uuid that identifies a timeout
>> policy in
>> +                                     * struct datapaths's "ct_tps cmap.
>> */
>> +    struct cmap_node node;          /* Element in struct datapath's
>> "ct_zones"
>> +                                     * cmap. */
>> +};
>> +
>> +struct datapath {
>> +    char *type;                     /* Datapath type. */
>> +    char *dpif_backer_name;
>> +    const struct ovsrec_datapath *cfg;
>> +
>> +    struct hmap_node node;          /* In 'all_datapaths'. */
>> +    struct cmap ct_zones;           /* "struct ct_zone"s indexed by zone
>> id. */
>> +    struct cmap ct_tps;             /* "struct ct_timeout_policy"s
>> indexed by
>> +                                     * uuid. */
>> +};
>> +
>> +/* All datapaths, indexed by type. */
>> +static struct hmap all_datapaths = HMAP_INITIALIZER(&all_datapaths);
>> +
>> +static void ct_zone_destroy(struct datapath *, struct ct_zone *);
>> +static void ct_timeout_policy_destroy(struct datapath *,
>> +                                      struct ct_timeout_policy *,
>> +                                      struct dpif *);
>> +
>> +static struct datapath *
>> +datapath_lookup(const char *type)
>> +{
>> +    struct datapath *dp;
>> +
>> +    HMAP_FOR_EACH_WITH_HASH (dp, node, hash_string(type, 0),
>> &all_datapaths) {
>> +        if (!strcmp(dp->type, type)) {
>> +            return dp;
>> +        }
>> +    }
>> +    return NULL;
>> +}
>> +
>> +static void
>> +datapath_clear_timeout_policy(struct datapath *dp)
>> +{
>> +    struct ct_dpif_timeout_policy *tp;
>> +    struct dpif *dpif;
>> +    void *state;
>> +    int err;
>> +
>> +    dpif_open(dp->dpif_backer_name, dp->type, &dpif);
>> +    if (!dpif) {
>> +        return;
>> +    }
>> +
>> +    err = ct_dpif_timeout_policy_dump_start(dpif, &state);
>> +    if (err) {
>> +        return ;
>> +    }
>> +
>> +    while (!(err = ct_dpif_timeout_policy_dump_next(dpif, state, &tp))) {
>> +        ct_dpif_del_timeout_policy(dpif, tp->id);
>> +        free(tp);
>> +    }
>> +
>> +    ct_dpif_timeout_policy_dump_done(dpif, state);
>> +    dpif_close(dpif);
>> +}
>> +
>> +static struct datapath *
>> +datapath_create(const struct ovsrec_datapath *dp_cfg, const char *type)
>> +{
>> +    struct datapath *dp;
>> +
>> +    ovs_assert(!datapath_lookup(type));
>> +    dp = xzalloc(sizeof *dp);
>> +
>> +    dp->type = xstrdup(type);
>> +    dp->dpif_backer_name = xasprintf("ovs-%s", type);
>> +    dp->cfg = dp_cfg;
>> +
>> +    cmap_init(&dp->ct_zones);
>> +    cmap_init(&dp->ct_tps);
>> +
>> +    datapath_clear_timeout_policy(dp);
>> +    hmap_insert(&all_datapaths, &dp->node, hash_string(dp->type, 0));
>> +    return dp;
>> +}
>> +
>> +static void
>> +datapath_destroy(struct datapath *dp)
>> +{
>> +    struct ct_zone *zone;
>> +    struct ct_timeout_policy *tp;
>> +    struct dpif *dpif;
>> +
>> +    if (dp) {
>> +        CMAP_FOR_EACH (zone, node, &dp->ct_zones) {
>> +            ct_zone_destroy(dp, zone);
>> +        }
>> +
>> +        dpif_open(dp->dpif_backer_name, dp->type, &dpif);
>> +
>> +        CMAP_FOR_EACH (tp, node, &dp->ct_tps) {
>> +            ct_timeout_policy_destroy(dp, tp, dpif);
>> +        }
>> +
>> +        dpif_close(dpif);
>> +        hmap_remove(&all_datapaths, &dp->node);
>> +        cmap_destroy(&dp->ct_zones);
>> +        cmap_destroy(&dp->ct_tps);
>> +        free(dp->type);
>> +        free(dp->dpif_backer_name);
>> +        free(dp);
>> +    }
>> +}
>> +
>> +static void
>> +add_del_datapaths(const struct ovsrec_open_vswitch *cfg)
>> +{
>> +    struct datapath *dp, *next;
>> +    struct shash_node *node;
>> +    struct shash new_dp;
>> +    size_t i;
>> +
>> +    /* Collect new datapaths' type. */
>> +    shash_init(&new_dp);
>> +    for (i = 0; i < cfg->n_datapaths; i++) {
>> +        const struct ovsrec_datapath *dp_cfg = cfg->value_datapaths[i];
>> +        char *key = cfg->key_datapaths[i];
>> +
>> +        if (!strcmp(key, "system") || !strcmp(key, "netdev")) {
>> +            shash_add(&new_dp, key, dp_cfg);
>> +        } else {
>> +            VLOG_WARN("Unsupported dpatapath type %s\n", key);
>> +        }
>> +    }
>> +
>> +    /* Get rid of deleted datapath. */
>> +    HMAP_FOR_EACH_SAFE (dp, next, node, &all_datapaths) {
>> +        dp->cfg = shash_find_data(&new_dp, dp->type);
>> +        if (!dp->cfg) {
>> +            datapath_destroy(dp);
>> +        }
>> +    }
>> +
>> +    /* Add new datapaths */
>> +    SHASH_FOR_EACH (node, &new_dp) {
>> +        const struct ovsrec_datapath *dp_cfg = node->data;
>> +        if (!datapath_lookup(node->name)) {
>> +            datapath_create(dp_cfg, node->name);
>> +        }
>> +    }
>> +
>> +    shash_destroy(&new_dp);
>> +}
>> +
>> +static struct ct_zone *
>> +ct_zone_lookup(struct cmap *ct_zones, uint16_t zone_id)
>> +{
>> +    struct ct_zone *zone;
>> +
>> +    CMAP_FOR_EACH_WITH_HASH (zone, node, hash_int(zone_id, 0), ct_zones)
>> {
>> +        if (zone->id == zone_id) {
>> +            return zone;
>> +        }
>> +    }
>> +    return NULL;
>> +}
>> +
>> +static struct ct_zone *
>> +ct_zone_alloc(uint16_t zone_id)
>> +{
>> +    struct ct_zone *zone;
>> +
>> +    zone = xzalloc(sizeof *zone);
>> +    zone->id = zone_id;
>> +
>> +    return zone;
>> +}
>> +
>> +static void
>> +ct_zone_destroy(struct datapath *dp, struct ct_zone *zone)
>> +{
>> +    cmap_remove(&dp->ct_zones, &zone->node, hash_int(zone->id, 0));
>> +    ovsrcu_postpone(free, zone);
>> +}
>> +
>> +static struct ct_timeout_policy *
>> +ct_timeout_policy_lookup(struct cmap *ct_tps, struct uuid *uuid)
>> +{
>> +    struct ct_timeout_policy *tp;
>> +
>> +    CMAP_FOR_EACH_WITH_HASH (tp, node, uuid_hash(uuid), ct_tps) {
>> +        if (uuid_equals(&tp->uuid, uuid)) {
>> +            return tp;
>> +        }
>> +    }
>> +    return NULL;
>> +}
>> +
>> +static struct ct_timeout_policy *
>> +ct_timeout_policy_alloc(struct ovsrec_ct_timeout_policy *tp_cfg,
>> +                        unsigned int idl_seqno)
>> +{
>> +    struct ct_timeout_policy *tp;
>> +    size_t i;
>> +
>> +    tp = xzalloc(sizeof *tp);
>> +    tp->uuid = tp_cfg->header_.uuid;
>> +    for (i = 0; i < tp_cfg->n_timeouts; i++) {
>> +        ct_dpif_set_timeout_policy_attr_by_name(&tp->cdtp,
>> +            tp_cfg->key_timeouts[i], tp_cfg->value_timeouts[i]);
>> +    }
>> +    tp->cdtp.id = idl_seqno;
>> +    tp->last_updated_seqno = idl_seqno;
>>
>
I am not sure this datapath timeout profile ID allocation scheme is going
to work.

1/ I think one change in the idL_seqno can be associated with multiple
changes in the DB;
for example we can add multiple timeout profiles with one seqno change, in
which
case all these profiles would get the same datapath timeout profile ID.

2/ What happens when vswitchd restarts.
If you want to delete a profile from the kernel, how do you know the
datapath profile ID ?
When you want to add a profile, I think you could end with trying to use
the same ID as an
existing different profile in the kernel.

I think you want to use an ID pool (see id-pool.c/.h) to allocate datapath
profile IDs
and then store the ID in the external ID column of the timeout profile in
the DB
When vswitchd restarts, you need to re-populate your datastructures,
including the
datapath profile IDs.

+
>> +    return tp;
>> +}
>> +
>> +static bool
>> +ct_timeout_policy_update(struct ovsrec_ct_timeout_policy *tp_cfg,
>> +                         struct ct_timeout_policy *tp,
>> +                         unsigned int idl_seqno)
>> +{
>> +    size_t i;
>> +    bool changed = false;
>> +
>> +    for (i = 0; i < tp_cfg->n_timeouts; i++) {
>> +        changed |= ct_dpif_set_timeout_policy_attr_by_name(&tp->cdtp,
>> +                        tp_cfg->key_timeouts[i],
>> tp_cfg->value_timeouts[i]);
>> +    }
>> +    if (changed) {
>> +        tp->last_updated_seqno = idl_seqno;
>> +    }
>> +    return changed;
>> +}
>> +
>> +static void
>> +ct_timeout_policy_destroy(struct datapath *dp, struct ct_timeout_policy
>> *tp,
>> +                          struct dpif *dpif)
>> +{
>> +    cmap_remove(&dp->ct_tps, &tp->node, uuid_hash(&tp->uuid));
>> +    if (dpif) {
>> +        ct_dpif_del_timeout_policy(dpif, tp->cdtp.id);
>> +    }
>> +    ovsrcu_postpone(free, tp);
>> +}
>> +
>> +static void
>> +datapath_update_ct_zone_config(struct datapath *dp, struct dpif *dpif,
>> +                               unsigned int idl_seqno)
>> +{
>> +    const struct ovsrec_datapath *dp_cfg = dp->cfg;
>> +    struct ovsrec_ct_timeout_policy *tp_cfg;
>> +    struct ovsrec_ct_zone *zone_cfg;
>> +    struct ct_timeout_policy *tp;
>> +    struct ct_zone *zone;
>> +    uint16_t zone_id;
>> +    bool new_zone;
>> +    size_t i;
>> +
>> +    for (i = 0; i < dp_cfg->n_ct_zones; i++) {
>> +        /* Update ct_zone config */
>> +        zone_cfg = dp_cfg->value_ct_zones[i];
>> +        zone_id = dp_cfg->key_ct_zones[i];
>> +        zone = ct_zone_lookup(&dp->ct_zones, zone_id);
>> +        if (!zone) {
>> +            new_zone = true;
>> +            zone = ct_zone_alloc(zone_id);
>> +        } else {
>> +            new_zone = false;
>> +        }
>> +        zone->last_used_seqno = idl_seqno;
>> +
>> +        /* Update timeout policy */
>> +        tp_cfg = zone_cfg->timeout_policy;
>> +        tp = ct_timeout_policy_lookup(&dp->ct_tps,
>> &tp_cfg->header_.uuid);
>> +        if (!tp) {
>> +            tp = ct_timeout_policy_alloc(tp_cfg, idl_seqno);
>> +            cmap_insert(&dp->ct_tps, &tp->node, uuid_hash(&tp->uuid));
>> +            if (dpif) {
>> +                ct_dpif_add_timeout_policy(dpif, false, &tp->cdtp);
>> +            }
>> +        } else {
>> +            if (ct_timeout_policy_update(tp_cfg, tp, idl_seqno)) {
>> +                if (dpif) {
>> +                    ct_dpif_add_timeout_policy(dpif, false, &tp->cdtp);
>> +                }
>> +            }
>> +        }
>> +        tp->last_used_seqno = idl_seqno;
>> +
>> +        /* Update default timeout policy */
>> +        if (!zone_id && tp->last_updated_seqno == idl_seqno) {
>>
>
>
> If zone==0, we will configure a default timeout policy.
> In Netfilter this will be nw_proto scope and shared across V4/V6
> i.e. the global Netfilter values
>
> I eluded to this in a previous patch.
> We need to document it
> Maybe we need to present it better.
>
>
> +            ct_dpif_add_timeout_policy(dpif, true, &tp->cdtp);
>> +        }
>> +
>> +        /* Link zone with new timeout policy */
>> +        zone->tp_uuid = tp_cfg->header_.uuid;
>> +        if (new_zone) {
>> +            cmap_insert(&dp->ct_zones, &zone->node, hash_int(zone_id,
>> 0));
>> +        }
>> +    }
>> +}
>> +
>> +void
>> +reconfigure_datapath(const struct ovsrec_open_vswitch *cfg,
>> +                     unsigned int idl_seqno)
>> +{
>> +    struct ct_timeout_policy *tp;
>> +    struct ct_zone *zone;
>> +    struct datapath *dp;
>> +    struct dpif *dpif;
>> +
>> +    add_del_datapaths(cfg);
>> +    HMAP_FOR_EACH (dp, node, &all_datapaths) {
>> +        dpif_open(dp->dpif_backer_name, dp->type, &dpif);
>> +
>> +        datapath_update_ct_zone_config(dp, dpif, idl_seqno);
>> +
>> +        /* Garbage colleciton */
>> +        CMAP_FOR_EACH (zone, node, &dp->ct_zones) {
>> +            if (zone->last_used_seqno != idl_seqno) {
>> +                ct_zone_destroy(dp, zone);
>> +            }
>> +        }
>> +        CMAP_FOR_EACH (tp, node, &dp->ct_tps) {
>> +            if (tp->last_used_seqno != idl_seqno) {
>> +                ct_timeout_policy_destroy(dp, tp, dpif);
>> +            }
>> +        }
>> +
>> +        dpif_close(dpif);
>> +    }
>> +}
>> +
>> +void
>> +destroy_all_datapaths(void)
>> +{
>> +    struct datapath *dp, *next_dp;
>> +
>> +    HMAP_FOR_EACH_SAFE (dp, next_dp, node, &all_datapaths) {
>> +        datapath_destroy(dp);
>> +    }
>> +}
>> diff --git a/lib/datapath-config.h b/lib/datapath-config.h
>> new file mode 100644
>> index 000000000000..d9a90e4f8312
>> --- /dev/null
>> +++ b/lib/datapath-config.h
>> @@ -0,0 +1,25 @@
>> +/* Copyright (c) 2019 Nicira, Inc.
>> + *
>> + * Licensed under the Apache License, Version 2.0 (the "License");
>> + * you may not use this file except in compliance with the License.
>> + * You may obtain a copy of the License at:
>> + *
>> + *     http://www.apache.org/licenses/LICENSE-2.0
>> + *
>> + * Unless required by applicable law or agreed to in writing, software
>> + * distributed under the License is distributed on an "AS IS" BASIS,
>> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
>> implied.
>> + * See the License for the specific language governing permissions and
>> + * limitations under the License.
>> + */
>> +
>> +#ifndef DATAPATH_CONFIG_H
>> +#define DATAPATH_CONFIG_H 1
>> +
>> +#include "vswitch-idl.h"
>> +
>> +void reconfigure_datapath(const struct ovsrec_open_vswitch *,
>> +                          unsigned int idl_seqno);
>> +void destroy_all_datapaths(void);
>> +
>> +#endif /* datapath-config.h */
>> diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
>> index 2976771aeaba..e8ac24a50ff2 100644
>> --- a/vswitchd/bridge.c
>> +++ b/vswitchd/bridge.c
>> @@ -26,6 +26,7 @@
>>  #include "connectivity.h"
>>  #include "coverage.h"
>>  #include "daemon.h"
>> +#include "datapath-config.h"
>>  #include "dirs.h"
>>  #include "dpif.h"
>>  #include "dpdk.h"
>> @@ -508,6 +509,7 @@ bridge_exit(bool delete_datapath)
>>      HMAP_FOR_EACH_SAFE (br, next_br, node, &all_bridges) {
>>          bridge_destroy(br, delete_datapath);
>>      }
>> +    destroy_all_datapaths();
>>      ovsdb_idl_destroy(idl);
>>  }
>>
>> @@ -669,6 +671,7 @@ bridge_reconfigure(const struct ovsrec_open_vswitch
>> *ovs_cfg)
>>      }
>>
>>      reconfigure_system_stats(ovs_cfg);
>> +    reconfigure_datapath(ovs_cfg, idl_seqno);
>>
>>      /* Complete the configuration. */
>>      sflow_bridge_number = 0;
>> --
>> 2.7.4
>>
>> _______________________________________________
>> dev mailing list
>> dev@openvswitch.org
>> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>>
>
Yi-Hung Wei July 29, 2019, 10:52 p.m. UTC | #4
On Fri, Jul 26, 2019 at 1:22 PM William Tu <u9012063@gmail.com> wrote:
> > +static void
> > +datapath_update_ct_zone_config(struct datapath *dp, struct dpif *dpif,
> > +                               unsigned int idl_seqno)
> > +{
> > +    const struct ovsrec_datapath *dp_cfg = dp->cfg;
> > +    struct ovsrec_ct_timeout_policy *tp_cfg;
> > +    struct ovsrec_ct_zone *zone_cfg;
> > +    struct ct_timeout_policy *tp;
> > +    struct ct_zone *zone;
> > +    uint16_t zone_id;
> > +    bool new_zone;
> > +    size_t i;
> > +
> > +    for (i = 0; i < dp_cfg->n_ct_zones; i++) {
> > +        /* Update ct_zone config */
> > +        zone_cfg = dp_cfg->value_ct_zones[i];
> > +        zone_id = dp_cfg->key_ct_zones[i];
> > +        zone = ct_zone_lookup(&dp->ct_zones, zone_id);
> > +        if (!zone) {
> > +            new_zone = true;
> > +            zone = ct_zone_alloc(zone_id);
> > +        } else {
> > +            new_zone = false;
> > +        }
> > +        zone->last_used_seqno = idl_seqno;
> > +
> > +        /* Update timeout policy */
> missing .
> > +        tp_cfg = zone_cfg->timeout_policy;
> > +        tp = ct_timeout_policy_lookup(&dp->ct_tps, &tp_cfg->header_.uuid);
> > +        if (!tp) {
> > +            tp = ct_timeout_policy_alloc(tp_cfg, idl_seqno);
> > +            cmap_insert(&dp->ct_tps, &tp->node, uuid_hash(&tp->uuid));
> > +            if (dpif) {
> > +                ct_dpif_add_timeout_policy(dpif, false, &tp->cdtp);
> > +            }
> > +        } else {
> > +            if (ct_timeout_policy_update(tp_cfg, tp, idl_seqno)) {
> > +                if (dpif) {
> > +                    ct_dpif_add_timeout_policy(dpif, false, &tp->cdtp);
> > +                }
> > +            }
> > +        }
> > +        tp->last_used_seqno = idl_seqno;
> > +
> > +        /* Update default timeout policy */
>
> missing . and some places below
>
> > +        if (!zone_id && tp->last_updated_seqno == idl_seqno) {
> > +            ct_dpif_add_timeout_policy(dpif, true, &tp->cdtp);
>
> Do we need to check 'if (dpif)' here?
> You have the checking above, but not here. Or should we just return
> error when dpif is NULL.
Thanks for review. I will check if dpif is NULL and address the
comment issue in v2.

Thanks,

-Yi-Hung
diff mbox series

Patch

diff --git a/lib/automake.mk b/lib/automake.mk
index 17b36b43d9d7..7532153f5d02 100644
--- a/lib/automake.mk
+++ b/lib/automake.mk
@@ -67,6 +67,8 @@  lib_libopenvswitch_la_SOURCES = \
 	lib/daemon.c \
 	lib/daemon.h \
 	lib/daemon-private.h \
+	lib/datapath-config.c \
+	lib/datapath-config.h \
 	lib/db-ctl-base.c \
 	lib/db-ctl-base.h \
 	lib/dhcp.h \
diff --git a/lib/datapath-config.c b/lib/datapath-config.c
new file mode 100644
index 000000000000..cdd2128a60bc
--- /dev/null
+++ b/lib/datapath-config.c
@@ -0,0 +1,379 @@ 
+/* Copyright (c) 2019 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+#include "datapath-config.h"
+
+#include "cmap.h"
+#include "ct-dpif.h"
+#include "dpif.h"
+#include "openvswitch/vlog.h"
+
+VLOG_DEFINE_THIS_MODULE(datapath_config);
+
+struct ct_timeout_policy {
+    struct uuid uuid;
+    unsigned int last_used_seqno;
+    unsigned int last_updated_seqno;
+    struct ct_dpif_timeout_policy cdtp;
+    struct cmap_node node;          /* Element in struct datapath's
+                                     * "ct_timeout_policies" cmap. */
+};
+
+struct ct_zone {
+    uint16_t id;
+    unsigned int last_used_seqno;
+    struct uuid tp_uuid;            /* uuid that identifies a timeout policy in
+                                     * struct datapaths's "ct_tps cmap. */
+    struct cmap_node node;          /* Element in struct datapath's "ct_zones"
+                                     * cmap. */
+};
+
+struct datapath {
+    char *type;                     /* Datapath type. */
+    char *dpif_backer_name;
+    const struct ovsrec_datapath *cfg;
+
+    struct hmap_node node;          /* In 'all_datapaths'. */
+    struct cmap ct_zones;           /* "struct ct_zone"s indexed by zone id. */
+    struct cmap ct_tps;             /* "struct ct_timeout_policy"s indexed by
+                                     * uuid. */
+};
+
+/* All datapaths, indexed by type. */
+static struct hmap all_datapaths = HMAP_INITIALIZER(&all_datapaths);
+
+static void ct_zone_destroy(struct datapath *, struct ct_zone *);
+static void ct_timeout_policy_destroy(struct datapath *,
+                                      struct ct_timeout_policy *,
+                                      struct dpif *);
+
+static struct datapath *
+datapath_lookup(const char *type)
+{
+    struct datapath *dp;
+
+    HMAP_FOR_EACH_WITH_HASH (dp, node, hash_string(type, 0), &all_datapaths) {
+        if (!strcmp(dp->type, type)) {
+            return dp;
+        }
+    }
+    return NULL;
+}
+
+static void
+datapath_clear_timeout_policy(struct datapath *dp)
+{
+    struct ct_dpif_timeout_policy *tp;
+    struct dpif *dpif;
+    void *state;
+    int err;
+
+    dpif_open(dp->dpif_backer_name, dp->type, &dpif);
+    if (!dpif) {
+        return;
+    }
+
+    err = ct_dpif_timeout_policy_dump_start(dpif, &state);
+    if (err) {
+        return ;
+    }
+
+    while (!(err = ct_dpif_timeout_policy_dump_next(dpif, state, &tp))) {
+        ct_dpif_del_timeout_policy(dpif, tp->id);
+        free(tp);
+    }
+
+    ct_dpif_timeout_policy_dump_done(dpif, state);
+    dpif_close(dpif);
+}
+
+static struct datapath *
+datapath_create(const struct ovsrec_datapath *dp_cfg, const char *type)
+{
+    struct datapath *dp;
+
+    ovs_assert(!datapath_lookup(type));
+    dp = xzalloc(sizeof *dp);
+
+    dp->type = xstrdup(type);
+    dp->dpif_backer_name = xasprintf("ovs-%s", type);
+    dp->cfg = dp_cfg;
+
+    cmap_init(&dp->ct_zones);
+    cmap_init(&dp->ct_tps);
+
+    datapath_clear_timeout_policy(dp);
+    hmap_insert(&all_datapaths, &dp->node, hash_string(dp->type, 0));
+    return dp;
+}
+
+static void
+datapath_destroy(struct datapath *dp)
+{
+    struct ct_zone *zone;
+    struct ct_timeout_policy *tp;
+    struct dpif *dpif;
+
+    if (dp) {
+        CMAP_FOR_EACH (zone, node, &dp->ct_zones) {
+            ct_zone_destroy(dp, zone);
+        }
+
+        dpif_open(dp->dpif_backer_name, dp->type, &dpif);
+
+        CMAP_FOR_EACH (tp, node, &dp->ct_tps) {
+            ct_timeout_policy_destroy(dp, tp, dpif);
+        }
+
+        dpif_close(dpif);
+        hmap_remove(&all_datapaths, &dp->node);
+        cmap_destroy(&dp->ct_zones);
+        cmap_destroy(&dp->ct_tps);
+        free(dp->type);
+        free(dp->dpif_backer_name);
+        free(dp);
+    }
+}
+
+static void
+add_del_datapaths(const struct ovsrec_open_vswitch *cfg)
+{
+    struct datapath *dp, *next;
+    struct shash_node *node;
+    struct shash new_dp;
+    size_t i;
+
+    /* Collect new datapaths' type. */
+    shash_init(&new_dp);
+    for (i = 0; i < cfg->n_datapaths; i++) {
+        const struct ovsrec_datapath *dp_cfg = cfg->value_datapaths[i];
+        char *key = cfg->key_datapaths[i];
+
+        if (!strcmp(key, "system") || !strcmp(key, "netdev")) {
+            shash_add(&new_dp, key, dp_cfg);
+        } else {
+            VLOG_WARN("Unsupported dpatapath type %s\n", key);
+        }
+    }
+
+    /* Get rid of deleted datapath. */
+    HMAP_FOR_EACH_SAFE (dp, next, node, &all_datapaths) {
+        dp->cfg = shash_find_data(&new_dp, dp->type);
+        if (!dp->cfg) {
+            datapath_destroy(dp);
+        }
+    }
+
+    /* Add new datapaths */
+    SHASH_FOR_EACH (node, &new_dp) {
+        const struct ovsrec_datapath *dp_cfg = node->data;
+        if (!datapath_lookup(node->name)) {
+            datapath_create(dp_cfg, node->name);
+        }
+    }
+
+    shash_destroy(&new_dp);
+}
+
+static struct ct_zone *
+ct_zone_lookup(struct cmap *ct_zones, uint16_t zone_id)
+{
+    struct ct_zone *zone;
+
+    CMAP_FOR_EACH_WITH_HASH (zone, node, hash_int(zone_id, 0), ct_zones) {
+        if (zone->id == zone_id) {
+            return zone;
+        }
+    }
+    return NULL;
+}
+
+static struct ct_zone *
+ct_zone_alloc(uint16_t zone_id)
+{
+    struct ct_zone *zone;
+
+    zone = xzalloc(sizeof *zone);
+    zone->id = zone_id;
+
+    return zone;
+}
+
+static void
+ct_zone_destroy(struct datapath *dp, struct ct_zone *zone)
+{
+    cmap_remove(&dp->ct_zones, &zone->node, hash_int(zone->id, 0));
+    ovsrcu_postpone(free, zone);
+}
+
+static struct ct_timeout_policy *
+ct_timeout_policy_lookup(struct cmap *ct_tps, struct uuid *uuid)
+{
+    struct ct_timeout_policy *tp;
+
+    CMAP_FOR_EACH_WITH_HASH (tp, node, uuid_hash(uuid), ct_tps) {
+        if (uuid_equals(&tp->uuid, uuid)) {
+            return tp;
+        }
+    }
+    return NULL;
+}
+
+static struct ct_timeout_policy *
+ct_timeout_policy_alloc(struct ovsrec_ct_timeout_policy *tp_cfg,
+                        unsigned int idl_seqno)
+{
+    struct ct_timeout_policy *tp;
+    size_t i;
+
+    tp = xzalloc(sizeof *tp);
+    tp->uuid = tp_cfg->header_.uuid;
+    for (i = 0; i < tp_cfg->n_timeouts; i++) {
+        ct_dpif_set_timeout_policy_attr_by_name(&tp->cdtp,
+            tp_cfg->key_timeouts[i], tp_cfg->value_timeouts[i]);
+    }
+    tp->cdtp.id = idl_seqno;
+    tp->last_updated_seqno = idl_seqno;
+
+    return tp;
+}
+
+static bool
+ct_timeout_policy_update(struct ovsrec_ct_timeout_policy *tp_cfg,
+                         struct ct_timeout_policy *tp,
+                         unsigned int idl_seqno)
+{
+    size_t i;
+    bool changed = false;
+
+    for (i = 0; i < tp_cfg->n_timeouts; i++) {
+        changed |= ct_dpif_set_timeout_policy_attr_by_name(&tp->cdtp,
+                        tp_cfg->key_timeouts[i], tp_cfg->value_timeouts[i]);
+    }
+    if (changed) {
+        tp->last_updated_seqno = idl_seqno;
+    }
+    return changed;
+}
+
+static void
+ct_timeout_policy_destroy(struct datapath *dp, struct ct_timeout_policy *tp,
+                          struct dpif *dpif)
+{
+    cmap_remove(&dp->ct_tps, &tp->node, uuid_hash(&tp->uuid));
+    if (dpif) {
+        ct_dpif_del_timeout_policy(dpif, tp->cdtp.id);
+    }
+    ovsrcu_postpone(free, tp);
+}
+
+static void
+datapath_update_ct_zone_config(struct datapath *dp, struct dpif *dpif,
+                               unsigned int idl_seqno)
+{
+    const struct ovsrec_datapath *dp_cfg = dp->cfg;
+    struct ovsrec_ct_timeout_policy *tp_cfg;
+    struct ovsrec_ct_zone *zone_cfg;
+    struct ct_timeout_policy *tp;
+    struct ct_zone *zone;
+    uint16_t zone_id;
+    bool new_zone;
+    size_t i;
+
+    for (i = 0; i < dp_cfg->n_ct_zones; i++) {
+        /* Update ct_zone config */
+        zone_cfg = dp_cfg->value_ct_zones[i];
+        zone_id = dp_cfg->key_ct_zones[i];
+        zone = ct_zone_lookup(&dp->ct_zones, zone_id);
+        if (!zone) {
+            new_zone = true;
+            zone = ct_zone_alloc(zone_id);
+        } else {
+            new_zone = false;
+        }
+        zone->last_used_seqno = idl_seqno;
+
+        /* Update timeout policy */
+        tp_cfg = zone_cfg->timeout_policy;
+        tp = ct_timeout_policy_lookup(&dp->ct_tps, &tp_cfg->header_.uuid);
+        if (!tp) {
+            tp = ct_timeout_policy_alloc(tp_cfg, idl_seqno);
+            cmap_insert(&dp->ct_tps, &tp->node, uuid_hash(&tp->uuid));
+            if (dpif) {
+                ct_dpif_add_timeout_policy(dpif, false, &tp->cdtp);
+            }
+        } else {
+            if (ct_timeout_policy_update(tp_cfg, tp, idl_seqno)) {
+                if (dpif) {
+                    ct_dpif_add_timeout_policy(dpif, false, &tp->cdtp);
+                }
+            }
+        }
+        tp->last_used_seqno = idl_seqno;
+
+        /* Update default timeout policy */
+        if (!zone_id && tp->last_updated_seqno == idl_seqno) {
+            ct_dpif_add_timeout_policy(dpif, true, &tp->cdtp);
+        }
+
+        /* Link zone with new timeout policy */
+        zone->tp_uuid = tp_cfg->header_.uuid;
+        if (new_zone) {
+            cmap_insert(&dp->ct_zones, &zone->node, hash_int(zone_id, 0));
+        }
+    }
+}
+
+void
+reconfigure_datapath(const struct ovsrec_open_vswitch *cfg,
+                     unsigned int idl_seqno)
+{
+    struct ct_timeout_policy *tp;
+    struct ct_zone *zone;
+    struct datapath *dp;
+    struct dpif *dpif;
+
+    add_del_datapaths(cfg);
+    HMAP_FOR_EACH (dp, node, &all_datapaths) {
+        dpif_open(dp->dpif_backer_name, dp->type, &dpif);
+
+        datapath_update_ct_zone_config(dp, dpif, idl_seqno);
+
+        /* Garbage colleciton */
+        CMAP_FOR_EACH (zone, node, &dp->ct_zones) {
+            if (zone->last_used_seqno != idl_seqno) {
+                ct_zone_destroy(dp, zone);
+            }
+        }
+        CMAP_FOR_EACH (tp, node, &dp->ct_tps) {
+            if (tp->last_used_seqno != idl_seqno) {
+                ct_timeout_policy_destroy(dp, tp, dpif);
+            }
+        }
+
+        dpif_close(dpif);
+    }
+}
+
+void
+destroy_all_datapaths(void)
+{
+    struct datapath *dp, *next_dp;
+
+    HMAP_FOR_EACH_SAFE (dp, next_dp, node, &all_datapaths) {
+        datapath_destroy(dp);
+    }
+}
diff --git a/lib/datapath-config.h b/lib/datapath-config.h
new file mode 100644
index 000000000000..d9a90e4f8312
--- /dev/null
+++ b/lib/datapath-config.h
@@ -0,0 +1,25 @@ 
+/* Copyright (c) 2019 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef DATAPATH_CONFIG_H
+#define DATAPATH_CONFIG_H 1
+
+#include "vswitch-idl.h"
+
+void reconfigure_datapath(const struct ovsrec_open_vswitch *,
+                          unsigned int idl_seqno);
+void destroy_all_datapaths(void);
+
+#endif /* datapath-config.h */
diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
index 2976771aeaba..e8ac24a50ff2 100644
--- a/vswitchd/bridge.c
+++ b/vswitchd/bridge.c
@@ -26,6 +26,7 @@ 
 #include "connectivity.h"
 #include "coverage.h"
 #include "daemon.h"
+#include "datapath-config.h"
 #include "dirs.h"
 #include "dpif.h"
 #include "dpdk.h"
@@ -508,6 +509,7 @@  bridge_exit(bool delete_datapath)
     HMAP_FOR_EACH_SAFE (br, next_br, node, &all_bridges) {
         bridge_destroy(br, delete_datapath);
     }
+    destroy_all_datapaths();
     ovsdb_idl_destroy(idl);
 }
 
@@ -669,6 +671,7 @@  bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
     }
 
     reconfigure_system_stats(ovs_cfg);
+    reconfigure_datapath(ovs_cfg, idl_seqno);
 
     /* Complete the configuration. */
     sflow_bridge_number = 0;