#include "patch.h"
#include "hash.h"
-#include "lib/hmap.h"
+#include "lflow.h"
#include "lib/vswitch-idl.h"
+#include "lport.h"
+#include "openvswitch/hmap.h"
#include "openvswitch/vlog.h"
#include "ovn-controller.h"
ovsrec_bridge_verify_ports(src);
ovsrec_bridge_set_ports(src, ports, src->n_ports + 1);
+ lport_index_reset();
+ mcgroup_index_reset();
+ lflow_reset_processing();
free(ports);
}
return;
}
}
+ lport_index_reset();
+ mcgroup_index_reset();
+ lflow_reset_processing();
}
/* Obtains external-ids:ovn-bridge-mappings from OVSDB and adds patch ports for
add_bridge_mappings(struct controller_ctx *ctx,
const struct ovsrec_bridge *br_int,
struct shash *existing_ports,
- struct hmap *local_datapaths)
+ struct hmap *local_datapaths,
+ const char *chassis_id)
{
/* Get ovn-bridge-mappings. */
const char *mappings_cfg = "";
const struct sbrec_port_binding *binding;
SBREC_PORT_BINDING_FOR_EACH (binding, ctx->ovnsb_idl) {
+ const char *patch_port_id;
if (!strcmp(binding->type, "localnet")) {
struct local_datapath *ld
= get_local_datapath(local_datapaths,
* to create patch ports for it. */
continue;
}
- if (ld->localnet_port) {
+
+ /* Under incremental processing, it is possible to re-enter the
+ * following block with a logical port that has already been
+ * recorded in binding->logical_port. Rather than emit spurious
+ * warnings, add a check to see if the logical port name has
+ * actually changed. */
+
+ if (ld->localnet_port && strcmp(ld->localnet_port->logical_port,
+ binding->logical_port)) {
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
VLOG_WARN_RL(&rl, "localnet port '%s' already set for datapath "
"'%"PRId64"', skipping the new port '%s'.",
continue;
}
ld->localnet_port = binding;
+ patch_port_id = "ovn-localnet-port";
+ } else if (!strcmp(binding->type, "l2gateway")) {
+ if (!binding->chassis
+ || strcmp(chassis_id, binding->chassis->name)) {
+ /* This L2 gateway port is not bound to this chassis,
+ * so we should not create any patch ports for it. */
+ continue;
+ }
+ patch_port_id = "ovn-l2gateway-port";
} else {
- /* Not a binding for a localnet port. */
+ /* not a localnet or L2 gateway port. */
continue;
}
const char *network = smap_get(&binding->options, "network_name");
if (!network) {
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
- VLOG_ERR_RL(&rl, "localnet port '%s' has no network name.",
- binding->logical_port);
+ VLOG_ERR_RL(&rl, "%s port '%s' has no network name.",
+ binding->type, binding->logical_port);
continue;
}
struct ovsrec_bridge *br_ln = shash_find_data(&bridge_mappings, network);
if (!br_ln) {
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
- VLOG_ERR_RL(&rl, "bridge not found for localnet port '%s' "
- "with network name '%s'", binding->logical_port, network);
+ VLOG_ERR_RL(&rl, "bridge not found for %s port '%s' "
+ "with network name '%s'",
+ binding->type, binding->logical_port, network);
continue;
}
char *name1 = patch_port_name(br_int->name, binding->logical_port);
char *name2 = patch_port_name(binding->logical_port, br_int->name);
- create_patch_port(ctx, "ovn-localnet-port", binding->logical_port,
+ create_patch_port(ctx, patch_port_id, binding->logical_port,
br_int, name1, br_ln, name2, existing_ports);
- create_patch_port(ctx, "ovn-localnet-port", binding->logical_port,
+ create_patch_port(ctx, patch_port_id, binding->logical_port,
br_ln, name2, br_int, name1, existing_ports);
free(name1);
free(name2);
static void
add_patched_datapath(struct hmap *patched_datapaths,
- const struct sbrec_port_binding *binding_rec)
+ const struct sbrec_port_binding *binding_rec, bool local)
{
- if (get_patched_datapath(patched_datapaths,
- binding_rec->datapath->tunnel_key)) {
+ struct patched_datapath *pd = get_patched_datapath(patched_datapaths,
+ binding_rec->datapath->tunnel_key);
+ if (pd) {
+ /* If the patched datapath is referenced by a logical patch port it is
+ * not stale, by definition, so set 'stale' to false */
+ pd->stale = false;
return;
}
- struct patched_datapath *pd = xzalloc(sizeof *pd);
+ pd = xzalloc(sizeof *pd);
+ pd->local = local;
+ pd->key = xasprintf(UUID_FMT,
+ UUID_ARGS(&binding_rec->datapath->header_.uuid));
+ /* stale is set to false. */
hmap_insert(patched_datapaths, &pd->hmap_node,
binding_rec->datapath->tunnel_key);
}
+static void
+add_logical_patch_ports_preprocess(struct hmap *patched_datapaths)
+{
+ /* Mark all patched datapaths as stale for later cleanup by
+ * add_logical_patch_ports_postprocess(). */
+ struct patched_datapath *pd;
+ HMAP_FOR_EACH (pd, hmap_node, patched_datapaths) {
+ pd->stale = true;
+ }
+}
+
+/* This function should cleanup stale patched datapaths and any memory
+ * allocated for fields within a stale patched datapath. */
+static void
+add_logical_patch_ports_postprocess(struct hmap *patched_datapaths)
+{
+ /* Clean up stale patched datapaths. */
+ struct patched_datapath *pd_cur_node, *pd_next_node;
+ HMAP_FOR_EACH_SAFE (pd_cur_node, pd_next_node, hmap_node,
+ patched_datapaths) {
+ if (pd_cur_node->stale == true) {
+ hmap_remove(patched_datapaths, &pd_cur_node->hmap_node);
+ free(pd_cur_node->key);
+ free(pd_cur_node);
+ }
+ }
+}
+
/* Add one OVS patch port for each OVN logical patch port.
*
* This is suboptimal for several reasons. First, it creates an OVS port for
return;
}
+ add_logical_patch_ports_preprocess(patched_datapaths);
+
const struct sbrec_port_binding *binding;
SBREC_PORT_BINDING_FOR_EACH (binding, ctx->ovnsb_idl) {
bool local_port = false;
if (!strcmp(binding->type, "gateway")) {
const char *chassis = smap_get(&binding->options,
"gateway-chassis");
- if (!strcmp(local_chassis_id, chassis)) {
+ if (chassis && !strcmp(local_chassis_id, chassis)) {
local_port = true;
}
}
existing_ports);
free(dst_name);
free(src_name);
- add_patched_datapath(patched_datapaths, binding);
+ add_patched_datapath(patched_datapaths, binding, local_port);
if (local_port) {
if (binding->chassis != chassis_rec && ctx->ovnsb_idl_txn) {
sbrec_port_binding_set_chassis(binding, chassis_rec);
}
}
}
+ add_logical_patch_ports_postprocess(patched_datapaths);
}
void
struct shash existing_ports = SHASH_INITIALIZER(&existing_ports);
const struct ovsrec_port *port;
OVSREC_PORT_FOR_EACH (port, ctx->ovs_idl) {
- if (smap_get(&port->external_ids, "ovn-localnet-port") ||
- smap_get(&port->external_ids, "ovn-logical-patch-port")) {
+ if (smap_get(&port->external_ids, "ovn-localnet-port")
+ || smap_get(&port->external_ids, "ovn-l2gateway-port")
+ || smap_get(&port->external_ids, "ovn-logical-patch-port")) {
shash_add(&existing_ports, port->name, port);
}
}
/* Create in the database any patch ports that should exist. Remove from
* 'existing_ports' any patch ports that do exist in the database and
* should be there. */
- add_bridge_mappings(ctx, br_int, &existing_ports, local_datapaths);
+ add_bridge_mappings(ctx, br_int, &existing_ports, local_datapaths, chassis_id);
add_logical_patch_ports(ctx, br_int, chassis_id, &existing_ports,
patched_datapaths);