From b49b6b6a396d471b4e86417f33f1ec4fa881660e Mon Sep 17 00:00:00 2001 From: Vladimir Lavor Date: Wed, 30 Mar 2016 16:13:22 +0200 Subject: [PATCH] Bug 5617: Added UT for GroupTable and ChainActionFlows Signed-off-by: Vladimir Lavor Change-Id: I2a45247bbc7a3b611baa6a1cf55b26da06ef9232 (cherry picked from commit 619e7bf903b9f096af6617432350b9e8b5ff072a) --- .../ofoverlay/flow/ChainActionFlows.java | 6 +- .../renderer/ofoverlay/flow/GroupTable.java | 257 ++++++------- .../ofoverlay/flow/ChainActionFlowsTest.java | 311 +++++++++++++--- .../ofoverlay/flow/GroupTableTest.java | 349 +++++++++++------- 4 files changed, 591 insertions(+), 332 deletions(-) diff --git a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/ChainActionFlows.java b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/ChainActionFlows.java index d630535b3..f77fb1702 100755 --- a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/ChainActionFlows.java +++ b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/ChainActionFlows.java @@ -210,8 +210,7 @@ public class ChainActionFlows { return flowb.build(); } - @VisibleForTesting - static Flow createExternalFlow(SfcNshHeader sfcNshHeader, NodeConnectorId tunPort, NetworkElements netElements, + private static Flow createExternalFlow(SfcNshHeader sfcNshHeader, NodeConnectorId tunPort, NetworkElements netElements, PolicyManager policyManager, SwitchManager switchManager, Ipv4Address ipTunDest) { short tableId = policyManager.getTABLEID_EXTERNAL_MAPPER(); @@ -345,8 +344,7 @@ public class ChainActionFlows { } - @VisibleForTesting - static Integer returnOfPortFromNodeConnector(NodeConnectorId nodeConnectorId) { + private static Integer returnOfPortFromNodeConnector(NodeConnectorId nodeConnectorId) { String[] elements = StringUtils.split(nodeConnectorId.getValue(), ":"); if (elements.length != 3) return null; diff --git a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/GroupTable.java b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/GroupTable.java index 8b21fd13c..fdb53bf24 100644 --- a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/GroupTable.java +++ b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/GroupTable.java @@ -8,19 +8,8 @@ package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow; -import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.actionList; -import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.createNodePath; -import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.getOfPortNum; -import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadTunIPv4Action; -import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.outputAction; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.concurrent.ExecutionException; - -import org.antlr.v4.runtime.misc.Array2DHashSet; +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Optional; import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.groupbasedpolicy.dto.EgKey; @@ -46,7 +35,12 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.base.Optional; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.ExecutionException; + +import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.*; /** * Manage the group tables for handling broadcast/multicast @@ -60,156 +54,163 @@ public class GroupTable extends OfTable { super(ctx); } - FlowCapableNode getFCNodeFromDatastore(NodeId nodeId) - throws ExecutionException, InterruptedException { - FlowCapableNode fcn = null; - ReadOnlyTransaction t = ctx.getDataBroker().newReadOnlyTransaction(); - InstanceIdentifier fcniid = createNodePath(nodeId).builder() - .augmentation(FlowCapableNode.class).build(); - - Optional r = t.read(LogicalDatastoreType.OPERATIONAL, fcniid).get(); - if (!r.isPresent()) { - LOG.warn("Node {} is not present", fcniid); - return null; - } - fcn = r.get(); - t.close(); - return fcn; - } - @Override public void sync(Endpoint endpoint, OfWriter ofWriter) throws Exception { - - // TODO: only temporary workaround, use src & dst endpoint in implementation - NodeId nodeId = ctx.getEndpointManager().getEndpointNodeId(endpoint); + NodeId endpointNodeId = ctx.getEndpointManager().getEndpointNodeId(endpoint); + if (endpointNodeId == null) { + LOG.warn("Endpoint {} has no location specified, skipped", endpoint); + return; + } // there appears to be no way of getting only the existing group - // tables unfortunately, so we have to get the whole goddamned node. + // tables unfortunately, so we have to get the whole node. // Since this is happening concurrently with other things that are // working in subtrees of nodes, we have to do two transactions - FlowCapableNode fcn = getFCNodeFromDatastore(nodeId); + FlowCapableNode fcn = getFCNodeFromDatastore(endpointNodeId); if (fcn == null) return; + EndpointFwdCtxOrdinals ordinals = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, endpoint); + if (ordinals == null) { + LOG.info("getEndpointFwdCtxOrdinals is null for EP {}", endpoint); + return; + } + GroupId groupId = new GroupId(Long.valueOf(ordinals.getFdId())); + if (!ofWriter.groupExists(endpointNodeId, groupId.getValue())) { + LOG.info("createGroup {} {}", endpointNodeId, groupId); + ofWriter.writeGroup(endpointNodeId, groupId); + } + syncGroups(endpointNodeId, ordinals, endpoint, groupId, ofWriter); + } - for (Endpoint localEp : ctx.getEndpointManager().getEndpointsForNode(nodeId)) { - EndpointFwdCtxOrdinals localEpFwdCtxOrds = - OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, localEp); - if (localEpFwdCtxOrds == null) { - LOG.info("getEndpointFwdCtxOrdinals is null for EP {}", localEp); - continue; - } - - GroupId gid = new GroupId(Long.valueOf(localEpFwdCtxOrds.getFdId())); - if (!ofWriter.groupExists(nodeId, gid.getValue())) { - LOG.info("createGroup {} {}", nodeId, gid); - ofWriter.writeGroup(nodeId, gid); - } - - for (EgKey epg : ctx.getEndpointManager().getGroupsForNode(nodeId)) { - - // we'll use the fdId with the high bit set for remote bucket - // and just the local port number for local bucket - for (NodeId destNode : findPeerNodesForGroup(epg)) { - if (nodeId.equals(destNode)) + @VisibleForTesting + void syncGroups(NodeId nodeId, EndpointFwdCtxOrdinals ordinals, Endpoint endpoint, GroupId groupId, + OfWriter ofWriter) throws Exception { + for (EgKey endpointGroupKey : ctx.getEndpointManager().getGroupsForNode(nodeId)) { + // we'll use the fdId with the high bit set for remote bucket + // and just the local port number for local bucket + for (NodeId destinationNode : findPeerNodesForGroup(endpointGroupKey)) { + if (nodeId.equals(destinationNode)) + continue; + if (isFloodDomainOnNode(ordinals.getFdId(), destinationNode)) { + Long bucketId; + try { + bucketId = (long) OrdinalFactory.getContextOrdinal(destinationNode); + } catch (Exception e) { + LOG.error("Error during getting of context ordinal, node: {}", destinationNode); continue; - - if(isFloodDomainOnNode(localEpFwdCtxOrds.getFdId(), destNode)) { - long bucketId = OrdinalFactory.getContextOrdinal(destNode); - bucketId |= 1L << 31; - - IpAddress tunDst = ctx.getSwitchManager().getTunnelIP(destNode, TunnelTypeVxlan.class); - NodeConnectorId tunPort = ctx.getSwitchManager().getTunnelPort(nodeId, TunnelTypeVxlan.class); - if (tunDst == null || tunPort == null) - continue; - Action tundstAction = null; - if (tunDst.getIpv4Address() != null) { - String nextHop = tunDst.getIpv4Address().getValue(); - tundstAction = nxLoadTunIPv4Action(nextHop, true); - } else { - LOG.error("IPv6 tunnel destination {} for {} not supported", tunDst.getIpv6Address().getValue(), - destNode); - continue; - } - BucketBuilder bb = new BucketBuilder().setBucketId(new BucketId(Long.valueOf(bucketId))) - .setAction(actionList(tundstAction, outputAction(tunPort))); - ofWriter.writeBucket(nodeId, gid, bb.build()); } + bucketId |= 1L << 31; + IpAddress tunDst = ctx.getSwitchManager().getTunnelIP(destinationNode, TunnelTypeVxlan.class); + NodeConnectorId tunPort = ctx.getSwitchManager().getTunnelPort(nodeId, TunnelTypeVxlan.class); + if (tunDst == null || tunPort == null) + continue; + Action tunDstAction; + if (tunDst.getIpv4Address() != null) { + String nextHop = tunDst.getIpv4Address().getValue(); + tunDstAction = nxLoadTunIPv4Action(nextHop, true); + } else { + LOG.error("IPv6 tunnel destination {} for {} not supported", tunDst.getIpv6Address().getValue(), + destinationNode); + continue; + } + BucketBuilder bucketBuilder = new BucketBuilder().setBucketId(new BucketId(bucketId)) + .setAction(actionList(tunDstAction, outputAction(tunPort))); + ofWriter.writeBucket(nodeId, groupId, bucketBuilder.build()); } - // TODO broadcasts are not separated by EPG between endpoints on the same node - OfOverlayContext ofc = localEp.getAugmentation(OfOverlayContext.class); - if (EndpointManager.isExternal(localEp, ctx.getTenant(localEp.getTenant()).getExternalImplicitGroups())) - continue; - - long bucketId; - try { - bucketId = getOfPortNum(ofc.getNodeConnectorId()); - } catch (NumberFormatException e) { - LOG.warn("Could not parse port number {}", ofc.getNodeConnectorId(), e); - continue; - } - Action output = outputAction(ofc.getNodeConnectorId()); - BucketBuilder bb = new BucketBuilder().setBucketId(new BucketId(Long.valueOf(bucketId))).setAction( - FlowUtils.actionList(output)); - ofWriter.writeBucket(nodeId, gid, bb.build()); - - // if boradcast exceeds internal domain - for (Endpoint extEp : ctx.getEndpointManager().getExtEpsNoLocForGroup(epg)) { - if (extEp.getNetworkContainment() != null - && extEp.getNetworkContainment().equals(localEp.getNetworkContainment())) { - L2FloodDomain l2Fd = ctx.getTenant(extEp.getTenant()).resolveL2FloodDomain( - extEp.getNetworkContainment()); - if (l2Fd != null) { - Segmentation segmentation = l2Fd.getAugmentation(Segmentation.class); - // external endpoints do not have location augmentation - // however they are beyond external ports - for (NodeConnectorId extNcId : ctx.getSwitchManager().getExternalPorts(nodeId)) { - try { - bucketId = getOfPortNum(extNcId); - } catch (NumberFormatException e) { - LOG.warn("Could not parse external port number {}", extNcId, e); - continue; - } - ArrayList + } + // TODO broadcasts are not separated by EPG between endpoints on the same node + OfOverlayContext ofc = endpoint.getAugmentation(OfOverlayContext.class); + if (EndpointManager.isExternal(endpoint, ctx.getTenant(endpoint.getTenant()).getExternalImplicitGroups())) + continue; + long bucketId; + try { + bucketId = getOfPortNum(ofc.getNodeConnectorId()); + } catch (NumberFormatException e) { + LOG.warn("Could not parse port number {}", ofc.getNodeConnectorId(), e); + continue; + } + Action output = outputAction(ofc.getNodeConnectorId()); + BucketBuilder bb = new BucketBuilder().setBucketId(new BucketId(bucketId)).setAction( + FlowUtils.actionList(output)); + ofWriter.writeBucket(nodeId, groupId, bb.build()); + // if broadcast exceeds internal domain + for (Endpoint extEp : ctx.getEndpointManager().getExtEpsNoLocForGroup(endpointGroupKey)) { + if (extEp.getNetworkContainment() != null + && extEp.getNetworkContainment().equals(endpoint.getNetworkContainment())) { + L2FloodDomain l2Fd = ctx.getTenant(extEp.getTenant()) + .resolveL2FloodDomain(extEp.getNetworkContainment()); + if (l2Fd != null) { + Segmentation segmentation = l2Fd.getAugmentation(Segmentation.class); + // external endpoints do not have location augmentation + // however they are beyond external ports + for (NodeConnectorId extNcId : ctx.getSwitchManager().getExternalPorts(nodeId)) { + try { + bucketId = getOfPortNum(extNcId); + } catch (NumberFormatException e) { + LOG.warn("Could not parse external port number {}", extNcId, e); + continue; + } + ArrayList actionList = new ArrayList<>(); - if (segmentation != null) { - Integer vlanId = segmentation.getSegmentationId(); - actionList.addAll(FlowUtils.pushVlanActions(vlanId)); - actionList.add(new ActionBuilder().setOrder(2).setAction(outputAction(extNcId))); - } else { - actionList.add(new ActionBuilder().setOrder(0).setAction(outputAction(extNcId))); - } - bb.setBucketId(new BucketId(Long.valueOf(bucketId))).setAction( - FlowUtils.actionList(actionList)); - ofWriter.writeBucket(nodeId, gid, bb.build()); + if (segmentation != null) { + Integer vlanId = segmentation.getSegmentationId(); + actionList.addAll(FlowUtils.pushVlanActions(vlanId)); + actionList.add(new ActionBuilder().setOrder(2).setAction(outputAction(extNcId))); + } else { + actionList.add(new ActionBuilder().setOrder(0).setAction(outputAction(extNcId))); } + bb.setBucketId(new BucketId(bucketId)).setAction( + FlowUtils.actionList(actionList)); + ofWriter.writeBucket(nodeId, groupId, bb.build()); } } } } } + } /** * @param sourceEpgKey a key of source group * @return all the nodes on which endpoints are either in groups that have policy with source - * group, or are in the source group + * group, or are in the source group */ private Set findPeerNodesForGroup(EgKey sourceEpgKey) { - Set nodes = new HashSet(); + Set nodes = new HashSet<>(); nodes.addAll(ctx.getEndpointManager().getNodesForGroup(sourceEpgKey)); - for (EgKey dstEpgs : ctx.getCurrentPolicy().getPeers(sourceEpgKey)) { - nodes.addAll(ctx.getEndpointManager().getNodesForGroup(dstEpgs)); + for (EgKey dstEpGroups : ctx.getCurrentPolicy().getPeers(sourceEpgKey)) { + nodes.addAll(ctx.getEndpointManager().getNodesForGroup(dstEpGroups)); } return nodes; } private boolean isFloodDomainOnNode(int fdId, NodeId node) throws Exception { - for (Endpoint ep : ctx.getEndpointManager().getEndpointsForNode(node)) { - int epFdId = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, ep).getFdId(); + for (Endpoint endpoint : ctx.getEndpointManager().getEndpointsForNode(node)) { + EndpointFwdCtxOrdinals endpointFwdCtxOrdinals = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, endpoint); + if (endpointFwdCtxOrdinals == null) { + continue; + } + int epFdId = endpointFwdCtxOrdinals.getFdId(); if (fdId == epFdId) { return true; } } return false; } + + private FlowCapableNode getFCNodeFromDatastore(NodeId nodeId) + throws ExecutionException, InterruptedException { + ReadOnlyTransaction t = ctx.getDataBroker().newReadOnlyTransaction(); + InstanceIdentifier fcnIid = createNodePath(nodeId).builder() + .augmentation(FlowCapableNode.class).build(); + + Optional r = t.read(LogicalDatastoreType.OPERATIONAL, fcnIid).get(); + if (!r.isPresent()) { + LOG.warn("Node {} is not present", fcnIid); + return null; + } + FlowCapableNode fcn = r.get(); + t.close(); + return fcn; + } } diff --git a/renderers/ofoverlay/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/ChainActionFlowsTest.java b/renderers/ofoverlay/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/ChainActionFlowsTest.java index 0957f00b6..28d820e59 100644 --- a/renderers/ofoverlay/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/ChainActionFlowsTest.java +++ b/renderers/ofoverlay/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/ChainActionFlowsTest.java @@ -8,86 +8,277 @@ package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import org.junit.Assert; +import com.google.common.base.Preconditions; import org.junit.Before; import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.opendaylight.groupbasedpolicy.dto.EgKey; +import org.opendaylight.groupbasedpolicy.dto.PolicyInfo; +import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext; +import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfWriter; import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager; -import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.OrdinalFactory.EndpointFwdCtxOrdinals; +import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.endpoint.EndpointManager; +import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.mapper.MapperUtilsTest; import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.mapper.policyenforcer.NetworkElements; import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node.SwitchManager; import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sfcutils.SfcNshHeader; import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sfcutils.SfcNshHeader.SfcNshHeaderBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address; +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.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.Flow; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; +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.Match; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.fields.L3Address; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection; +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.TenantBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg0; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg1; +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.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg7; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlanGpe; -public class ChainActionFlowsTest { +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.RegMatch; +import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.addNxNsiMatch; +import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.addNxNspMatch; +import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.addNxRegMatch; +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.base; +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.nxLoadNshc1RegAction; +import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadNshc2RegAction; +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.nxOutputRegAction; - private SfcNshHeader sfcNshHeader; - private NodeConnectorId tunPort; - private NetworkElements netElements; - private PolicyManager policyManager; - private SwitchManager switchManager; - private Ipv4Address ip1 = new Ipv4Address("10.1.1.1"); - private Ipv4Address ip2 = new Ipv4Address("10.1.1.2"); +public class ChainActionFlowsTest extends MapperUtilsTest { + + @Captor + private final ArgumentCaptor nodeIdCaptor = ArgumentCaptor.forClass(NodeId.class); + private final ArgumentCaptor tableIdCaptor = ArgumentCaptor.forClass(Short.class); + private final ArgumentCaptor flowCaptor = ArgumentCaptor.forClass(Flow.class); @Before - public void setup() { - policyManager = mock(PolicyManager.class); + public void init() { + ctx = mock(OfContext.class); + endpointManager = mock(EndpointManager.class); switchManager = mock(SwitchManager.class); - EndpointFwdCtxOrdinals ords = mock(EndpointFwdCtxOrdinals.class); - sfcNshHeader = mock(SfcNshHeader.class); - netElements = mock(NetworkElements.class); - when(netElements.getSrcNodeId()).thenReturn(new NodeId("openflow:1")); - when(netElements.getSrcEpOrdinals()).thenReturn(ords); - when(netElements.getSrcEpOrdinals().getL3Id()).thenReturn(7); - when(netElements.getDstNodeId()).thenReturn(new NodeId("openflow:1")); - when(netElements.getDstEpOrdinals()).thenReturn(ords); - when(netElements.getDstEpOrdinals().getL3Id()).thenReturn(7); - when(netElements.getLocalNodeId()).thenReturn(new NodeId("openflow:1")); - tunPort = new NodeConnectorId("openflow:1:42"); + policyManager = mock(PolicyManager.class); + policyInfo = mock(PolicyInfo.class); + ofWriter = mock(OfWriter.class); } @Test - public void createExternalFlowTest() throws Exception { - // Note C1 != tunDest ie ip1 and ip2 - output action - sfcNshHeader = new SfcNshHeaderBuilder().setNshMetaC1(SfcNshHeader.convertIpAddressToLong(ip1)) - .setNshTunIpDst(ip2) - .setNshMetaC2(7L) - .setNshNsiToChain((short) 1) - .build(); - - Flow flow = ChainActionFlows.createExternalFlow(sfcNshHeader, tunPort, netElements, policyManager, switchManager, ip2); - assertEquals(policyManager.getTABLEID_EXTERNAL_MAPPER(), flow.getTableId().shortValue()); - assertTrue(flow.getInstructions().getInstruction() - .get(0).getInstruction().toString().contains("_outputAction=OutputAction")); - - // Note C1 == tunDest ie ip1 - sfcNshHeader = new SfcNshHeaderBuilder().setNshMetaC1(SfcNshHeader.convertIpAddressToLong(ip1)) - .setNshTunIpDst(ip1) - .setNshMetaC2(7L) - .setNshNsiToChain((short) 1) - .build(); - - flow = ChainActionFlows.createExternalFlow(sfcNshHeader, tunPort, netElements, policyManager, switchManager, ip2); - - assertTrue(flow.getInstructions().getInstruction() - .get(0).getInstruction().toString().contains("_outputAction=OutputAction")); + public void createChainTunnelFlows_directionIn() throws Exception { + // Tenant + TenantBuilder tenantBuilder = buildTenant(); + Tenant tenant = tenantBuilder.build(); + // Source Endpoint + EndpointBuilder sourceEndpointBuilder = buildEndpoint(IPV4_0, MAC_0, CONNECTOR_0); + Endpoint sourceEndpoint = sourceEndpointBuilder.build(); + EgKey sourceEgKey = new EgKey(tenant.getId(), ENDPOINT_GROUP_0); + // Destination Endpoint + EndpointBuilder destinationEndpointBuilder = buildEndpoint(IPV4_1, MAC_1, CONNECTOR_1); + Endpoint destinationEndpoint = destinationEndpointBuilder.build(); + EgKey destinationEgKey = new EgKey(tenant.getId(), ENDPOINT_GROUP_1); + // Nsh header + SfcNshHeaderBuilder nshHeaderBuilder = new SfcNshHeaderBuilder(); + nshHeaderBuilder.setNshNsiFromChain((short) 250); + nshHeaderBuilder.setNshNspFromChain(27L); + SfcNshHeader nshHeader = nshHeaderBuilder.build(); + + when(ctx.getTenant(any(TenantId.class))).thenReturn(getTestIndexedTenant()); + when(ctx.getEndpointManager()).thenReturn(endpointManager); + when(ctx.getSwitchManager()).thenReturn(switchManager); + when(ctx.getPolicyManager()).thenReturn(policyManager); + when(ctx.getCurrentPolicy()).thenReturn(policyInfo); + when(switchManager.getTunnelPort(NODE_ID, TunnelTypeVxlanGpe.class)).thenReturn(CONNECTOR_2); + when(switchManager.getTunnelIP(NODE_ID, TunnelTypeVxlanGpe.class)).thenReturn(new IpAddress(IPV4_2)); + when(policyManager.getTABLEID_PORTSECURITY()).thenReturn((short) 4); + when(policyManager.getTABLEID_SOURCE_MAPPER()).thenReturn((short) 2); + + // Net elements + NetworkElements netElements = new NetworkElements(sourceEndpoint, destinationEndpoint, sourceEgKey, + destinationEgKey, NODE_ID, ctx); + assertNotNull(netElements); + + ChainActionFlows.createChainTunnelFlows(nshHeader, netElements, ofWriter, ctx, HasDirection.Direction.In); + + // Verify flows and capture arguments + verify(ofWriter, times(4)).writeFlow(nodeIdCaptor.capture(), tableIdCaptor.capture(), flowCaptor.capture()); + + // Verify nodeIds + for (NodeId capturedNodeId : nodeIdCaptor.getAllValues()) { + assertEquals(capturedNodeId, NODE_ID); + } + + // Verify tableIds + List tableIds = tableIdCaptor.getAllValues(); + Short expectedTableIds[] = {4, 2, 0, 2}; + assertArrayEquals(expectedTableIds, tableIds.toArray()); + + // Verify flows + List flows = flowCaptor.getAllValues(); + assertNotNull(flows); + assertTrue(flows.size() == 4); + assertEquals(flows.get(0), allowFromChainTestFlow()); + assertEquals(flows.get(1), createChainTunnelTestFlow(netElements).get(0)); // contains only 1 entry + assertEquals(flows.get(2), allowFromChainTunnelTestFlow()); + assertEquals(flows.get(3), createChainBroadcastTestFlow()); } @Test - public void returnOfPortFromNodeConnectorTest() { - NodeConnectorId ncId = new NodeConnectorId("openflow:1:42"); - Integer port = ChainActionFlows.returnOfPortFromNodeConnector(ncId); - assertEquals(new Integer("42"), port); + public void createChainTunnelFlows_directionOut() throws Exception { + // Tenant + TenantBuilder tenantBuilder = buildTenant(); + Tenant tenant = tenantBuilder.build(); + // Source Endpoint + EndpointBuilder sourceEndpointBuilder = buildEndpoint(IPV4_0, MAC_0, CONNECTOR_0); + Endpoint sourceEndpoint = sourceEndpointBuilder.build(); + EgKey sourceEgKey = new EgKey(tenant.getId(), ENDPOINT_GROUP_0); + // Destination Endpoint + EndpointBuilder destinationEndpointBuilder = buildEndpoint(IPV4_1, MAC_1, CONNECTOR_1); + Endpoint destinationEndpoint = destinationEndpointBuilder.build(); + EgKey destinationEgKey = new EgKey(tenant.getId(), ENDPOINT_GROUP_1); + // Nsh header + SfcNshHeaderBuilder nshHeaderBuilder = new SfcNshHeaderBuilder(); + nshHeaderBuilder.setNshNsiToChain((short) 255); + nshHeaderBuilder.setNshNspToChain(27L); + nshHeaderBuilder.setNshTunIpDst(IPV4_2); + SfcNshHeader nshHeader = nshHeaderBuilder.build(); + + when(ctx.getTenant(any(TenantId.class))).thenReturn(getTestIndexedTenant()); + when(ctx.getEndpointManager()).thenReturn(endpointManager); + when(ctx.getSwitchManager()).thenReturn(switchManager); + when(ctx.getPolicyManager()).thenReturn(policyManager); + when(ctx.getCurrentPolicy()).thenReturn(policyInfo); + when(switchManager.getTunnelPort(NODE_ID, TunnelTypeVxlanGpe.class)).thenReturn(CONNECTOR_2); + when(switchManager.getTunnelIP(NODE_ID, TunnelTypeVxlanGpe.class)).thenReturn(new IpAddress(IPV4_2)); + when(policyManager.getTABLEID_EXTERNAL_MAPPER()).thenReturn((short) 6); + + + // Net elements + NetworkElements netElements = new NetworkElements(sourceEndpoint, destinationEndpoint, sourceEgKey, + destinationEgKey, NODE_ID, ctx); + assertNotNull(netElements); + + ChainActionFlows.createChainTunnelFlows(nshHeader, netElements, ofWriter, ctx, HasDirection.Direction.Out); + + // Verify flows and capture arguments + verify(ofWriter, times(1)).writeFlow(NODE_ID, (short) 6, createExternalTestFlow()); + } + + private Flow allowFromChainTestFlow() { + MatchBuilder matchBuilder = new MatchBuilder(); + FlowUtils.addNxNshc1RegMatch(matchBuilder, 0L); + FlowUtils.addNxNsiMatch(matchBuilder, (short) 250); + FlowUtils.addNxNspMatch(matchBuilder, 27L); + Match match = matchBuilder.setInPort(CONNECTOR_2).build(); + + FlowId flowId = FlowIdUtils.newFlowId((short) 4, "chainport", match); + FlowBuilder flowBuilder = new FlowBuilder().setTableId((short) 4).setBarrier(false).setHardTimeout(0) + .setIdleTimeout(0).setId(flowId).setPriority(1200).setMatch(match) + .setInstructions(FlowUtils.gotoTableInstructions((short) 2)); + return flowBuilder.build(); + } + + private List createChainTunnelTestFlow(NetworkElements networkElements) { + Preconditions.checkNotNull(networkElements); + List flows = new ArrayList<>(); + Action segReg = nxLoadRegAction(NxmNxReg0.class, BigInteger.valueOf(1L)); + Action scgReg = nxLoadRegAction(NxmNxReg1.class, BigInteger.valueOf(0xffffff)); + Action bdReg = nxLoadRegAction(NxmNxReg4.class, BigInteger.valueOf(0L)); + Action fdReg = nxLoadRegAction(NxmNxReg5.class, BigInteger.valueOf(0L)); + Action vrfReg = nxLoadRegAction(NxmNxReg6.class, BigInteger.valueOf(0L)); + for (L3Address address : networkElements.getDstEp().getL3Address()) { + Layer3Match l3Match = new Ipv4MatchBuilder().setIpv4Source(new Ipv4Prefix(address.getIpAddress() + .getIpv4Address().getValue() + IP_PREFIX_32)).build(); + MatchBuilder mb = new MatchBuilder().setInPort(CONNECTOR_2).setLayer3Match(l3Match) + .setEthernetMatch(FlowUtils.ethernetMatch(null, null, FlowUtils.IPv4)); + addNxTunIdMatch(mb, 2); + addNxNspMatch(mb, 27L); + addNxNsiMatch(mb, (short) 250); + Match match = mb.build(); + FlowId flowId = FlowIdUtils.newFlowId((short) 2, "chaintunnel", match); + FlowBuilder flowBuilder = base((short) 2).setId(flowId).setPriority(150).setMatch(match).setInstructions( + instructions(applyActionIns(segReg, scgReg, bdReg, fdReg, vrfReg), + gotoTableIns(ctx.getPolicyManager().getTABLEID_DESTINATION_MAPPER()))); + flows.add(flowBuilder.build()); + } + assertTrue(flows.size() == 1); + return flows; + } + + private Flow allowFromChainTunnelTestFlow() { + MatchBuilder matchBuilder = new MatchBuilder().setInPort(CONNECTOR_2); + addNxRegMatch(matchBuilder, RegMatch.of(NxmNxReg1.class, 0xffffffL)); + Match match = matchBuilder.build(); + FlowId flowId = FlowIdUtils.newFlowId((short) 0, "chainport", match); + FlowBuilder flowBuilder = base((short) 0).setId(flowId).setMatch(match) + .setPriority(65000).setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class)))); + return flowBuilder.build(); + } + + private Flow createChainBroadcastTestFlow() { + MatchBuilder matchBuilder = new MatchBuilder().setInPort(CONNECTOR_2); + addNxNsiMatch(matchBuilder, (short) 250); + addNxNspMatch(matchBuilder, 27L); + addNxTunIdMatch(matchBuilder, 0); + Match match = matchBuilder.build(); + FlowId flowId = FlowIdUtils.newFlowId((short) 2, "chainbroadcast", match); + FlowBuilder flowBuilder = base((short) 2).setId(flowId).setPriority(150).setMatch(match) + .setInstructions(instructions(applyActionIns(nxLoadRegAction(NxmNxReg5.class, BigInteger.valueOf(0))), + gotoTableIns(ctx.getPolicyManager().getTABLEID_DESTINATION_MAPPER()))); + return flowBuilder.build(); + } + + private Flow createExternalTestFlow() { + Action loadC1 = nxLoadNshc1RegAction(null); + Action loadC2 = nxLoadNshc2RegAction(2L); + Action loadChainTunVnId = nxLoadTunIdAction(BigInteger.valueOf(2L), false); + Action loadChainTunDest = nxLoadTunIPv4Action(IPV4_2.getValue(), false); + Action outputAction = FlowUtils.createActionResubmit(null, (short) 0); + + MatchBuilder matchBuilder = new MatchBuilder(); + addNxRegMatch(matchBuilder, RegMatch.of(NxmNxReg6.class, 0L)); + addNxTunIdMatch(matchBuilder, 2); + addNxNspMatch(matchBuilder, 27L); + addNxNsiMatch(matchBuilder, (short) 255); + - ncId = new NodeConnectorId("openflow:1"); - Assert.assertNull(ChainActionFlows.returnOfPortFromNodeConnector(ncId)); + Match match = matchBuilder.build(); + FlowId flowId = FlowIdUtils.newFlowId(((short) 6), "chainexternal", match); + FlowBuilder flowBuilder = base((short) 6).setId(flowId).setPriority(1000).setMatch(match) + .setInstructions(instructions(applyActionIns(loadC1, loadC2, loadChainTunDest, loadChainTunVnId, + outputAction))); + return flowBuilder.build(); } } diff --git a/renderers/ofoverlay/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/GroupTableTest.java b/renderers/ofoverlay/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/GroupTableTest.java index 8fe25913b..5f79a61f1 100755 --- a/renderers/ofoverlay/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/GroupTableTest.java +++ b/renderers/ofoverlay/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/GroupTableTest.java @@ -8,195 +8,264 @@ package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.Collections; -import java.util.HashSet; -import java.util.List; - +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.util.concurrent.CheckedFuture; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; +import org.mockito.InOrder; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; -import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; -import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; -import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; import org.opendaylight.groupbasedpolicy.dto.EgKey; -import org.opendaylight.groupbasedpolicy.dto.IndexedTenant; import org.opendaylight.groupbasedpolicy.dto.PolicyInfo; import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext; import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfWriter; import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.endpoint.EndpointManager; -import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action; +import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.mapper.MapperUtilsTest; +import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node.SwitchManager; +import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.ovs.rev140701.Node; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.Buckets; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket; -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; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointBuilder; 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.policy.EndpointGroup; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContextBuilder; 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.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import com.google.common.base.Optional; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; -import com.google.common.util.concurrent.CheckedFuture; - -public class GroupTableTest { +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; - private GroupTable groupTable; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.when; - private OfContext ofContext; +public class GroupTableTest extends MapperUtilsTest { + private final GroupId GROUP_ID = new GroupId(27L); + private GroupTable groupTable; + // DataStore mocks private DataBroker dataBroker; private ReadOnlyTransaction readOnlyTransaction; - private WriteTransaction writeTransaction; - private ReadWriteTransaction readWriteTransaction; - - private CheckedFuture, ReadFailedException> checkedFutureFCNRead; - private CheckedFuture checkedFutureWrite; - private Optional optionalFlowCapableNode; - + private CheckedFuture checkedFutureFCNRead; + private Optional optionalFlowCapableNode; private FlowCapableNode flowCapableNode; - private Group group; - private List groups; - private Buckets buckets; - private Bucket bucket; - private NodeId nodeId; - private OfWriter ofWriter; - private Bucket bucketOther; - private EndpointManager endpointManager; - private Endpoint localEp; - private EgKey egKey; - private OfOverlayContext ofc; - private NodeConnectorId nodeConnectorId; - - @SuppressWarnings("unchecked") + @Before - public void initialisation() throws Exception { - ofContext = mock(OfContext.class); - groupTable = spy(new GroupTable(ofContext)); + public void init() { + ctx = mock(OfContext.class); + endpointManager = mock(EndpointManager.class); + switchManager = mock(SwitchManager.class); + policyInfo = mock(PolicyInfo.class); + groupTable = new GroupTable(ctx); + ofWriter = mock(OfWriter.class); + OrdinalFactory.resetPolicyOrdinalValue(); + } - dataBroker = mock(DataBroker.class); - when(ofContext.getDataBroker()).thenReturn(dataBroker); + @Test + public void sync_noEpNodeId() throws Exception { + initDataStoreMocks(); + EndpointBuilder endpointBuilder = new EndpointBuilder(); + Endpoint endpoint = endpointBuilder.build(); - checkedFutureFCNRead = mock(CheckedFuture.class); - optionalFlowCapableNode = mock(Optional.class); - flowCapableNode = mock(FlowCapableNode.class); + when(ctx.getEndpointManager()).thenReturn(endpointManager); - when(checkedFutureFCNRead.get()).thenReturn(optionalFlowCapableNode); - - when(optionalFlowCapableNode.isPresent()).thenReturn(true); - when(optionalFlowCapableNode.get()).thenReturn(flowCapableNode); + groupTable.sync(endpoint, ofWriter); + verifyZeroInteractions(ofWriter); + } - readOnlyTransaction = mock(ReadOnlyTransaction.class); + @Test + public void sync_nodeIsNotFlowCapable() throws Exception { + initDataStoreMocks(); + EndpointBuilder endpointBuilder = new EndpointBuilder(); + OfOverlayContextBuilder ofOverlayContextBuilder = new OfOverlayContextBuilder(); + ofOverlayContextBuilder.setNodeId(NODE_ID); + endpointBuilder.addAugmentation(OfOverlayContext.class, ofOverlayContextBuilder.build()); + Endpoint endpoint = endpointBuilder.build(); + + when(ctx.getEndpointManager()).thenReturn(endpointManager); + when(ctx.getDataBroker()).thenReturn(dataBroker); + when(endpointManager.getEndpointNodeId(any(Endpoint.class))).thenCallRealMethod(); when(dataBroker.newReadOnlyTransaction()).thenReturn(readOnlyTransaction); - when(readOnlyTransaction.read(any(LogicalDatastoreType.class), - any(InstanceIdentifier.class))).thenReturn(checkedFutureFCNRead); - - writeTransaction = mock(WriteTransaction.class); - when(dataBroker.newWriteOnlyTransaction()).thenReturn(writeTransaction); - checkedFutureWrite = mock(CheckedFuture.class); - when(writeTransaction.submit()).thenReturn(checkedFutureWrite); - - readWriteTransaction = mock(ReadWriteTransaction.class); - when(dataBroker.newReadWriteTransaction()).thenReturn(readWriteTransaction); + when(readOnlyTransaction.read(eq(LogicalDatastoreType.OPERATIONAL), any(InstanceIdentifier.class))) + .thenReturn(checkedFutureFCNRead); + when(checkedFutureFCNRead.get()).thenReturn(optionalFlowCapableNode); + when(optionalFlowCapableNode.isPresent()).thenReturn(true); - group = mock(Group.class); - groups = Collections.singletonList(group); - when(flowCapableNode.getGroup()).thenReturn(groups); + groupTable.sync(endpoint, ofWriter); - buckets = mock(Buckets.class); - when(group.getBuckets()).thenReturn(buckets); - bucket = mock(Bucket.class); - when(bucket.getAction()).thenReturn(Collections.singletonList(mock(Action.class))); - List bucketList = Collections.singletonList(bucket); - when(buckets.getBucket()).thenReturn(bucketList); + verify(optionalFlowCapableNode, times(1)).isPresent(); + verifyZeroInteractions(ofWriter); + } - bucketOther = mock(Bucket.class); - when(bucketOther.getAction()).thenReturn(Collections.singletonList(mock(Action.class))); + @Test + public void sync_nullOrdinals() throws Exception { + initDataStoreMocks(); + EndpointBuilder endpointBuilder = new EndpointBuilder(); + OfOverlayContextBuilder ofOverlayContextBuilder = new OfOverlayContextBuilder(); + ofOverlayContextBuilder.setNodeId(NODE_ID); + endpointBuilder.addAugmentation(OfOverlayContext.class, ofOverlayContextBuilder.build()); + Endpoint endpoint = endpointBuilder.build(); + + when(ctx.getEndpointManager()).thenReturn(endpointManager); + when(ctx.getDataBroker()).thenReturn(dataBroker); + when(endpointManager.getEndpointNodeId(any(Endpoint.class))).thenCallRealMethod(); + when(dataBroker.newReadOnlyTransaction()).thenReturn(readOnlyTransaction); + when(readOnlyTransaction.read(eq(LogicalDatastoreType.OPERATIONAL), any(InstanceIdentifier.class))) + .thenReturn(checkedFutureFCNRead); + when(checkedFutureFCNRead.get()).thenReturn(optionalFlowCapableNode); + when(optionalFlowCapableNode.isPresent()).thenReturn(true); + when(optionalFlowCapableNode.get()).thenReturn(flowCapableNode); + groupTable.sync(endpoint, ofWriter); - nodeId = mock(NodeId.class); - ofWriter = mock(OfWriter.class); - - endpointManager = mock(EndpointManager.class); - when(ofContext.getEndpointManager()).thenReturn(endpointManager); - localEp = mock(Endpoint.class); - when(endpointManager.getEndpointsForNode(nodeId)).thenReturn(Collections.singletonList( - localEp)); - IndexedTenant indexedTenant = mock(IndexedTenant.class); - when(ofContext.getTenant(any(TenantId.class))).thenReturn(indexedTenant); - EndpointGroup epg = mock(EndpointGroup.class); - when(indexedTenant.getEndpointGroup(any(EndpointGroupId.class))).thenReturn(epg); - egKey = mock(EgKey.class); - when(endpointManager.getGroupsForNode(any(NodeId.class))).thenReturn( - new HashSet<>(Collections.singletonList(egKey))); - ofc = mock(OfOverlayContext.class); - when(localEp.getAugmentation(OfOverlayContext.class)).thenReturn(ofc); - nodeConnectorId = mock(NodeConnectorId.class); - when(ofc.getNodeConnectorId()).thenReturn(nodeConnectorId); + verify(optionalFlowCapableNode, times(1)).isPresent(); + verifyZeroInteractions(ofWriter); } - @Ignore @Test - public void updateTest() throws Exception { - //doNothing().when(groupTable).sync(NODE_ID, ofWriter); + public void sync() throws Exception { + initDataStoreMocks(); + EndpointBuilder endpointBuilder = new EndpointBuilder(); + OfOverlayContextBuilder ofOverlayContextBuilder = new OfOverlayContextBuilder(); + ofOverlayContextBuilder.setNodeId(NODE_ID); + endpointBuilder.addAugmentation(OfOverlayContext.class, ofOverlayContextBuilder.build()); + endpointBuilder.setNetworkContainment(NET_DOMAIN_ID); + endpointBuilder.setTenant(buildTenant().getId()); + Endpoint endpoint = endpointBuilder.build(); + + when(ctx.getEndpointManager()).thenReturn(endpointManager); + when(ctx.getCurrentPolicy()).thenReturn(policyInfo); + when(ctx.getDataBroker()).thenReturn(dataBroker); + when(ctx.getTenant(any(TenantId.class))).thenReturn(getTestIndexedTenant()); + when(endpointManager.getEndpointNodeId(any(Endpoint.class))).thenCallRealMethod(); + when(dataBroker.newReadOnlyTransaction()).thenReturn(readOnlyTransaction); + when(readOnlyTransaction.read(eq(LogicalDatastoreType.OPERATIONAL), any(InstanceIdentifier.class))) + .thenReturn(checkedFutureFCNRead); + when(checkedFutureFCNRead.get()).thenReturn(optionalFlowCapableNode); + when(optionalFlowCapableNode.isPresent()).thenReturn(true); + when(optionalFlowCapableNode.get()).thenReturn(flowCapableNode); - //groupTable.sync(NODE_ID, ofWriter); - //verify(groupTable).sync(any(NodeId.class), any(OfWriter.class)); - } + groupTable.sync(endpoint, ofWriter); - @Ignore - @Test - public void updateTestNoFCN() throws Exception { - doReturn(null).when(groupTable).getFCNodeFromDatastore(any(NodeId.class)); - - //groupTable.sync(NODE_ID, ofWriter); - verify(ofWriter, never()).writeBucket(any(NodeId.class), any(GroupId.class), any(Bucket.class));; - verify(ofWriter, never()).writeFlow(any(NodeId.class), any(Short.class), any(Flow.class)); - verify(ofWriter, never()).writeGroup(any(NodeId.class), any(GroupId.class), any(GroupTypes.class), - any(String.class), any(String.class), any(Boolean.class)); + verify(optionalFlowCapableNode, times(1)).isPresent(); + verify(ofWriter, times(1)).writeGroup(NODE_ID, new GroupId(0L)); } - @Ignore @Test - public void syncTestNoGroup() throws Exception { - when(ofWriter.groupExists(any(NodeId.class), any(Long.class))).thenReturn(false); - when(endpointManager.getGroupsForNode(any(NodeId.class))).thenReturn( - Collections.emptySet()); - - //groupTable.sync(NODE_ID, ofWriter); - verify(ofWriter).writeGroup(any(NodeId.class), any(GroupId.class)); + public void syncGroups_groupsForNode() throws Exception { + // Define NodeIds + NodeId nodeWithoutTunnel = new NodeId("nodeIdWithoutTunnel"); + NodeId nodeIdIpV6 = new NodeId("nodeIdIpV6"); + NodeId nodeIdIpV4 = new NodeId("nodeIdIpV4"); + Endpoint endpoint = buildEndpoint(IPV4_0, MAC_0, new NodeConnectorId(OPENFLOW + CONNECTOR_0.getValue())).build(); + + when(ctx.getTenant(any(TenantId.class))).thenReturn(getTestIndexedTenant()); + when(ctx.getEndpointManager()).thenReturn(endpointManager); + when(ctx.getCurrentPolicy()).thenReturn(policyInfo); + + OrdinalFactory.EndpointFwdCtxOrdinals ordinals = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, endpoint); + Preconditions.checkNotNull(ordinals); + + // EgKeys + Set egKeys = new HashSet<>(); + egKeys.add(new EgKey(buildTenant().getId(), endpoint.getEndpointGroup())); + // Nodes + Set nodeIds = new HashSet<>(); + nodeIds.add(NODE_ID); + nodeIds.add(nodeWithoutTunnel); + nodeIds.add(nodeIdIpV6); + nodeIds.add(nodeIdIpV4); + // Endpoints + Collection endpoints = new HashSet<>(); + endpoints.add(buildEndpoint(IPV4_1, MAC_1, CONNECTOR_1).build()); + endpoints.add(buildEndpoint(IPV4_2, MAC_2, CONNECTOR_2).build()); + + when(ctx.getSwitchManager()).thenReturn(switchManager); + when(endpointManager.getGroupsForNode(NODE_ID)).thenReturn(egKeys); + when(endpointManager.getNodesForGroup(any(EgKey.class))).thenReturn(nodeIds); + when(endpointManager.getEndpointsForNode(any(NodeId.class))).thenReturn(endpoints); + when(switchManager.getTunnelIP(nodeIdIpV6, TunnelTypeVxlan.class)).thenReturn(new IpAddress(IPV6_1)); + when(switchManager.getTunnelIP(nodeIdIpV4, TunnelTypeVxlan.class)).thenReturn(new IpAddress(IPV4_1)); + when(switchManager.getTunnelPort(NODE_ID, TunnelTypeVxlan.class)).thenReturn(CONNECTOR_1); + when(policyInfo.getPeers(any(EgKey.class))).thenReturn(egKeys); + + groupTable.syncGroups(NODE_ID, ordinals, endpoint, GROUP_ID, ofWriter); + + // Verify method order + InOrder order = inOrder(endpointManager, policyInfo, switchManager, ofWriter); + order.verify(endpointManager, times(1)).getGroupsForNode(NODE_ID); + order.verify(endpointManager, times(1)).getNodesForGroup(any(EgKey.class)); + order.verify(policyInfo, times(1)).getPeers(any(EgKey.class)); + order.verify(endpointManager, times(1)).getNodesForGroup(any(EgKey.class)); + order.verify(switchManager, times(1)).getTunnelIP(nodeWithoutTunnel, TunnelTypeVxlan.class); + order.verify(switchManager, times(1)).getTunnelPort(NODE_ID, TunnelTypeVxlan.class); + order.verify(switchManager, times(1)).getTunnelIP(any(NodeId.class), eq(TunnelTypeVxlan.class)); + order.verify(switchManager, times(1)).getTunnelPort(NODE_ID, TunnelTypeVxlan.class); + order.verify(switchManager, times(1)).getTunnelIP(any(NodeId.class), eq(TunnelTypeVxlan.class)); + order.verify(switchManager, times(1)).getTunnelPort(NODE_ID, TunnelTypeVxlan.class); + order.verify(ofWriter, atLeastOnce()).writeBucket(any(NodeId.class), any(GroupId.class), any(Bucket.class)); } - @Ignore @Test - public void syncTestGroupExists() throws Exception { - when(ofWriter.groupExists(any(NodeId.class), any(Long.class))).thenReturn(true); - when(endpointManager.getGroupsForNode(any(NodeId.class))).thenReturn( - Collections.emptySet()); + public void syncGroups_externalEpsWithoutLocation() throws Exception { + EndpointBuilder endpointBuilder = buildEndpoint(IPV4_0, MAC_0, new NodeConnectorId(OPENFLOW + CONNECTOR_0.getValue())); + endpointBuilder.setNetworkContainment(L2FD_ID); + Endpoint endpoint = endpointBuilder.build(); + + when(ctx.getTenant(any(TenantId.class))).thenReturn(getTestIndexedTenant()); + when(ctx.getEndpointManager()).thenReturn(endpointManager); + when(ctx.getCurrentPolicy()).thenReturn(policyInfo); + + OrdinalFactory.EndpointFwdCtxOrdinals ordinals = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, endpoint); + Preconditions.checkNotNull(ordinals); + // EgKeys + Set egKeys = new HashSet<>(); + egKeys.add(new EgKey(buildTenant().getId(), endpoint.getEndpointGroup())); + // NodeConnectorIds + Set externalPorts = new HashSet<>(); + externalPorts.add(new NodeConnectorId(OPENFLOW + CONNECTOR_1.getValue())); // Correct format + externalPorts.add(CONNECTOR_2); // NumberFormatException + // Endpoints + Collection endpoints = new HashSet<>(); + EndpointBuilder noLocEndpointBuilder = buildEndpoint(IPV4_1, MAC_1, CONNECTOR_1); + noLocEndpointBuilder.setNetworkContainment(L2FD_ID); + endpoints.add(noLocEndpointBuilder.build()); + + when(ctx.getSwitchManager()).thenReturn(switchManager); + when(endpointManager.getGroupsForNode(NODE_ID)).thenReturn(egKeys); + when(endpointManager.getExtEpsNoLocForGroup(any(EgKey.class))).thenReturn(endpoints); + when(switchManager.getExternalPorts(NODE_ID)).thenReturn(externalPorts); + + groupTable.syncGroups(NODE_ID, ordinals, endpoint, GROUP_ID, ofWriter); + + // Verify method order + InOrder order = inOrder(endpointManager, policyInfo, switchManager, ofWriter); + order.verify(endpointManager, times(1)).getGroupsForNode(NODE_ID); + order.verify(endpointManager, times(1)).getExtEpsNoLocForGroup(any(EgKey.class)); + order.verify(switchManager, times(1)).getExternalPorts(any(NodeId.class)); + order.verify(ofWriter, times(1)).writeBucket(any(NodeId.class), any(GroupId.class), any(Bucket.class)); + } - //groupTable.sync(NODE_ID, ofWriter); - verify(ofWriter, never()).writeGroup(any(NodeId.class), any(GroupId.class)); + private void initDataStoreMocks() { + dataBroker = mock(DataBroker.class); + readOnlyTransaction = mock(ReadOnlyTransaction.class); + checkedFutureFCNRead = mock(CheckedFuture.class); + optionalFlowCapableNode = mock(Optional.class); + flowCapableNode = mock(FlowCapableNode.class); } } -- 2.36.6