---
controller/ovn-controller.c | 89 +++++++++++++++++++++++++++++++-----
controller/physical.c | 2 +-
lib/ovn-util.c | 7 +++
lib/ovn-util.h | 1 +
northd/ovn-northd.c | 10 ++++
ovn-nb.xml | 7 +++
tests/ovn.at | 91 +++++++++++++++++++++++++++++++++++++
7 files changed, 194 insertions(+), 13 deletions(-)
diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c
index a06cae3cc..54c8fd2db 100644
--- a/controller/ovn-controller.c
+++ b/controller/ovn-controller.c
@@ -531,6 +531,21 @@ update_sb_db(struct ovsdb_idl *ovs_idl, struct ovsdb_idl
*ovnsb_idl,
}
}
+static void
+add_pending_ct_zone_entry(struct shash *pending_ct_zones,
+ enum ct_zone_pending_state state,
+ int zone, bool add, const char *name)
+{
+ VLOG_DBG("%s ct zone %"PRId32" for '%s'",
+ add ? "assigning" : "removing", zone, name);
+
+ struct ct_zone_pending_entry *pending = xmalloc(sizeof *pending);
+ pending->state = state; /* Skip flushing zone. */
+ pending->zone = zone;
+ pending->add = add;
+ shash_add(pending_ct_zones, name, pending);
+}
+
static void
update_ct_zones(const struct sset *lports, const struct hmap *local_datapaths,
struct simap *ct_zones, unsigned long *ct_zone_bitmap,
@@ -540,6 +555,7 @@ update_ct_zones(const struct sset *lports, const struct
hmap *local_datapaths,
int scan_start = 1;
const char *user;
struct sset all_users = SSET_INITIALIZER(&all_users);
+ struct simap req_snat_zones = SIMAP_INITIALIZER(&req_snat_zones);
SSET_FOR_EACH(user, lports) {
sset_add(&all_users, user);
@@ -554,6 +570,25 @@ update_ct_zones(const struct sset *lports, const struct
hmap *local_datapaths,
char *snat = alloc_nat_zone_key(&ld->datapath->header_.uuid, "snat");
sset_add(&all_users, dnat);
sset_add(&all_users, snat);
+
+ int req_snat_zone = datapath_snat_ct_zone(ld->datapath);
+ if (req_snat_zone >= 0) {
+ struct simap_node *node;
+ bool collision = false;
+ SIMAP_FOR_EACH (node, &req_snat_zones) {
+ if (node->data == req_snat_zone) {
+ VLOG_WARN("Datapaths %.*s and " UUID_FMT " request SNAT "
+ "CT zone %d\n", UUID_LEN, node->name,
+ UUID_ARGS(&ld->datapath->header_.uuid),
+ req_snat_zone);
+ collision = true;
+ break;
+ }
+ }
+ if (!collision) {
+ simap_put(&req_snat_zones, snat, req_snat_zone);
+ }
+ }
free(dnat);
free(snat);
}
@@ -564,17 +599,51 @@ update_ct_zones(const struct sset *lports, const struct
hmap *local_datapaths,
VLOG_DBG("removing ct zone %"PRId32" for '%s'",
ct_zone->data, ct_zone->name);
- struct ct_zone_pending_entry *pending = xmalloc(sizeof *pending);
- pending->state = CT_ZONE_DB_QUEUED; /* Skip flushing zone. */
- pending->zone = ct_zone->data;
- pending->add = false;
- shash_add(pending_ct_zones, ct_zone->name, pending);
+ add_pending_ct_zone_entry(pending_ct_zones, CT_ZONE_DB_QUEUED,
+ ct_zone->data, false, ct_zone->name);
bitmap_set0(ct_zone_bitmap, ct_zone->data);
simap_delete(ct_zones, ct_zone);
}
}
+ /* Prioritize requested CT zones */
+ struct simap_node *snat_req_node;
+ SIMAP_FOR_EACH (snat_req_node, &req_snat_zones) {
+ struct simap_node *node = simap_find(ct_zones, snat_req_node->name);
+ if (node) {
+ if (node->data == snat_req_node->data) {
+ /* Already have this zone reserved */
+ continue;
+ } else {
+ /* Zone has changed for this node. delete old entry */
+ bitmap_set0(ct_zone_bitmap, node->data);
+ simap_delete(ct_zones, node);
+ }
+ } else if (snat_req_node->data > 0 &&
+ bitmap_is_set(ct_zone_bitmap, snat_req_node->data)) {
+ /* Uh oh. Someone else already has this zone assigned.
+ * We need to find who and remove them from ct_zones so
+ * that they get re-assigned a new zone below
+ */
+ struct simap_node *next;
+ SIMAP_FOR_EACH_SAFE (node, next, ct_zones) {
+ if (node->data == snat_req_node->data) {
+ simap_delete(ct_zones, node);
+ break;
+ }
+ }
+ }
+
+ add_pending_ct_zone_entry(pending_ct_zones, CT_ZONE_OF_QUEUED,
+ snat_req_node->data, true,
+ snat_req_node->name);
+
+ bitmap_set1(ct_zone_bitmap, snat_req_node->data);
+ simap_put(ct_zones, snat_req_node->name, snat_req_node->data);
+ }
+ simap_destroy(&req_snat_zones);
+
/* xxx This is wasteful to assign a zone to each port--even if no
* xxx security policy is applied. */
@@ -596,13 +665,8 @@ update_ct_zones(const struct sset *lports, const struct
hmap *local_datapaths,
}
scan_start = zone + 1;
- VLOG_DBG("assigning ct zone %"PRId32" to '%s'", zone, user);
-
- struct ct_zone_pending_entry *pending = xmalloc(sizeof *pending);
- pending->state = CT_ZONE_OF_QUEUED;
- pending->zone = zone;
- pending->add = true;
- shash_add(pending_ct_zones, user, pending);
+ add_pending_ct_zone_entry(pending_ct_zones, CT_ZONE_OF_QUEUED,
+ zone, true, user);
bitmap_set1(ct_zone_bitmap, zone);
simap_put(ct_zones, user, zone);
@@ -2330,6 +2394,7 @@ main(int argc, char *argv[])
engine_add_input(&en_ct_zones, &en_ovs_open_vswitch, NULL);
engine_add_input(&en_ct_zones, &en_ovs_bridge, NULL);
+ engine_add_input(&en_ct_zones, &en_sb_datapath_binding, NULL);
engine_add_input(&en_ct_zones, &en_runtime_data, NULL);
engine_add_input(&en_runtime_data, &en_ofctrl_is_connected, NULL);
diff --git a/controller/physical.c b/controller/physical.c
index 1bc2c389b..00c4ca4fd 100644
--- a/controller/physical.c
+++ b/controller/physical.c
@@ -926,7 +926,7 @@ consider_port_binding(struct ovsdb_idl_index
*sbrec_port_binding_by_name,
ofctrl_add_flow(flow_table, OFTABLE_LOG_TO_PHY, 100,
binding->header_.uuid.parts[0],
- &match, ofpacts_p, &binding->header_.uuid);
+ &match, ofpacts_p, hc_uuid);
return;
}
diff --git a/lib/ovn-util.c b/lib/ovn-util.c
index 18aac8da3..f0fb796b4 100644
--- a/lib/ovn-util.c
+++ b/lib/ovn-util.c
@@ -532,6 +532,13 @@ datapath_is_switch(const struct sbrec_datapath_binding
*ldp)
{
return smap_get(&ldp->external_ids, "logical-switch") != NULL;
}
+
+int
+datapath_snat_ct_zone(const struct sbrec_datapath_binding *dp)
+{
+ return smap_get_int(&dp->external_ids, "snat-ct-zone", -1);
+}
+
struct tnlid_node {
struct hmap_node hmap_node;
diff --git a/lib/ovn-util.h b/lib/ovn-util.h
index 3496673b2..ea8226571 100644
--- a/lib/ovn-util.h
+++ b/lib/ovn-util.h
@@ -107,6 +107,7 @@ uint32_t ovn_logical_flow_hash(const struct uuid
*logical_datapath,
uint16_t priority,
const char *match, const char *actions);
bool datapath_is_switch(const struct sbrec_datapath_binding *);
+int datapath_snat_ct_zone(const struct sbrec_datapath_binding *ldp);
void ovn_conn_show(struct unixctl_conn *conn, int argc OVS_UNUSED,
const char *argv[] OVS_UNUSED, void *idl_);
diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
index 4d4190cb9..8ce756c8a 100644
--- a/northd/ovn-northd.c
+++ b/northd/ovn-northd.c
@@ -1179,6 +1179,16 @@ ovn_datapath_update_external_ids(struct ovn_datapath *od)
smap_add(&ids, "interconn-ts", ts);
}
}
+
+ /* Set snat-ct-zone */
+ if (od->nbr) {
+ int nat_default_ct = smap_get_int(&od->nbr->options,
+ "snat-ct-zone", -1);
+ if (nat_default_ct >= 0) {
+ smap_add_format(&ids, "snat-ct-zone", "%d", nat_default_ct);
+ }
+ }
+
sbrec_datapath_binding_set_external_ids(od->sb, &ids);
smap_destroy(&ids);
}
diff --git a/ovn-nb.xml b/ovn-nb.xml
index 5e6c6c7a3..619c0e299 100644
--- a/ovn-nb.xml
+++ b/ovn-nb.xml
@@ -1961,6 +1961,13 @@
unique key for each datapath by itself. However, if it is configured,
<code>ovn-northd</code> honors the configured value.
</column>
+ <column name="options" key="snat-ct-zone"
+ type='{"type": "integer", "minInteger": 0, "maxInteger": 65535}'>
+ Use the requested conntrack zone for SNAT with this router. This can be
+ useful if egress traffic from the host running OVN comes from both OVN
+ and other sources. This way, OVN and the other sources can make use of
+ the same conntrack zone.
+ </column>
</group>
<group title="Common Columns">
diff --git a/tests/ovn.at b/tests/ovn.at
index 378d11921..4f8c1a3e1 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
@@ -22686,3 +22686,94 @@ AT_CHECK([test "$encap_rec_mvtep" ==
"$encap_rec_mvtep1"], [0], [])
OVN_CLEANUP([hv1])
AT_CLEANUP
+
+AT_SETUP([ovn -- snat default ct zone])
+ovn_start
+
+net_add n1
+sim_add hv1
+ovs-vsctl add-br br-phys
+as hv1
+ovn_attach n1 br-phys 192.168.0.10
+
+ovn-nbctl ls-add sw0
+ovn-nbctl lsp-add sw0 sw0-p1
+ovn-nbctl lsp-set-addresses sw0-p1 "00:00:00:00:00:02 10.0.0.2"
+
+ovn-nbctl lr-add gw_router
+ovn-nbctl set Logical_Router gw_router options:chassis="hv1"
+
+ovn-nbctl lrp-add gw_router gw_router-sw0 00:00:00:00:00:01 10.0.0.1/24
+ovn-nbctl lsp-add sw0 sw0-gw_router
+ovn-nbctl lsp-set-addresses sw0-gw_router router
+ovn-nbctl set Logical_Switch_Port sw0-gw_router type=router \
+ options:router-port=gw_router-sw0 \
+
+ovn-nbctl lr-nat-add gw_router snat 192.168.0.1 10.0.0.0/24
+
+as hv1 ovs-vsctl -- add-port br-int hv1-vif1 -- \
+ set interface hv1-vif1 external-ids:iface-id=sw0-p1
+
+ovn-nbctl --wait=hv sync
+
+ro_nb_uuid=$(ovn-nbctl get Logical_Router gw_router _uuid)
+sw_nb_uuid=$(ovn-nbctl get Logical_Switch sw0 _uuid)
+ro_sb_uuid=$(ovn-sbctl --bare --columns=_uuid find Datapath_Binding
external-ids:logical-router=${ro_nb_uuid})
+sw_sb_uuid=$(ovn-sbctl --bare --columns=_uuid find Datapath_Binding
external-ids:logical-switch=${sw_nb_uuid})
+ro_meta=$(ovn-sbctl get Datapath_Binding ${ro_sb_uuid} tunnel_key)
+ro_meta=$(printf %#x ${ro_meta})
+sw_meta=$(ovn-sbctl get Datapath_Binding ${sw_sb_uuid} tunnel_key)
+sw_meta=$(printf %#x ${sw_meta})
+
+echo "ro_nb_uuid: ${ro_nb_uuid}"
+echo "sw_nb_uuid: ${sw_nb_uuid}"
+echo "ro_sb_uuid: ${ro_sb_uuid}"
+echo "sw_sb_uuid: ${sw_sb_uuid}"
+echo "ro_meta: ${ro_meta}"
+echo "sw_meta: ${sw_meta}"
+
+as hv1
+ovs-vsctl list bridge br-int
+snat_zone=$(printf %#x $(ovs-vsctl get bridge br-int
external-ids:ct-zone-${ro_sb_uuid}_snat | tr -d \"))
+
+echo "snat_zone: ${snat_zone}"
+
+as hv1 ovs-ofctl dump-flows br-int > offlows_pre
+AT_CAPTURE_FILE([offlows_pre])
+# We should have a flow in table 33 that transitions from the ingress pipeline
+# to the egress pipeline of gw_router.
+AT_CHECK_UNQUOTED([grep -c
"table=33.*metadata=${ro_meta}.*load:${snat_zone}->NXM_NX_REG12[]"
offlows_pre], [0], [dnl
+1
+])
+
+# We should have a flow in table 65 that transitions from the egress pipeline
+# of sw0 to the ingress pipeline of gw_router.
+AT_CHECK_UNQUOTED([grep -c
"table=65.*metadata=${sw_meta}.*load:${snat_zone}->NXM_NX_REG12[]"
offlows_pre], [0], [dnl
+1
+])
+
+ovn-nbctl --wait=hv set Logical_Router gw_router options:snat-ct-zone=666
+
+as hv1
+snat_zone=$(ovs-vsctl get bridge br-int external-ids:ct-zone-${ro_sb_uuid}_snat |
tr -d \")
+
+echo "snat_zone: ${snat_zone}"
+
+AT_CHECK([test "${snat_zone}" = "666"], [0], [])
+
+as hv1 ovs-ofctl dump-flows br-int > offlows_post
+AT_CAPTURE_FILE([offlows_post])
+# We should have a flow in table 33 that transitions from the ingress pipeline
+# to the egress pipeline of gw_router.
+AT_CHECK_UNQUOTED([grep -c
"table=33.*metadata=${ro_meta}.*load:0x29a->NXM_NX_REG12[]" offlows_post], [0],
[dnl
+1
+])
+
+# We should have a flow in table 65 that transitions from the egress pipeline
+# of sw0 to the ingress pipeline of gw_router.
+AT_CHECK_UNQUOTED([grep -c
"table=65.*metadata=${sw_meta}.*load:0x29a->NXM_NX_REG12[]" offlows_post], [0],
[dnl
+1
+])
+
+OVN_CLEANUP([hv1])
+AT_CLEANUP
--
2.25.4
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev