summaryrefslogtreecommitdiff
path: root/vswitchd/bridge.c
diff options
context:
space:
mode:
authorYi-Hung Wei <yihung.wei@gmail.com>2019-08-28 15:14:26 -0700
committerJustin Pettit <jpettit@ovn.org>2019-09-26 13:50:17 -0700
commit993cae678bca283cf0ef553bed5df99c7bb15b13 (patch)
treef176ac607a473d56a9384d7e176f26cfe6698532 /vswitchd/bridge.c
parent6a16962cda0ea757de88b0fa9e737dfb303387d6 (diff)
downloadopenvswitch-993cae678bca283cf0ef553bed5df99c7bb15b13.tar.gz
ofproto-dpif: Consume CT_Zone, and CT_Timeout_Policy tables
This patch consumes the CT_Zone and CT_Timeout_Policy tables, maintains the zone-based configuration in the vswitchd. Whenever there is a database change, vswitchd will read the datapath, CT_Zone, and CT_Timeout_Policy tables from ovsdb, builds an internal snapshot of the database configuration in bridge.c, and pushes down the change into ofproto and dpif layer. If a new zone-based timeout policy is added, it updates the zone to timeout policy mapping in the per datapath type datapath structure in dpif-backer, and pushes down the timeout policy into the datapath via dpif interface. If a timeout policy is no longer used, for kernel datapath, vswitchd may not be able to remove it from datapath immediately since datapath flows can still reference the to-be-deleted timeout policies. Thus, we keep an timeout policy kill list, that vswitchd will go back to the list periodically and try to kill the unused timeout policies. Signed-off-by: Yi-Hung Wei <yihung.wei@gmail.com> Signed-off-by: Justin Pettit <jpettit@ovn.org>
Diffstat (limited to 'vswitchd/bridge.c')
-rw-r--r--vswitchd/bridge.c197
1 files changed, 195 insertions, 2 deletions
diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
index 791bef11c..9095ebf5d 100644
--- a/vswitchd/bridge.c
+++ b/vswitchd/bridge.c
@@ -153,9 +153,35 @@ struct aa_mapping {
char *br_name;
};
+/* Internal representation of conntrack zone configuration table in OVSDB. */
+struct ct_zone {
+ uint16_t zone_id;
+ struct simap tp; /* A map from timeout policy attribute to
+ * timeout value. */
+ struct hmap_node node; /* Node in 'struct datapath' 'ct_zones'
+ * hmap. */
+ unsigned int last_used; /* The last idl_seqno that this 'ct_zone' used
+ * in OVSDB. This number is used for garbage
+ * collection. */
+};
+
+/* Internal representation of datapath configuration table in OVSDB. */
+struct datapath {
+ char *type; /* Datapath type. */
+ struct hmap ct_zones; /* Map of 'struct ct_zone' elements, indexed
+ * by 'zone'. */
+ struct hmap_node node; /* Node in 'all_datapaths' hmap. */
+ unsigned int last_used; /* The last idl_seqno that this 'datapath'
+ * used in OVSDB. This number is used for
+ * garbage collection. */
+};
+
/* All bridges, indexed by name. */
static struct hmap all_bridges = HMAP_INITIALIZER(&all_bridges);
+/* All datapath configuartions, indexed by type. */
+static struct hmap all_datapaths = HMAP_INITIALIZER(&all_datapaths);
+
/* OVSDB IDL used to obtain configuration. */
static struct ovsdb_idl *idl;
@@ -276,6 +302,8 @@ static bool bridge_has_bond_fake_iface(const struct bridge *,
const char *name);
static bool port_is_bond_fake_iface(const struct port *);
+static void datapath_destroy(struct datapath *dp);
+
static unixctl_cb_func qos_unixctl_show_types;
static unixctl_cb_func qos_unixctl_show;
@@ -506,13 +534,19 @@ bridge_init(const char *remote)
void
bridge_exit(bool delete_datapath)
{
- struct bridge *br, *next_br;
-
if_notifier_destroy(ifnotifier);
seq_destroy(ifaces_changed);
+
+ struct datapath *dp, *next;
+ HMAP_FOR_EACH_SAFE (dp, next, node, &all_datapaths) {
+ datapath_destroy(dp);
+ }
+
+ struct bridge *br, *next_br;
HMAP_FOR_EACH_SAFE (br, next_br, node, &all_bridges) {
bridge_destroy(br, delete_datapath);
}
+
ovsdb_idl_destroy(idl);
}
@@ -593,6 +627,164 @@ config_ofproto_types(const struct smap *other_config)
}
static void
+get_timeout_policy_from_ovsrec(struct simap *tp,
+ const struct ovsrec_ct_timeout_policy *tp_cfg)
+{
+ for (size_t i = 0; i < tp_cfg->n_timeouts; i++) {
+ simap_put(tp, tp_cfg->key_timeouts[i], tp_cfg->value_timeouts[i]);
+ }
+}
+
+static struct ct_zone *
+ct_zone_lookup(struct hmap *ct_zones, uint16_t zone_id)
+{
+ struct ct_zone *ct_zone;
+
+ HMAP_FOR_EACH_WITH_HASH (ct_zone, node, hash_int(zone_id, 0), ct_zones) {
+ if (ct_zone->zone_id == zone_id) {
+ return ct_zone;
+ }
+ }
+ return NULL;
+}
+
+static struct ct_zone *
+ct_zone_alloc(uint16_t zone_id, struct ovsrec_ct_timeout_policy *tp_cfg)
+{
+ struct ct_zone *ct_zone = xzalloc(sizeof *ct_zone);
+
+ ct_zone->zone_id = zone_id;
+ simap_init(&ct_zone->tp);
+ get_timeout_policy_from_ovsrec(&ct_zone->tp, tp_cfg);
+ return ct_zone;
+}
+
+static void
+ct_zone_remove_and_destroy(struct datapath *dp, struct ct_zone *ct_zone)
+{
+ hmap_remove(&dp->ct_zones, &ct_zone->node);
+ simap_destroy(&ct_zone->tp);
+ free(ct_zone);
+}
+
+/* Replace 'old_tp' by 'new_tp' (destroyed 'new_tp'). Returns true if 'old_tp'
+ * and 'new_tp' contains different data, false if they are the same. */
+static bool
+update_timeout_policy(struct simap *old_tp, struct simap *new_tp)
+{
+ bool changed = !simap_equal(old_tp, new_tp);
+ if (changed) {
+ simap_swap(old_tp, new_tp);
+ }
+ simap_destroy(new_tp);
+ return changed;
+}
+
+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 struct datapath *
+datapath_create(const char *type)
+{
+ struct datapath *dp = xzalloc(sizeof *dp);
+ dp->type = xstrdup(type);
+ hmap_init(&dp->ct_zones);
+ hmap_insert(&all_datapaths, &dp->node, hash_string(type, 0));
+ return dp;
+}
+
+static void
+datapath_destroy(struct datapath *dp)
+{
+ if (dp) {
+ struct ct_zone *ct_zone, *next;
+ HMAP_FOR_EACH_SAFE (ct_zone, next, node, &dp->ct_zones) {
+ ofproto_ct_del_zone_timeout_policy(dp->type, ct_zone->zone_id);
+ ct_zone_remove_and_destroy(dp, ct_zone);
+ }
+
+ hmap_remove(&all_datapaths, &dp->node);
+ hmap_destroy(&dp->ct_zones);
+ free(dp->type);
+ free(dp);
+ }
+}
+
+static void
+ct_zones_reconfigure(struct datapath *dp, struct ovsrec_datapath *dp_cfg)
+{
+ struct ct_zone *ct_zone, *next;
+
+ /* 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++) {
+ uint16_t zone_id = dp_cfg->key_ct_zones[i];
+ struct ovsrec_ct_zone *zone_cfg = dp_cfg->value_ct_zones[i];
+ struct ovsrec_ct_timeout_policy *tp_cfg = zone_cfg->timeout_policy;
+
+ ct_zone = ct_zone_lookup(&dp->ct_zones, zone_id);
+ if (ct_zone) {
+ struct simap new_tp = SIMAP_INITIALIZER(&new_tp);
+ get_timeout_policy_from_ovsrec(&new_tp, tp_cfg);
+ if (update_timeout_policy(&ct_zone->tp, &new_tp)) {
+ ofproto_ct_set_zone_timeout_policy(dp->type, ct_zone->zone_id,
+ &ct_zone->tp);
+ }
+ } else {
+ ct_zone = ct_zone_alloc(zone_id, tp_cfg);
+ hmap_insert(&dp->ct_zones, &ct_zone->node, hash_int(zone_id, 0));
+ ofproto_ct_set_zone_timeout_policy(dp->type, ct_zone->zone_id,
+ &ct_zone->tp);
+ }
+ ct_zone->last_used = idl_seqno;
+ }
+
+ /* Purge 'ct_zone's no longer found in the database. */
+ HMAP_FOR_EACH_SAFE (ct_zone, next, node, &dp->ct_zones) {
+ if (ct_zone->last_used != idl_seqno) {
+ ofproto_ct_del_zone_timeout_policy(dp->type, ct_zone->zone_id);
+ ct_zone_remove_and_destroy(dp, ct_zone);
+ }
+ }
+}
+
+static void
+datapath_reconfigure(const struct ovsrec_open_vswitch *cfg)
+{
+ struct datapath *dp, *next;
+
+ /* Add new 'datapath's or update existing ones. */
+ for (size_t i = 0; i < cfg->n_datapaths; i++) {
+ struct ovsrec_datapath *dp_cfg = cfg->value_datapaths[i];
+ char *dp_name = cfg->key_datapaths[i];
+
+ dp = datapath_lookup(dp_name);
+ if (!dp) {
+ dp = datapath_create(dp_name);
+ }
+ dp->last_used = idl_seqno;
+ ct_zones_reconfigure(dp, dp_cfg);
+ }
+
+ /* Purge deleted 'datapath's. */
+ HMAP_FOR_EACH_SAFE (dp, next, node, &all_datapaths) {
+ if (dp->last_used != idl_seqno) {
+ datapath_destroy(dp);
+ }
+ }
+}
+
+static void
bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
{
struct sockaddr_in *managers;
@@ -680,6 +872,7 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
}
reconfigure_system_stats(ovs_cfg);
+ datapath_reconfigure(ovs_cfg);
/* Complete the configuration. */
sflow_bridge_number = 0;