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>
#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"
}
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;
}
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
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,
* 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 *,
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 = xzalloc(sizeof *pd);
+ pd->local = local;
+ pd->port_binding = binding_rec;
hmap_insert(patched_datapaths, &pd->hmap_node,
binding_rec->datapath->tunnel_key);
}
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);
#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"
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);
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);
* 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). */
#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 */
#include <config.h>
#include "ovn-util.h"
#include "openvswitch/vlog.h"
+#include "ovn/lib/ovn-sb-idl.h"
VLOG_DEFINE_THIS_MODULE(ovn_util);
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);
+}
#include "lib/packets.h"
+struct sbrec_port_binding;
+
struct ipv4_netaddr {
ovs_be32 addr;
unsigned int plen;
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
</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>