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

Yi-Hung Wei yihung.wei at gmail.com
Thu Jul 25 23:24:10 UTC 2019


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 at 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 */
+    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;
-- 
2.7.4



More information about the dev mailing list