/* * 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.arp; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeNoException; import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.net.InetAddress; import java.util.Collections; import java.util.concurrent.Future; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.Matchers; import org.opendaylight.controller.liblldp.EtherTypes; import org.opendaylight.controller.liblldp.Ethernet; import org.opendaylight.controller.liblldp.HexEncode; 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.WriteTransaction; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.test.OfOverlayDataBrokerTest; import org.opendaylight.groupbasedpolicy.util.IidFactory; 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.IpPrefix; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2BridgeDomainId; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2ContextId; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L3ContextId; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.NetworkDomainId; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubnetId; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.Endpoints; 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.EndpointL3; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Builder; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Key; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContextBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayL3Context; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayL3ContextBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayNodeConfig; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayNodeConfigBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.nodes.node.ExternalInterfacesBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.Tenants; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.TenantsBuilder; 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.groupbasedpolicy.policy.rev140421.tenants.TenantKey; 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.ForwardingContextBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L2BridgeDomain; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L2BridgeDomainBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L2BridgeDomainKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.SubnetBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodesBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatch; import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService; import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived; import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceivedBuilder; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.common.RpcResult; import com.google.common.base.Optional; import com.google.common.util.concurrent.CheckedFuture; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.UncheckedExecutionException; public class ArpTaskerTest extends OfOverlayDataBrokerTest { private ArpTasker arpTasker; private DataBroker broker; private PacketProcessingService packetService; private SalFlowService flowService; @Before public void init() { packetService = mock(PacketProcessingService.class); flowService = mock(SalFlowService.class); } @SuppressWarnings("unchecked") @Test public void addMacForL3EpAndCreateEp_onPacketReceivedTest() throws Exception { IpAddress ipAddr = new IpAddress(new Ipv4Address("192.168.0.1")); L3ContextId l3conId = new L3ContextId("l3context"); EndpointL3Key key = new EndpointL3Key(ipAddr, l3conId); EndpointL3Builder epL3 = new EndpointL3Builder(); // node conector NodeConnectorId connectorId = new NodeConnectorId("nodeConnector"); MacAddress macAddr = new MacAddress("00:00:00:00:00:01"); FlowCapableNodeConnectorBuilder fcnConnector = new FlowCapableNodeConnectorBuilder().setHardwareAddress(macAddr); NodeConnectorBuilder connector = new NodeConnectorBuilder().setKey(new NodeConnectorKey(connectorId)) .addAugmentation(FlowCapableNodeConnector.class, fcnConnector.build()); // node NodeId nodeId = new NodeId("node"); ExternalInterfacesBuilder extIface = new ExternalInterfacesBuilder().setNodeConnectorId(connectorId); OfOverlayNodeConfigBuilder ofOverNodeCfg = new OfOverlayNodeConfigBuilder().setExternalInterfaces(Collections.singletonList(extIface.build())); NodeBuilder node = new NodeBuilder().addAugmentation(OfOverlayNodeConfig.class, ofOverNodeCfg.build()) .setKey(new NodeKey(nodeId)) .setId(nodeId) .setNodeConnector(Collections.singletonList(connector.build())); // subnet NetworkDomainId domainId = new NetworkDomainId("domainId"); TenantId tenantId = new TenantId("tenant"); L2ContextId l2conId = new L2ContextId("l2context"); SubnetBuilder subnet = new SubnetBuilder().setId(new SubnetId(domainId)) .setIpPrefix(new IpPrefix(new Ipv4Prefix(ipAddr.getIpv4Address().getValue() + "/24"))) .setParent(l2conId); TenantsBuilder tenants = new TenantsBuilder().setTenant(Collections.singletonList(new TenantBuilder().setId(tenantId) .setForwardingContext( new ForwardingContextBuilder().setSubnet(Collections.singletonList(subnet.build())).build()) .build())); // test without key ReadOnlyTransaction rtx = mock(ReadOnlyTransaction.class); broker = mock(DataBroker.class); arpTasker = new ArpTasker(broker, packetService, flowService); epL3.setKey(new EndpointL3Key(mock(IpAddress.class), null)); arpTasker.addMacForL3EpAndCreateEp(epL3.build()); verify(broker, never()).newReadOnlyTransaction(); // test without node with external interface epL3.setKey(key); when(broker.newReadOnlyTransaction()).thenReturn(rtx); CheckedFuture<Optional<DataObject>, ReadFailedException> future = Futures.immediateCheckedFuture(Optional.<DataObject>absent()); when(rtx.read(Matchers.eq(LogicalDatastoreType.CONFIGURATION), any(InstanceIdentifier.class))) .thenReturn(future); arpTasker.addMacForL3EpAndCreateEp(epL3.build()); verify(broker).newReadOnlyTransaction(); verify(rtx).close(); // test correct broker = getDataBroker(); arpTasker = new ArpTasker(broker, packetService, flowService); WriteTransaction wtx = broker.newWriteOnlyTransaction(); wtx.put(LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.builder(Nodes.class).build(), new NodesBuilder().setNode(Collections.singletonList(node.build())).build(), true); wtx.put(LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.builder(Nodes.class) .child(Node.class, node.getKey()) .child(NodeConnector.class, new NodeConnectorKey(connectorId)) .build(), connector.build(), true); // ignoring a Windows-specific bug try { wtx.put(LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.builder(Tenants.class).build(), tenants.build(), true); } catch (UncheckedExecutionException e) { assumeNoException(e); } wtx.submit().get(); Future<RpcResult<AddFlowOutput>> flowFuture = mock(Future.class); when(flowService.addFlow(any(AddFlowInput.class))).thenReturn(flowFuture); epL3.setNetworkContainment(domainId).setTenant(tenantId); arpTasker.addMacForL3EpAndCreateEp(epL3.build()); ArgumentCaptor<AddFlowInput> argument = ArgumentCaptor.forClass(AddFlowInput.class); verify(flowService).addFlow(argument.capture()); AddFlowInput result = argument.getValue(); assertEquals(EtherTypes.ARP.intValue(), result.getMatch() .getEthernetMatch() .getEthernetType() .getType() .getValue() .intValue()); ArpMatch match = (ArpMatch)result.getMatch().getLayer3Match(); assertEquals(ArpOperation.REPLY.intValue(), match.getArpOp().intValue()); assertEquals("192.168.0.254/32", match.getArpTargetTransportAddress().getValue()); assertEquals("192.168.0.1/32", match.getArpSourceTransportAddress().getValue()); assertEquals(connectorId, result.getMatch().getInPort()); assertEquals(new NodeRef( InstanceIdentifier.builder(Nodes.class).child(Node.class, node.getKey()).build()), result.getNode()); // onPacketReceived Arp arp = new Arp(); byte[] sha = HexEncode.bytesFromHexString("00:00:00:00:00:01"); byte[] spa = InetAddress.getByName("192.168.0.1").getAddress(); byte[] tha = HexEncode.bytesFromHexString("00:00:00:00:00:02"); byte[] tpa = InetAddress.getByName("192.168.0.2").getAddress(); int htype = 1; int ptype = EtherTypes.IPv4.intValue(); short hlen = 6; short plen = 4; int operation = ArpOperation.REPLY.intValue(); arp.setSenderHardwareAddress(sha); arp.setSenderProtocolAddress(spa); arp.setTargetHardwareAddress(tha); arp.setTargetProtocolAddress(tpa); arp.setOperation(operation); arp.setHardwareLength(hlen); arp.setProtocolLength(plen); arp.setHardwareType(htype); arp.setProtocolType(ptype); Ethernet arpFrame = new Ethernet().setSourceMACAddress(sha) .setDestinationMACAddress(tha) .setEtherType(EtherTypes.ARP.shortValue()); arpFrame.setPayload(arp); L2BridgeDomainId l2domainId = new L2BridgeDomainId(l2conId); L2BridgeDomainBuilder l2domain = new L2BridgeDomainBuilder().setId(l2domainId); InstanceIdentifier<NodeConnector> ncIid = InstanceIdentifier.builder(Nodes.class) .child(Node.class, new NodeKey(new NodeId("node"))) .child(NodeConnector.class, new NodeConnectorKey(new NodeConnectorId("connector"))) .build(); PacketReceived packet = new PacketReceivedBuilder().setPayload(arpFrame.serialize()) .setIngress(new NodeConnectorRef(ncIid)) .build(); wtx = broker.newWriteOnlyTransaction(); OfOverlayL3Context augment = new OfOverlayL3ContextBuilder().build(); epL3.addAugmentation(OfOverlayL3Context.class, augment); InstanceIdentifier<EndpointL3> epL3Iid = InstanceIdentifier.builder(Endpoints.class).child(EndpointL3.class, key).build(); wtx.put(LogicalDatastoreType.OPERATIONAL, epL3Iid, epL3.build(), true); InstanceIdentifier<L2BridgeDomain> l2domainIid = InstanceIdentifier.builder(Tenants.class) .child(Tenant.class, new TenantKey(tenantId)) .child(ForwardingContext.class) .child(L2BridgeDomain.class, new L2BridgeDomainKey(l2domainId)) .build(); wtx.put(LogicalDatastoreType.OPERATIONAL, l2domainIid, l2domain.build() ,true); wtx.submit(); arpTasker.onPacketReceived(packet); rtx = broker.newReadOnlyTransaction(); Optional<EndpointL3> optional = rtx.read(LogicalDatastoreType.OPERATIONAL, epL3Iid).get(); assertTrue(optional.isPresent()); EndpointL3 epl3 = optional.get(); assertArrayEquals(sha, HexEncode.bytesFromHexString(epl3.getMacAddress().getValue())); assertEquals(l2domain.getId(), epl3.getL2Context()); Optional<Endpoint> optionalEp = rtx.read(LogicalDatastoreType.OPERATIONAL, IidFactory.endpointIid(l2domainId, new MacAddress("00:00:00:00:00:01"))).get(); assertTrue(optionalEp.isPresent()); assertEquals(new OfOverlayContextBuilder(augment).build(), optionalEp.get().getAugmentation(OfOverlayContext.class)); } }