Fixed NAT in OFOverlay based on EIG
[groupbasedpolicy.git] / renderers / ofoverlay / src / main / java / org / opendaylight / groupbasedpolicy / renderer / ofoverlay / flow / DestinationMapper.java
index 77a205c76fa98dda2dce39e2d0637b3e9bfa3b4f..7250e509dc74a6e7cd9488139523547e91eca7d2 100755 (executable)
@@ -8,28 +8,61 @@
 
 package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow;
 
-import com.google.common.base.Optional;
-import com.google.common.base.Strings;
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.SetMultimap;
-import com.google.common.collect.Sets;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.ARP;
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.IPv4;
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.IPv6;
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.addNxRegMatch;
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.applyActionIns;
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.decNwTtlAction;
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.ethernetMatch;
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.getOfPortNum;
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.gotoTableIns;
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.groupAction;
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.instructions;
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadArpOpAction;
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadArpShaAction;
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadArpSpaAction;
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadRegAction;
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadTunIPv4Action;
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadTunIdAction;
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxMoveArpShaToArpThaAction;
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxMoveArpSpaToArpTpaAction;
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxMoveEthSrcToEthDstAction;
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.outputAction;
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.setDlDstAction;
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.setDlSrcAction;
+import static org.opendaylight.groupbasedpolicy.util.DataStoreHelper.readFromDs;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.Set;
+
 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.groupbasedpolicy.endpoint.EpKey;
+import org.opendaylight.groupbasedpolicy.dto.EgKey;
+import org.opendaylight.groupbasedpolicy.dto.EpKey;
+import org.opendaylight.groupbasedpolicy.dto.IndexedTenant;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;
-import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager.FlowMap;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfWriter;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.endpoint.EndpointManager;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.RegMatch;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.OrdinalFactory.EndpointFwdCtxOrdinals;
-import org.opendaylight.groupbasedpolicy.resolver.EgKey;
-import org.opendaylight.groupbasedpolicy.resolver.PolicyInfo;
-import org.opendaylight.groupbasedpolicy.resolver.TenantUtils;
 import org.opendaylight.groupbasedpolicy.util.IidFactory;
+import org.opendaylight.groupbasedpolicy.util.TenantUtils;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Prefix;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
@@ -38,7 +71,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.M
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.NetworkDomainId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
@@ -49,14 +81,13 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.r
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Key;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Prefix;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.EndpointLocation.LocationType;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.Tenant;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L3Context;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.Subnet;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.ForwardingContext;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L3Context;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.Subnet;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetDestinationBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatchBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match;
@@ -74,44 +105,11 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.math.BigInteger;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Objects;
-import java.util.Set;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.ARP;
-import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.IPv4;
-import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.IPv6;
-import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.addNxRegMatch;
-import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.applyActionIns;
-import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.createNodePath;
-import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.decNwTtlAction;
-import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.ethernetMatch;
-import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.getOfPortNum;
-import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.gotoTableIns;
-import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.groupAction;
-import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.instructions;
-import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadArpOpAction;
-import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadArpShaAction;
-import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadArpSpaAction;
-import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadRegAction;
-import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadTunIPv4Action;
-import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadTunIdAction;
-import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxMoveArpShaToArpThaAction;
-import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxMoveArpSpaToArpTpaAction;
-import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxMoveEthSrcToEthDstAction;
-import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.outputAction;
-import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.setDlDstAction;
-import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.setDlSrcAction;
-import static org.opendaylight.groupbasedpolicy.util.DataStoreHelper.readFromDs;
+import com.google.common.base.Optional;
+import com.google.common.base.Strings;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.SetMultimap;
+import com.google.common.collect.Sets;
 
 /**
  * Manage the table that maps the destination address to the next hop for the
@@ -147,11 +145,11 @@ public class DestinationMapper extends FlowTable {
     }
 
     @Override
-    public void sync(NodeId nodeId, PolicyInfo policyInfo, FlowMap flowMap) throws Exception {
+    public void sync(NodeId nodeId, OfWriter ofWriter) throws Exception {
 
         TenantId currentTenant = null;
 
-        flowMap.writeFlow(nodeId, TABLE_ID, dropFlow(Integer.valueOf(1), null, TABLE_ID));
+        ofWriter.writeFlow(nodeId, TABLE_ID, dropFlow(Integer.valueOf(1), null, TABLE_ID));
 
         SetMultimap<EpKey, EpKey> visitedEps = HashMultimap.create();
         Set<EndpointFwdCtxOrdinals> epOrdSet = new HashSet<>();
@@ -165,7 +163,7 @@ public class DestinationMapper extends FlowTable {
 
             for (EndpointGroupId epgId : srcEpgIds) {
                 EgKey epg = new EgKey(srcEp.getTenant(), epgId);
-                Set<EgKey> peers = Sets.union(Collections.singleton(epg), policyInfo.getPeers(epg));
+                Set<EgKey> peers = Sets.union(Collections.singleton(epg), ctx.getCurrentPolicy().getPeers(epg));
                 for (EgKey peer : peers) {
                     for (Endpoint peerEp : ctx.getEndpointManager().getEndpointsForGroup(peer)) {
                         currentTenant = peerEp.getTenant();
@@ -176,12 +174,17 @@ public class DestinationMapper extends FlowTable {
                         if (visitedEps.get(srcEpKey) != null && visitedEps.get(srcEpKey).contains(peerEpKey)) {
                             continue;
                         }
-                        syncEP(flowMap, nodeId, policyInfo, srcEp, peerEp);
+                        syncEP(ofWriter, nodeId, srcEp, peerEp);
                         visitedEps.put(srcEpKey, peerEpKey);
 
                         // Process subnets and flood-domains for epPeer
-                        EndpointFwdCtxOrdinals epOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo,
+                        EndpointFwdCtxOrdinals epOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx,
                                 peerEp);
+                        if (epOrds == null) {
+                            LOG.debug("getEndpointFwdCtxOrdinals is null for EP {}", peerEp);
+                            continue;
+                        }
+
                         epOrdSet.add(epOrds);
                     }
                 }
@@ -199,7 +202,7 @@ public class DestinationMapper extends FlowTable {
                 Flow arpFlow = createRouterArpFlow(currentTenant, nodeId, sn,
                         OrdinalFactory.getContextOrdinal(currentTenant, l3c.getId()));
                 if (arpFlow != null) {
-                    flowMap.writeFlow(nodeId, TABLE_ID, arpFlow);
+                    ofWriter.writeFlow(nodeId, TABLE_ID, arpFlow);
                 } else {
                     LOG.debug(
                             "Gateway ARP flow is not created, because virtual router IP has not been set for subnet {} .",
@@ -210,8 +213,8 @@ public class DestinationMapper extends FlowTable {
 
         // Write broadcast flows per flood domain.
         for (EndpointFwdCtxOrdinals epOrd : epOrdSet) {
-            if (groupExists(nodeId, epOrd.getFdId())) {
-                flowMap.writeFlow(nodeId, TABLE_ID, createBroadcastFlow(epOrd));
+            if (ofWriter.groupExists(nodeId, Integer.valueOf(epOrd.getFdId()).longValue())) {
+                ofWriter.writeFlow(nodeId, TABLE_ID, createBroadcastFlow(epOrd));
             }
         }
 
@@ -225,21 +228,20 @@ public class DestinationMapper extends FlowTable {
                     continue;
                 }
                 for (Subnet localSubnet: localSubnets) {
-                    Flow prefixFlow = createL3PrefixFlow(prefixEp, policyInfo, nodeId, localSubnet);
+                    Flow prefixFlow = createL3PrefixFlow(prefixEp, nodeId, localSubnet);
                     if (prefixFlow != null) {
-                        flowMap.writeFlow(nodeId, TABLE_ID, prefixFlow);
+                        ofWriter.writeFlow(nodeId, TABLE_ID, prefixFlow);
                         LOG.trace("Wrote L3Prefix flow");
                     }
                 }
             }
         }
-
     }
 
     // set up next-hop destinations for all the endpoints in the endpoint
     // group on the node
 
-    private Flow createL3PrefixFlow(EndpointL3Prefix prefixEp, PolicyInfo policyInfo, NodeId nodeId, Subnet subnet) throws Exception {
+    private Flow createL3PrefixFlow(EndpointL3Prefix prefixEp, NodeId nodeId, Subnet subnet) throws Exception {
         /*
          * Priority: 100+lengthprefix
          * Match: prefix, l3c, "mac address of router" ?
@@ -273,7 +275,11 @@ public class DestinationMapper extends FlowTable {
             return null;
         }
         Endpoint l2Ep = optL2Ep.get();
-        EndpointFwdCtxOrdinals epFwdCtxOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo, l2Ep);
+        EndpointFwdCtxOrdinals epFwdCtxOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, l2Ep);
+        if (epFwdCtxOrds == null) {
+            LOG.debug("getEndpointFwdCtxOrdinals is null for EP {}", l2Ep);
+            return null;
+        }
 
         NetworkDomainId epNetworkContainment = getEPNetworkContainment(l2Ep);
 
@@ -299,21 +305,9 @@ public class DestinationMapper extends FlowTable {
         String nextHop=null;
 
         OfOverlayContext ofc = l2Ep.getAugmentation(OfOverlayContext.class);
-        LocationType location;
-
-        if (ofc != null && ofc.getLocationType() != null) {
-            location = ofc.getLocationType();
-        } else if (ofc != null) {
-            // Augmentation, but using default location
-            location = LocationType.Internal;
-        } else {
-            LOG.info("createL3PrefixFlow - Endpoint {} had no augmentation.", l2Ep);
-            return null;
-        }
 
         long portNum = -1;
-
-        if (location.equals(LocationType.Internal)) {
+        if (EndpointManager.isInternal(l2Ep, ctx.getTenant(l2Ep.getTenant()).getExternalImplicitGroups())) {
             checkNotNull(ofc.getNodeConnectorId());
             nextHop = ofc.getNodeConnectorId().getValue();
             try {
@@ -408,11 +402,10 @@ public class DestinationMapper extends FlowTable {
 
     private Flow createBroadcastFlow(EndpointFwdCtxOrdinals epOrd) {
         MatchBuilder mb = new MatchBuilder()
-                            .setEthernetMatch(new EthernetMatchBuilder()
-                            .setEthernetDestination(new EthernetDestinationBuilder().
-                                                        setAddress(MULTICAST_MAC)
-                                                        .setMask(MULTICAST_MAC).build())
-                            .build());
+                .setEthernetMatch(new EthernetMatchBuilder().setEthernetDestination(
+                        new EthernetDestinationBuilder().setAddress(MULTICAST_MAC)
+                                .setMask(MULTICAST_MAC)
+                                .build()).build());
         addNxRegMatch(mb, RegMatch.of(NxmNxReg5.class, Long.valueOf(epOrd.getFdId())));
 
         Match match = mb.build();
@@ -427,32 +420,6 @@ public class DestinationMapper extends FlowTable {
         return flowb.build();
     }
 
-    private boolean groupExists(NodeId nodeId, Integer fdId) throws Exception {
-        // Fetch existing GroupTables
-        if (ctx.getDataBroker() == null) {
-            return false;
-        }
-
-        ReadOnlyTransaction t = ctx.getDataBroker().newReadOnlyTransaction();
-        InstanceIdentifier<Node> niid = createNodePath(nodeId);
-        Optional<Node> r = t.read(LogicalDatastoreType.CONFIGURATION, niid).get();
-        if (!r.isPresent())
-            return false;
-        FlowCapableNode fcn = r.get().getAugmentation(FlowCapableNode.class);
-        if (fcn == null)
-            return false;
-
-        if (fcn.getGroup() != null) {
-            for (Group g : fcn.getGroup()) {
-                if (g.getGroupId().getValue().equals(Long.valueOf(fdId))) { // Group
-                                                                            // Exists.
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
     private MacAddress routerPortMac(L3Context l3c, IpAddress ipAddress) {
 
         if (ctx.getDataBroker() == null) {
@@ -485,7 +452,12 @@ public class DestinationMapper extends FlowTable {
     }
 
     private L3Context getL3ContextForSubnet(TenantId tenantId, Subnet sn) {
-        L3Context l3c = ctx.getPolicyResolver().getTenant(tenantId).resolveL3Context(sn.getId());
+        IndexedTenant indexedTenant = ctx.getTenant(tenantId);
+        if (indexedTenant == null) {
+            LOG.debug("Tenant {} is null, cannot get L3 context", tenantId);
+            return null;
+        }
+        L3Context l3c = indexedTenant.resolveL3Context(sn.getId());
         return l3c;
     }
 
@@ -593,21 +565,39 @@ public class DestinationMapper extends FlowTable {
         return flowb.build();
     }
 
-    private void syncEP(FlowMap flowMap, NodeId nodeId, PolicyInfo policyInfo, Endpoint srcEp, Endpoint destEp)
+    private void syncEP(OfWriter ofWriter, NodeId nodeId, Endpoint srcEp, Endpoint destEp)
             throws Exception {
 
+        if (ctx.getTenant(srcEp.getTenant()) == null
+                || ctx.getTenant(destEp.getTenant()) == null) {
+            LOG.debug("Source or destination EP references empty tenant srcEp:{} destEp:{}", srcEp, destEp);
+            return;
+        }
+
         // TODO: Conditions messed up, but for now, send policyInfo until this
         // is fixed.
-        EndpointFwdCtxOrdinals destEpFwdCtxOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo, destEp);
-        EndpointFwdCtxOrdinals srcEpFwdCtxOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo, srcEp);
+        EndpointFwdCtxOrdinals destEpFwdCtxOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, destEp);
+        if (destEpFwdCtxOrds == null) {
+            LOG.debug("getEndpointFwdCtxOrdinals is null for EP {}", destEp);
+            return;
+        }
+        EndpointFwdCtxOrdinals srcEpFwdCtxOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, srcEp);
+        if (srcEpFwdCtxOrds == null) {
+            LOG.debug("getEndpointFwdCtxOrdinals is null for EP {}", srcEp);
+            return;
+        }
+
 
         if (destEp.getTenant() == null || (destEp.getEndpointGroup() == null && destEp.getEndpointGroups() == null)) {
-            LOG.trace("Didn't process endpoint due to either tenant, or EPG(s) being null", destEp.getKey());
+            if (destEp.getTenant() == null) {
+                LOG.debug("Didn't process endpoint {} due to tenant being null", destEp.getKey());
+            } else {
+                LOG.debug("Didn't process endpoint {} due to EPG(s) being null", destEp.getKey());
+            }
             return;
         }
-        OfOverlayContext ofc = destEp.getAugmentation(OfOverlayContext.class);
 
-        if (LocationType.External.equals(ofc.getLocationType())) {
+        if (EndpointManager.isExternal(destEp, ctx.getTenant(destEp.getTenant()).getExternalImplicitGroups())) {
             LOG.error("syncEp(): External endpoints should not be seen here.");
             return;
         }
@@ -624,12 +614,13 @@ public class DestinationMapper extends FlowTable {
             return;
         }
 
+        OfOverlayContext ofc = destEp.getAugmentation(OfOverlayContext.class);
         if (Objects.equals(ofc.getNodeId(), nodeId)) {
             // this is a local endpoint; send to the approppriate local
             // port
 
             if (srcEpFwdCtxOrds.getBdId() == destEpFwdCtxOrds.getBdId()) {
-                flowMap.writeFlow(nodeId, TABLE_ID, createLocalL2Flow(destEp, destEpFwdCtxOrds, ofc));
+                ofWriter.writeFlow(nodeId, TABLE_ID, createLocalL2Flow(destEp, destEpFwdCtxOrds, ofc));
             }
             // TODO Li alagalah: Need to move to EndpointL3 for L3 processing.
             // The Endpoint conflation must end!
@@ -647,7 +638,7 @@ public class DestinationMapper extends FlowTable {
                     for (Subnet localSubnet : localSubnets) {
                         Flow flow = createLocalL3RoutedFlow(destEp, l3a, destEpFwdCtxOrds, ofc, localSubnet);
                         if (flow != null) {
-                            flowMap.writeFlow(nodeId, TABLE_ID, flow);
+                            ofWriter.writeFlow(nodeId, TABLE_ID, flow);
                         } else {
                             LOG.trace("Did not write remote L3 flow for endpoint {} and subnet {}", l3a.getIpAddress(),
                                     localSubnet.getIpPrefix().getValue());
@@ -661,7 +652,7 @@ public class DestinationMapper extends FlowTable {
             if (srcEpFwdCtxOrds.getBdId() == destEpFwdCtxOrds.getBdId()) {
                 Flow remoteL2Flow = createRemoteL2Flow(destEp, nodeId, srcEpFwdCtxOrds, destEpFwdCtxOrds, ofc);
                 if (remoteL2Flow != null) {
-                    flowMap.writeFlow(nodeId, TABLE_ID, remoteL2Flow);
+                    ofWriter.writeFlow(nodeId, TABLE_ID, remoteL2Flow);
                 }
             } else {
                 LOG.trace("DestinationMapper: RemoteL2Flow: not created, in different BDs src: {} dst: {}",
@@ -684,7 +675,7 @@ public class DestinationMapper extends FlowTable {
                         Flow remoteL3Flow = createRemoteL3RoutedFlow(destEp, l3a, nodeId, srcEpFwdCtxOrds,
                                 destEpFwdCtxOrds, ofc, localSubnet);
                         if (remoteL3Flow != null) {
-                            flowMap.writeFlow(nodeId, TABLE_ID, remoteL3Flow);
+                            ofWriter.writeFlow(nodeId, TABLE_ID, remoteL3Flow);
                         } else {
                             LOG.trace("Did not write remote L3 flow for endpoint {} and subnet {}", l3a.getIpAddress(),
                                     localSubnet.getIpPrefix().getValue());
@@ -1106,8 +1097,7 @@ public class DestinationMapper extends FlowTable {
              * which we can't do because of the backwards way endpoints were
              * "architected".
              */
-            return ctx.getPolicyResolver()
-                .getTenant(endpoint.getTenant())
+            return ctx.getTenant(endpoint.getTenant())
                 .getEndpointGroup(endpoint.getEndpointGroup())
                 .getNetworkDomain();
         }
@@ -1115,10 +1105,6 @@ public class DestinationMapper extends FlowTable {
 
     private HashSet<Subnet> getSubnets(final TenantId tenantId) {
 
-        // if (subnetsByTenant.get(tenantId) != null) {
-        // return subnetsByTenant.get(tenantId);
-        // }
-
         if (ctx.getDataBroker() == null) {
             return null;
         }
@@ -1131,18 +1117,20 @@ public class DestinationMapper extends FlowTable {
         } catch (Exception e) {
             LOG.error("Could not read Tenant {}", tenantId, e);
             return null;
+        } finally {
+            t.close();
         }
 
-        HashSet<Subnet> subnets = new HashSet<Subnet>();
-
         if (!tenantInfo.isPresent()) {
             LOG.warn("Tenant {} not found", tenantId);
             return null;
         }
 
-        subnets.addAll(tenantInfo.get().getSubnet());
-        // subnetsByTenant.put(tenantId, subnets);
-        return subnets;
+        ForwardingContext fwCtx = tenantInfo.get().getForwardingContext();
+        if (fwCtx == null || fwCtx.getSubnet() == null) {
+            return new HashSet<>();
+        }
+        return new HashSet<>(fwCtx.getSubnet());
     }
 
     // Need a method to get subnets for EPs attached to the node locally
@@ -1155,8 +1143,8 @@ public class DestinationMapper extends FlowTable {
         for (Endpoint endpoint : endpointsForNode) {
             HashSet<Subnet> subnets = getSubnets(endpoint.getTenant());
             if (subnets == null) {
-                LOG.error("No local subnets.");
-                return null;
+                LOG.debug("No local subnets in tenant {} for EP {}.", endpoint.getTenant(), endpoint.getKey());
+                continue;
             }
             NetworkDomainId epNetworkContainment = getEPNetworkContainment(endpoint);
             for (Subnet subnet : subnets) {