/* * Copyright (c) 2015 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, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow; 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.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.rev130715.IpAddress; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.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.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; 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.nxLoadTunGpeNpAction; 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; import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxPopNshAction; public class ChainActionFlowsTest extends MapperUtilsTest { @Captor private final ArgumentCaptor<NodeId> nodeIdCaptor = ArgumentCaptor.forClass(NodeId.class); private final ArgumentCaptor<Short> tableIdCaptor = ArgumentCaptor.forClass(Short.class); private final ArgumentCaptor<Flow> flowCaptor = ArgumentCaptor.forClass(Flow.class); @Before public void init() { ctx = mock(OfContext.class); endpointManager = mock(EndpointManager.class); switchManager = mock(SwitchManager.class); policyManager = mock(PolicyManager.class); policyInfo = mock(PolicyInfo.class); ofWriter = mock(OfWriter.class); } @Test 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.setNshMetaC1(Long.valueOf(0L)); 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<Short> tableIds = tableIdCaptor.getAllValues(); Short expectedTableIds[] = {4, 2, 0, 2}; assertArrayEquals(expectedTableIds, tableIds.toArray()); // Verify flows List<Flow> 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 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.setNshMetaC1(Long.valueOf(0L)); 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(netElements)); } 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<Flow> createChainTunnelTestFlow(NetworkElements networkElements) { Preconditions.checkNotNull(networkElements); List<Flow> 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(3L)); Action fdReg = nxLoadRegAction(NxmNxReg5.class, BigInteger.valueOf(4L)); Action vrfReg = nxLoadRegAction(NxmNxReg6.class, BigInteger.valueOf(5L)); 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, networkElements.getSrcEpOrdinals().getTunnelId()); 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(nxPopNshAction(), 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, 4); 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(4))), gotoTableIns(ctx.getPolicyManager().getTABLEID_DESTINATION_MAPPER()))); return flowBuilder.build(); } private Flow createExternalTestFlow(NetworkElements networkElements) { int matchTunnelId = networkElements.getSrcEpOrdinals().getTunnelId(); long setTunnelId = networkElements.getDstEpOrdinals().getTunnelId(); final short TUN_GPE_NP_NSH = 0x4; Action loadC1 = nxLoadNshc1RegAction(Long.valueOf(0)); Action loadC2 = nxLoadNshc2RegAction(setTunnelId); Action loadChainTunVnId = nxLoadTunIdAction(BigInteger.valueOf(setTunnelId), false); Action loadChainTunDest = nxLoadTunIPv4Action(IPV4_2.getValue(), false); Action loadTunGpeNp = nxLoadTunGpeNpAction(BigInteger.valueOf(TUN_GPE_NP_NSH), false); Action outputAction = FlowUtils.createActionResubmit(null, (short) 0); MatchBuilder matchBuilder = new MatchBuilder(); addNxRegMatch(matchBuilder, RegMatch.of(NxmNxReg6.class, 5L)); addNxTunIdMatch(matchBuilder, matchTunnelId); addNxNspMatch(matchBuilder, 27L); addNxNsiMatch(matchBuilder, (short) 255); 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, loadTunGpeNp, outputAction))); return flowBuilder.build(); } }