Implement SFC integration
[groupbasedpolicy.git] / renderers / ofoverlay / src / main / java / org / opendaylight / groupbasedpolicy / renderer / ofoverlay / flow / SourceMapper.java
index 9e6f17446fdf9a255d9697d2d4e0e3aa17c0d5b6..e5e297e3fbbc3847cb239cffc3ce4ac23ab1718a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
@@ -8,29 +8,34 @@
 
 package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow;
 
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.addNxTunIdMatch;
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.applyActionIns;
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.ethernetMatch;
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.gotoTableIns;
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.instructions;
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadRegAction;
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadTunIdAction;
+
 import java.math.BigInteger;
-import java.util.List;
-import java.util.Map;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
 
-import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
-import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager.Dirty;
-import org.opendaylight.groupbasedpolicy.resolver.ConditionGroup;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager.FlowMap;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.OrdinalFactory.EndpointFwdCtxOrdinals;
 import org.opendaylight.groupbasedpolicy.resolver.EgKey;
 import org.opendaylight.groupbasedpolicy.resolver.IndexedTenant;
 import org.opendaylight.groupbasedpolicy.resolver.PolicyInfo;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action;
 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;
+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;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
 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.EndpointGroup;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2BridgeDomain;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2FloodDomain;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L3Context;
 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.openflowjava.nx.match.rev140421.NxmNxReg0;
@@ -38,24 +43,24 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev14
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg4;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg5;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg6;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.*;
+import com.google.common.collect.Sets;
 
 /**
- * Manage the table that assigns source endpoint group, bridge domain, and 
+ * Manage the table that assigns source endpoint group, bridge domain, and
  * router domain to registers to be used by other tables.
- * @author readams
  */
 public class SourceMapper extends FlowTable {
-    protected static final Logger LOG =
-            LoggerFactory.getLogger(SourceMapper.class);
 
+    protected static final Logger LOG = LoggerFactory.getLogger(SourceMapper.class);
+
+    // TODO Li alagalah Improve UT coverage for this class.
     public static final short TABLE_ID = 1;
 
-    public SourceMapper(OfTable.OfTableCtx ctx) {
+    public SourceMapper(OfContext ctx) {
         super(ctx);
     }
 
@@ -65,114 +70,167 @@ public class SourceMapper extends FlowTable {
     }
 
     @Override
-    public void sync(ReadWriteTransaction t,
-                     InstanceIdentifier<Table> tiid,
-                     Map<String, FlowCtx> flowMap, 
-                     NodeId nodeId, PolicyInfo policyInfo, 
-                     Dirty dirty) throws Exception {
-        dropFlow(t, tiid, flowMap, Integer.valueOf(1), null);
-
-        for (EgKey sepg : ctx.epManager.getGroupsForNode(nodeId)) {
-            IndexedTenant tenant = 
-                    ctx.policyResolver.getTenant(sepg.getTenantId());
-            if (tenant == null) continue;
-
-            EndpointGroup eg = tenant.getEndpointGroup(sepg.getEgId());
-            L3Context l3c = tenant.resolveL3Context(eg.getNetworkDomain());
-            L2BridgeDomain bd = tenant.resolveL2BridgeDomain(eg.getNetworkDomain());
-            L2FloodDomain fd = tenant.resolveL2FloodDomain(eg.getNetworkDomain());
-            int egId = 0, bdId = 0, fdId = 0, l3Id = 0;
-            
-            egId = ctx.policyManager.getContextOrdinal(sepg.getTenantId(), 
-                                                       sepg.getEgId());
-            if (bd != null)
-                bdId = ctx.policyManager.getContextOrdinal(sepg.getTenantId(), 
-                                                           bd.getId());
-            if (fd != null)
-                fdId = ctx.policyManager.getContextOrdinal(sepg.getTenantId(), 
-                                                           fd.getId());
-            if (l3c != null)
-                l3Id = ctx.policyManager.getContextOrdinal(sepg.getTenantId(), 
-                                                           l3c.getId());
-
-            NodeConnectorId tunPort =
-                    ctx.switchManager.getTunnelPort(nodeId);
-            if (tunPort != null) {
-                FlowId flowid = new FlowId(new StringBuilder()
-                    .append(tunPort.getValue())
-                    .append("|tunnel|")
-                    .append(egId)
-                    .append("|")
-                    .append(bdId)
-                    .append("|")
-                    .append(fdId)
-                    .append("|")
-                    .append(l3Id)
-                    .toString());
-                if (visit(flowMap, flowid.getValue())) {
-                    MatchBuilder mb = new MatchBuilder()
-                        .setInPort(tunPort);
-                    addNxTunIdMatch(mb, egId);
-                    Action segReg = nxLoadRegAction(NxmNxReg0.class, 
-                                                    BigInteger.valueOf(egId));
-                    // set condition group register to all ones to bypass
-                    // policy enforcement
-                    Action scgReg = nxLoadRegAction(NxmNxReg1.class,
-                                                    BigInteger.valueOf(0xffffff));
-                    Action bdReg = nxLoadRegAction(NxmNxReg4.class, 
-                                                   BigInteger.valueOf(bdId));
-                    Action fdReg = nxLoadRegAction(NxmNxReg5.class, 
-                                                   BigInteger.valueOf(fdId));
-                    Action vrfReg = nxLoadRegAction(NxmNxReg6.class, 
-                                                    BigInteger.valueOf(l3Id));
-                    FlowBuilder flowb = base()
-                        .setId(flowid)
-                        .setPriority(Integer.valueOf(150))
-                        .setMatch(mb.build())
-                        .setInstructions(instructions(applyActionIns(segReg,
-                                                                     scgReg,
-                                                                     bdReg,
-                                                                     fdReg,
-                                                                     vrfReg),
-                                                      gotoTableIns((short)(TABLE_ID + 1))));
-                    writeFlow(t, tiid, flowb.build());
-                }
+    public void sync(NodeId nodeId, PolicyInfo policyInfo, FlowMap flowMap) throws Exception {
+
+        flowMap.writeFlow(nodeId, TABLE_ID, dropFlow(Integer.valueOf(1), null));
+
+        for (Endpoint ep : ctx.getEndpointManager().getEndpointsForNode(nodeId)) {
+            OfOverlayContext ofc = ep.getAugmentation(OfOverlayContext.class);
+            if (ofc != null && ofc.getNodeConnectorId() != null
+                    && (ofc.getLocationType() == null || LocationType.Internal.equals(ofc.getLocationType()))
+                    && ep.getTenant() != null && (ep.getEndpointGroup() != null || ep.getEndpointGroups() != null)) {
+
+                IndexedTenant tenant = ctx.getPolicyResolver().getTenant(ep.getTenant());
+                if (tenant == null)
+                    continue;
+
+                EndpointFwdCtxOrdinals epFwdCtxOrds = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo, ep);
+                EgKey sepg = new EgKey(ep.getTenant(), ep.getEndpointGroup());
+
+                createRemoteTunnels(flowMap, nodeId, ep, policyInfo, epFwdCtxOrds);
+
+                /**
+                 * Sync the local EP information.
+                 */
+                syncEP(flowMap, policyInfo, nodeId, ep, ofc, sepg, epFwdCtxOrds);
+            }
+        }
+    }
+
+    private void createRemoteTunnels(FlowMap flowMap, NodeId nodeId, Endpoint ep, PolicyInfo policyInfo,
+            EndpointFwdCtxOrdinals epFwdCtxOrds) throws Exception {
+        Set<EgKey> epgs = new HashSet<>();
+
+        // Get EPGs and add to Set to remove duplicates
+        // TODO alagalah Li: test EndpointManager.getEgKeys
+        if (ep.getEndpointGroup() != null) {
+            epgs.add(new EgKey(ep.getTenant(), ep.getEndpointGroup()));
+        }
+        if (ep.getEndpointGroups() != null) {
+            for (EndpointGroupId epgId : ep.getEndpointGroups()) {
+                epgs.add(new EgKey(ep.getTenant(), epgId));
             }
-            
-            for (Endpoint e : ctx.epManager.getEPsForNode(nodeId, sepg)) {
-                OfOverlayContext ofc = e.getAugmentation(OfOverlayContext.class);
-                if (ofc != null && ofc.getNodeConnectorId() != null &&
-                        (ofc.getLocationType() == null ||
-                        LocationType.Internal.equals(ofc.getLocationType())) &&
-                        e.getTenant() != null && e.getEndpointGroup() != null) {
-                    syncEP(t, tiid, flowMap, policyInfo, nodeId, e, ofc,
-                           egId, bdId, fdId, l3Id);
-                } 
+        }
+
+        // Create tunnels on remote Nodes that may talk to us.
+        for (EgKey epg : epgs) {
+            Set<EgKey> peers = Sets.union(Collections.singleton(epg), policyInfo.getPeers(epg));
+            for (EgKey peer : peers) {
+                for (NodeId remoteNodeId : ctx.getEndpointManager().getNodesForGroup(peer)) {
+
+                    // Please do not check for remote v local nodeID, we need local to local tunnels
+                    // in the case of chaining - The Great Dr Sunal.
+                    NodeConnectorId tunPort = ctx.getSwitchManager().getTunnelPort(remoteNodeId, TunnelTypeVxlan.class);
+                    if (tunPort == null) {
+                        LOG.trace("No tunnel port for tunnel in SourceMapper between local:{} and remote:{}",
+                                nodeId.getValue(), remoteNodeId.getValue());
+                        continue;
+                    }
+                    flowMap.writeFlow(remoteNodeId, TABLE_ID, createTunnelFlow(tunPort, epFwdCtxOrds));
+                    flowMap.writeFlow(remoteNodeId, TABLE_ID, createBroadcastFlow(tunPort, epFwdCtxOrds));
+                }
             }
         }
     }
-    
-    private void syncEP(ReadWriteTransaction t,
-                        InstanceIdentifier<Table> tiid,
-                        Map<String, FlowCtx> flowMap, 
-                        PolicyInfo policyInfo,
-                        NodeId nodeId, Endpoint e, OfOverlayContext ofc,
-                        int egId, int bdId, int fdId, int l3Id) 
-                                 throws Exception {
-        // Set sEPG, flood domain, bridge domain, and layer 3 context 
-        // for internal endpoints by directly matching each endpoint
-
-        List<ConditionName> conds = ctx.epManager.getCondsForEndpoint(e);
-        ConditionGroup cg = 
-                policyInfo.getEgCondGroup(new EgKey(e.getTenant(), 
-                                                    e.getEndpointGroup()), 
-                                          conds);
-        int cgId = ctx.policyManager.getCondGroupOrdinal(cg);
-
-        FlowId flowid = new FlowId(new StringBuilder()
-            .append(ofc.getNodeConnectorId().getValue())
+
+    private Flow createBroadcastFlow(NodeConnectorId tunPort, EndpointFwdCtxOrdinals epFwdCtxOrds) {
+
+        int fdId = epFwdCtxOrds.getFdId();
+
+        FlowId flowid = new FlowId(new StringBuilder().append(tunPort.getValue())
+            .append("|tunnel|")
+            .append("|")
+            .append(fdId)
+            .toString());
+
+        MatchBuilder mb = new MatchBuilder().setInPort(tunPort);
+        addNxTunIdMatch(mb, fdId);
+
+        // set condition group register to all ones to
+        // bypass
+        // policy enforcement
+        /*
+         * TODO: This breaks distributed policy enforcement
+         * especially wrt multi-action. BAD. Must be addressed
+         * (this is why we can't have nice things).
+         * This can be fixed with new tunnelId ordinal in
+         * Ordinal Factory.
+         */
+
+        Action fdReg = nxLoadRegAction(NxmNxReg5.class, BigInteger.valueOf(fdId));
+
+        FlowBuilder flowb = base().setId(flowid)
+            .setPriority(Integer.valueOf(150))
+            .setMatch(mb.build())
+            .setInstructions(instructions(applyActionIns(fdReg), gotoTableIns((short) (TABLE_ID + 1))));
+        return flowb.build();
+    }
+
+    private Flow createTunnelFlow(NodeConnectorId tunPort, EndpointFwdCtxOrdinals epFwdCtxOrds) {
+        // ... this is a remote node.
+
+        int egId = epFwdCtxOrds.getEpgId();
+        int bdId = epFwdCtxOrds.getBdId();
+        int fdId = epFwdCtxOrds.getFdId();
+        int l3Id = epFwdCtxOrds.getL3Id();
+        int tunnelId = epFwdCtxOrds.getTunnelId();
+
+        FlowId flowid = new FlowId(new StringBuilder().append(tunPort.getValue())
+            .append("|tunnel|")
+            .append(egId)
+            .append("|")
+            .append(bdId)
+            .append("|")
+            .append(fdId)
+            .append("|")
+            .append(l3Id)
+            .append("|")
+            .append(tunnelId)
+            .toString());
+
+        MatchBuilder mb = new MatchBuilder().setInPort(tunPort);
+        addNxTunIdMatch(mb, tunnelId);
+
+        Action segReg = nxLoadRegAction(NxmNxReg0.class, BigInteger.valueOf(egId));
+        // set condition group register to all ones to
+        // bypass
+        // policy enforcement
+        /*
+         * TODO: This breaks distributed policy enforcement
+         * especially wrt multi-action. BAD. Must be addressed
+         * (this is why we can't have nice things).
+         * This can be fixed with new tunnelId ordinal in
+         * Ordinal Factory.
+         */
+        Action scgReg = nxLoadRegAction(NxmNxReg1.class, BigInteger.valueOf(0xffffff));
+        Action bdReg = nxLoadRegAction(NxmNxReg4.class, BigInteger.valueOf(bdId));
+        Action fdReg = nxLoadRegAction(NxmNxReg5.class, BigInteger.valueOf(fdId));
+        Action vrfReg = nxLoadRegAction(NxmNxReg6.class, BigInteger.valueOf(l3Id));
+        FlowBuilder flowb = base().setId(flowid)
+            .setPriority(Integer.valueOf(150))
+            .setMatch(mb.build())
+            .setInstructions(
+                    instructions(applyActionIns(segReg, scgReg, bdReg, fdReg, vrfReg),
+                            gotoTableIns((short) (TABLE_ID + 1))));
+        return flowb.build();
+    }
+
+    private void syncEP(FlowMap flowMap, PolicyInfo policyInfo, NodeId nodeId, Endpoint ep, OfOverlayContext ofc,
+            EgKey egKey, EndpointFwdCtxOrdinals epFwdCtxOrds) throws Exception {
+
+        // TODO alagalah Li/Be: We should also match on EndpointL3 with the appropriate
+        // network containment. This would solve a lot of problems and prepare for EndpointL3 RPC.
+
+        int egId = epFwdCtxOrds.getEpgId();
+        int bdId = epFwdCtxOrds.getBdId();
+        int fdId = epFwdCtxOrds.getFdId();
+        int l3Id = epFwdCtxOrds.getL3Id();
+        int cgId = epFwdCtxOrds.getCgId();
+        int tunnelId = epFwdCtxOrds.getTunnelId();
+
+        FlowId flowid = new FlowId(new StringBuilder().append(ofc.getNodeConnectorId().getValue())
             .append("|")
-            .append(e.getMacAddress().getValue())
+            .append(ep.getMacAddress().getValue())
             .append("|")
             .append(egId)
             .append("|")
@@ -184,32 +242,23 @@ public class SourceMapper extends FlowTable {
             .append("|")
             .append(cgId)
             .toString());
-        if (visit(flowMap, flowid.getValue())) {
-            Action segReg = nxLoadRegAction(NxmNxReg0.class, 
-                                            BigInteger.valueOf(egId));
-            Action scgReg = nxLoadRegAction(NxmNxReg1.class, 
-                                            BigInteger.valueOf(cgId));
-            Action bdReg = nxLoadRegAction(NxmNxReg4.class, 
-                                           BigInteger.valueOf(bdId));
-            Action fdReg = nxLoadRegAction(NxmNxReg5.class, 
-                                           BigInteger.valueOf(fdId));
-            Action vrfReg = nxLoadRegAction(NxmNxReg6.class, 
-                                            BigInteger.valueOf(l3Id));
-            FlowBuilder flowb = base()
-                .setPriority(Integer.valueOf(100))
-                .setId(flowid)
-                .setMatch(new MatchBuilder()
-                    .setEthernetMatch(ethernetMatch(e.getMacAddress(), 
-                                                    null, null))
-                    .setInPort(ofc.getNodeConnectorId())
-                    .build())
-                .setInstructions(instructions(applyActionIns(segReg,
-                                                             scgReg,
-                                                             bdReg,
-                                                             fdReg,
-                                                             vrfReg),
-                                              gotoTableIns((short)(TABLE_ID + 1))));
-            writeFlow(t, tiid, flowb.build());
-        }
+        Action segReg = nxLoadRegAction(NxmNxReg0.class, BigInteger.valueOf(egId));
+        Action scgReg = nxLoadRegAction(NxmNxReg1.class, BigInteger.valueOf(cgId));
+        Action bdReg = nxLoadRegAction(NxmNxReg4.class, BigInteger.valueOf(bdId));
+        Action fdReg = nxLoadRegAction(NxmNxReg5.class, BigInteger.valueOf(fdId));
+        Action vrfReg = nxLoadRegAction(NxmNxReg6.class, BigInteger.valueOf(l3Id));
+        Action tunIdAction = nxLoadTunIdAction(BigInteger.valueOf(tunnelId), false);
+
+        FlowBuilder flowb = base().setPriority(Integer.valueOf(100))
+            .setId(flowid)
+            .setMatch(
+                    new MatchBuilder().setEthernetMatch(ethernetMatch(ep.getMacAddress(), null, null))
+                        .setInPort(ofc.getNodeConnectorId())
+                        .build())
+            .setInstructions(
+                    instructions(applyActionIns(segReg, scgReg, bdReg, fdReg, vrfReg,tunIdAction),
+                            gotoTableIns((short) (TABLE_ID + 1))));
+        flowMap.writeFlow(nodeId, TABLE_ID, flowb.build());
     }
+
 }