ovn-controller: Assign conntrack zones for gateway router.
authorGurucharan Shetty <guru@ovn.org>
Wed, 11 May 2016 00:19:15 +0000 (17:19 -0700)
committerGurucharan Shetty <guru@ovn.org>
Fri, 3 Jun 2016 16:31:30 +0000 (09:31 -0700)
OVS NAT currently cannot do snat and dnat in the same zone.
So we need two zones per gateway router.

Signed-off-by: Gurucharan Shetty <guru@ovn.org>
Acked-by: Ben Pfaff <blp@ovn.org>
ovn/controller/ovn-controller.c
ovn/controller/ovn-controller.h
ovn/controller/patch.c
ovn/controller/physical.c
ovn/lib/logical-fields.h
ovn/lib/ovn-util.c
ovn/lib/ovn-util.h
ovn/ovn-architecture.7.xml

index a87937f..356a94b 100644 (file)
@@ -40,6 +40,7 @@
 #include "openvswitch/vconn.h"
 #include "openvswitch/vlog.h"
 #include "ovn/lib/ovn-sb-idl.h"
+#include "ovn/lib/ovn-util.h"
 #include "patch.h"
 #include "physical.h"
 #include "pinctrl.h"
@@ -254,29 +255,50 @@ get_ovnsb_remote_probe_interval(struct ovsdb_idl *ovs_idl, int *value)
 }
 
 static void
-update_ct_zones(struct sset *lports, struct simap *ct_zones,
-                unsigned long *ct_zone_bitmap)
+update_ct_zones(struct sset *lports, struct hmap *patched_datapaths,
+                struct simap *ct_zones, unsigned long *ct_zone_bitmap)
 {
     struct simap_node *ct_zone, *ct_zone_next;
-    const char *iface_id;
     int scan_start = 1;
+    struct patched_datapath *pd;
+    const char *user;
+    struct sset all_users = SSET_INITIALIZER(&all_users);
 
-    /* xxx This is wasteful to assign a zone to each port--even if no
-     * xxx security policy is applied. */
+    SSET_FOR_EACH(user, lports) {
+        sset_add(&all_users, user);
+    }
+
+    /* Local patched datapath (gateway routers) need zones assigned. */
+    HMAP_FOR_EACH(pd, hmap_node, patched_datapaths) {
+        if (!pd->local) {
+            continue;
+        }
 
-    /* Delete any zones that are associated with removed ports. */
+        char *dnat = alloc_nat_zone_key(pd->port_binding, "dnat");
+        char *snat = alloc_nat_zone_key(pd->port_binding, "snat");
+        sset_add(&all_users, dnat);
+        sset_add(&all_users, snat);
+        free(dnat);
+        free(snat);
+    }
+
+    /* Delete zones that do not exist in above sset. */
     SIMAP_FOR_EACH_SAFE(ct_zone, ct_zone_next, ct_zones) {
-        if (!sset_contains(lports, ct_zone->name)) {
+        if (!sset_contains(&all_users, ct_zone->name)) {
             bitmap_set0(ct_zone_bitmap, ct_zone->data);
             simap_delete(ct_zones, ct_zone);
         }
     }
 
-    /* Assign a unique zone id for each logical port. */
-    SSET_FOR_EACH(iface_id, lports) {
+    /* xxx This is wasteful to assign a zone to each port--even if no
+     * xxx security policy is applied. */
+
+    /* Assign a unique zone id for each logical port and two zones
+     * to a gateway router. */
+    SSET_FOR_EACH(user, &all_users) {
         size_t zone;
 
-        if (simap_contains(ct_zones, iface_id)) {
+        if (simap_contains(ct_zones, user)) {
             continue;
         }
 
@@ -290,12 +312,14 @@ update_ct_zones(struct sset *lports, struct simap *ct_zones,
         scan_start = zone + 1;
 
         bitmap_set1(ct_zone_bitmap, zone);
-        simap_put(ct_zones, iface_id, zone);
+        simap_put(ct_zones, user, zone);
 
         /* xxx We should erase any old entries for this
          * xxx zone, but we need a generic interface to the conntrack
          * xxx table. */
     }
+
+    sset_destroy(&all_users);
 }
 
 int
@@ -423,7 +447,8 @@ main(int argc, char *argv[])
             enum mf_field_id mff_ovn_geneve = ofctrl_run(br_int);
 
             pinctrl_run(&ctx, &lports, br_int, chassis_id, &local_datapaths);
-            update_ct_zones(&all_lports, &ct_zones, ct_zone_bitmap);
+            update_ct_zones(&all_lports, &patched_datapaths, &ct_zones,
+                            ct_zone_bitmap);
 
             struct hmap flow_table = HMAP_INITIALIZER(&flow_table);
             lflow_run(&ctx, &lports, &mcgroups, &local_datapaths,
index 9af7959..ba50a98 100644 (file)
@@ -48,6 +48,8 @@ struct local_datapath *get_local_datapath(const struct hmap *,
  * with at least one logical patch port binding. */
 struct patched_datapath {
     struct hmap_node hmap_node;
+    bool local; /* 'True' if the datapath is for gateway router. */
+    const struct sbrec_port_binding *port_binding;
 };
 
 struct patched_datapath *get_patched_datapath(const struct hmap *,
index e8abe30..652466b 100644 (file)
@@ -230,7 +230,7 @@ add_bridge_mappings(struct controller_ctx *ctx,
 
 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)) {
@@ -238,6 +238,8 @@ add_patched_datapath(struct hmap *patched_datapaths,
     }
 
     struct patched_datapath *pd = xzalloc(sizeof *pd);
+    pd->local = local;
+    pd->port_binding = binding_rec;
     hmap_insert(patched_datapaths, &pd->hmap_node,
                 binding_rec->datapath->tunnel_key);
 }
@@ -302,7 +304,7 @@ add_logical_patch_ports(struct controller_ctx *ctx,
                               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);
index 576c695..85528e0 100644 (file)
@@ -24,6 +24,7 @@
 #include "openvswitch/vlog.h"
 #include "ovn-controller.h"
 #include "ovn/lib/ovn-sb-idl.h"
+#include "ovn/lib/ovn-util.h"
 #include "physical.h"
 #include "shash.h"
 #include "simap.h"
@@ -367,6 +368,21 @@ physical_run(struct controller_ctx *ctx, enum mf_field_id mff_ovn_geneve,
                 put_load(zone_id, MFF_LOG_CT_ZONE, 0, 32, &ofpacts);
             }
 
+            int zone_id_dnat, zone_id_snat;
+            char *dnat = alloc_nat_zone_key(binding, "dnat");
+            char *snat = alloc_nat_zone_key(binding, "snat");
+            zone_id_dnat = simap_get(ct_zones, dnat);
+            if (zone_id_dnat) {
+                put_load(zone_id_dnat, MFF_LOG_DNAT_ZONE, 0, 32, &ofpacts);
+            }
+            free(dnat);
+
+            zone_id_snat = simap_get(ct_zones, snat);
+            if (zone_id_snat) {
+                put_load(zone_id_snat, MFF_LOG_SNAT_ZONE, 0, 32, &ofpacts);
+            }
+            free(snat);
+
             /* Set MFF_LOG_DATAPATH and MFF_LOG_INPORT. */
             put_load(dp_key, MFF_LOG_DATAPATH, 0, 64, &ofpacts);
             put_load(port_key, MFF_LOG_INPORT, 0, 32, &ofpacts);
@@ -403,6 +419,12 @@ physical_run(struct controller_ctx *ctx, enum mf_field_id mff_ovn_geneve,
             if (zone_id) {
                 put_load(zone_id, MFF_LOG_CT_ZONE, 0, 32, &ofpacts);
             }
+            if (zone_id_dnat) {
+                put_load(zone_id_dnat, MFF_LOG_DNAT_ZONE, 0, 32, &ofpacts);
+            }
+            if (zone_id_snat) {
+                put_load(zone_id_snat, MFF_LOG_SNAT_ZONE, 0, 32, &ofpacts);
+            }
 
             /* Resubmit to table 34. */
             put_resubmit(OFTABLE_DROP_LOOPBACK, &ofpacts);
index 59f1cee..f0f97a9 100644 (file)
  * These values are documented in ovn-architecture(7), please update the
  * documentation if you change any of them. */
 #define MFF_LOG_DATAPATH MFF_METADATA /* Logical datapath (64 bits). */
-#define MFF_LOG_CT_ZONE  MFF_REG5     /* Logical conntrack zone (32 bits). */
+#define MFF_LOG_DNAT_ZONE  MFF_REG3   /* conntrack dnat zone for gateway router
+                                       * (32 bits). */
+#define MFF_LOG_SNAT_ZONE  MFF_REG4   /* conntrack snat zone for gateway router
+                                       * (32 bits). */
+#define MFF_LOG_CT_ZONE  MFF_REG5     /* Logical conntrack zone for lports
+                                       * (32 bits). */
 #define MFF_LOG_INPORT   MFF_REG6     /* Logical input port (32 bits). */
 #define MFF_LOG_OUTPORT  MFF_REG7     /* Logical output port (32 bits). */
 
@@ -33,8 +38,6 @@
 #define MFF_LOG_REGS \
     MFF_LOG_REG(MFF_REG0) \
     MFF_LOG_REG(MFF_REG1) \
-    MFF_LOG_REG(MFF_REG2) \
-    MFF_LOG_REG(MFF_REG3) \
-    MFF_LOG_REG(MFF_REG4)
+    MFF_LOG_REG(MFF_REG2)
 
 #endif /* ovn/lib/logical-fields.h */
index abdc247..5a1dcb6 100644 (file)
@@ -15,6 +15,7 @@
 #include <config.h>
 #include "ovn-util.h"
 #include "openvswitch/vlog.h"
+#include "ovn/lib/ovn-sb-idl.h"
 
 VLOG_DEFINE_THIS_MODULE(ovn_util);
 
@@ -102,3 +103,15 @@ extract_lport_addresses(char *address, struct lport_addresses *laddrs,
 
     return true;
 }
+
+/* Allocates a key for NAT conntrack zone allocation for a provided
+ * 'port_binding' record and a 'type'.
+ *
+ * It is the caller's responsibility to free the allocated memory. */
+char *
+alloc_nat_zone_key(const struct sbrec_port_binding *port_binding,
+                   const char *type)
+{
+    return xasprintf(UUID_FMT"_%s",
+                     UUID_ARGS(&port_binding->datapath->header_.uuid), type);
+}
index 242984a..f475e6f 100644 (file)
@@ -18,6 +18,8 @@
 
 #include "lib/packets.h"
 
+struct sbrec_port_binding;
+
 struct ipv4_netaddr {
     ovs_be32 addr;
     unsigned int plen;
@@ -40,5 +42,7 @@ bool
 extract_lport_addresses(char *address, struct lport_addresses *laddrs,
                         bool store_ipv6);
 
-
+char *
+alloc_nat_zone_key(const struct sbrec_port_binding *port_binding,
+                   const char *type);
 #endif
index 13acaf5..553c2e5 100644 (file)
       </p>
     </dd>
 
-    <dt>conntrack zone field</dt>
+    <dt>conntrack zone field for logical ports</dt>
     <dd>
-      A field that denotes the connection tracking zone.  The value only
-      has local significance and is not meaningful between chassis.
-      This is initialized to 0 at the beginning of the logical ingress
-      pipeline.  OVN stores this in Nicira extension register number 5.
+      A field that denotes the connection tracking zone for logical ports.
+      The value only has local significance and is not meaningful between
+      chassis.  This is initialized to 0 at the beginning of the logical
+      ingress pipeline.  OVN stores this in Nicira extension register number 5.
+    </dd>
+
+    <dt>conntrack zone fields for Gateway router</dt>
+    <dd>
+      Fields that denote the connection tracking zones for Gateway routers.
+      These values only have local significance (only on chassis that have
+      Gateway routers instantiated) and is not meaningful between
+      chassis.  OVN stores the zone information for DNATting in Nicira
+      extension register number 3 and zone information for SNATing in Nicira
+      extension register number 4.
     </dd>
 
     <dt>VLAN ID</dt>