/* * Copyright 2014-present Open Networking Laboratory * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.onosproject.provider.of.packet.impl; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.onlab.packet.ARP; import org.onlab.packet.Ethernet; import org.onosproject.net.Device; import org.onosproject.net.DeviceId; import org.onosproject.net.PortNumber; import org.onosproject.net.flow.DefaultTrafficTreatment; import org.onosproject.net.flow.TrafficTreatment; import org.onosproject.net.flow.instructions.Instruction; import org.onosproject.net.flow.instructions.Instructions; import org.onosproject.net.packet.DefaultOutboundPacket; import org.onosproject.net.packet.OutboundPacket; import org.onosproject.net.packet.PacketContext; import org.onosproject.net.packet.PacketProvider; import org.onosproject.net.packet.PacketProviderRegistry; import org.onosproject.net.packet.PacketProviderService; import org.onosproject.net.provider.ProviderId; import org.onosproject.openflow.controller.DefaultOpenFlowPacketContext; import org.onosproject.openflow.controller.Dpid; import org.onosproject.openflow.controller.OpenFlowController; import org.onosproject.openflow.controller.OpenFlowEventListener; import org.onosproject.openflow.controller.OpenFlowMessageListener; import org.onosproject.openflow.controller.OpenFlowPacketContext; import org.onosproject.openflow.controller.OpenFlowSwitch; import org.onosproject.openflow.controller.OpenFlowSwitchListener; import org.onosproject.openflow.controller.PacketListener; import org.onosproject.openflow.controller.RoleState; import org.projectfloodlight.openflow.protocol.OFFactory; import org.projectfloodlight.openflow.protocol.OFMessage; import org.projectfloodlight.openflow.protocol.OFMeterFeatures; import org.projectfloodlight.openflow.protocol.OFPacketIn; import org.projectfloodlight.openflow.protocol.OFPacketInReason; import org.projectfloodlight.openflow.protocol.OFPortDesc; import org.projectfloodlight.openflow.protocol.ver10.OFFactoryVer10; import org.projectfloodlight.openflow.types.MacAddress; import org.projectfloodlight.openflow.types.OFBufferId; import org.projectfloodlight.openflow.types.OFPort; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.concurrent.CompletableFuture; import static org.junit.Assert.*; public class OpenFlowPacketProviderTest { private static final int PN1 = 100; private static final int PN2 = 200; private static final int PN3 = 300; private static final short VLANID = (short) 100; private static final DeviceId DID = DeviceId.deviceId("of:1"); private static final DeviceId DID_MISSING = DeviceId.deviceId("of:2"); private static final DeviceId DID_WRONG = DeviceId.deviceId("test:1"); private static final PortNumber P1 = PortNumber.portNumber(PN1); private static final PortNumber P2 = PortNumber.portNumber(PN2); private static final PortNumber P3 = PortNumber.portNumber(PN3); private static final Instruction INST1 = Instructions.createOutput(P1); private static final Instruction INST2 = Instructions.createOutput(P2); private static final Instruction INST3 = Instructions.createOutput(P3); private static final OFPortDesc PD1 = portDesc(PN1); private static final OFPortDesc PD2 = portDesc(PN2); private static final List<OFPortDesc> PLIST = Lists.newArrayList(PD1, PD2); private static final TrafficTreatment TR = treatment(INST1, INST2); private static final TrafficTreatment TR_MISSING = treatment(INST1, INST3); private static final byte[] ANY = new byte[] {0, 0, 0, 0}; private final OpenFlowPacketProvider provider = new OpenFlowPacketProvider(); private final TestPacketRegistry registry = new TestPacketRegistry(); private final TestController controller = new TestController(); private final TestOpenFlowSwitch sw = new TestOpenFlowSwitch(); @Before public void startUp() { provider.providerRegistry = registry; provider.controller = controller; provider.activate(); assertNotNull("listener should be registered", registry.listener); } @After public void teardown() { provider.deactivate(); assertNull("listeners shouldn't be registered", registry.listener); provider.controller = null; provider.providerRegistry = null; } @Test(expected = IllegalArgumentException.class) public void wrongScheme() { sw.setRole(RoleState.MASTER); OutboundPacket schemeFailPkt = outPacket(DID_WRONG, TR, null); provider.emit(schemeFailPkt); assertEquals("message sent incorrectly", 0, sw.sent.size()); } @Test public void emit() { MacAddress mac1 = MacAddress.of("00:00:00:11:00:01"); MacAddress mac2 = MacAddress.of("00:00:00:22:00:02"); ARP arp = new ARP(); arp.setSenderProtocolAddress(ANY) .setSenderHardwareAddress(mac1.getBytes()) .setTargetHardwareAddress(mac2.getBytes()) .setTargetProtocolAddress(ANY) .setHardwareType((short) 0) .setProtocolType((short) 0) .setHardwareAddressLength((byte) 6) .setProtocolAddressLength((byte) 4) .setOpCode((byte) 0); Ethernet eth = new Ethernet(); eth.setVlanID(VLANID) .setEtherType(Ethernet.TYPE_ARP) .setSourceMACAddress("00:00:00:11:00:01") .setDestinationMACAddress("00:00:00:22:00:02") .setPayload(arp); //the should-be working setup. OutboundPacket passPkt = outPacket(DID, TR, eth); sw.setRole(RoleState.MASTER); provider.emit(passPkt); assertEquals("invalid switch", sw, controller.current); assertEquals("message not sent", PLIST.size(), sw.sent.size()); sw.sent.clear(); //wrong Role //sw.setRole(RoleState.SLAVE); //provider.emit(passPkt); //assertEquals("invalid switch", sw, controller.current); //assertEquals("message sent incorrectly", 0, sw.sent.size()); //sw.setRole(RoleState.MASTER); //missing switch OutboundPacket swFailPkt = outPacket(DID_MISSING, TR, eth); provider.emit(swFailPkt); assertNull("invalid switch", controller.current); assertEquals("message sent incorrectly", 0, sw.sent.size()); //to missing port //OutboundPacket portFailPkt = outPacket(DID, TR_MISSING, eth); //provider.emit(portFailPkt); //assertEquals("extra message sent", 1, sw.sent.size()); } @Test public void handlePacket() { OFPacketIn pkt = sw.factory().buildPacketIn() .setBufferId(OFBufferId.NO_BUFFER) .setInPort(OFPort.NO_MASK) .setReason(OFPacketInReason.INVALID_TTL) .build(); controller.processPacket(null, pkt); assertNotNull("message unprocessed", registry.ctx); } private static OFPortDesc portDesc(int port) { OFPortDesc.Builder builder = OFFactoryVer10.INSTANCE.buildPortDesc(); builder.setPortNo(OFPort.of(port)); return builder.build(); } private static TrafficTreatment treatment(Instruction ... insts) { TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder(); for (Instruction i : insts) { builder.add(i); } return builder.build(); } private static OutboundPacket outPacket( DeviceId d, TrafficTreatment t, Ethernet e) { ByteBuffer buf = null; if (e != null) { buf = ByteBuffer.wrap(e.serialize()); } return new DefaultOutboundPacket(d, t, buf); } private class TestPacketRegistry implements PacketProviderRegistry { PacketProvider listener = null; PacketContext ctx = null; @Override public PacketProviderService register(PacketProvider provider) { listener = provider; return new TestPacketProviderService(); } @Override public void unregister(PacketProvider provider) { listener = null; } @Override public Set<ProviderId> getProviders() { return Sets.newHashSet(listener.id()); } private class TestPacketProviderService implements PacketProviderService { @Override public PacketProvider provider() { return null; } @Override public void processPacket(PacketContext context) { ctx = context; } } } private class TestController implements OpenFlowController { PacketListener pktListener; OpenFlowSwitch current; @Override public Iterable<OpenFlowSwitch> getSwitches() { return null; } @Override public Iterable<OpenFlowSwitch> getMasterSwitches() { return null; } @Override public Iterable<OpenFlowSwitch> getEqualSwitches() { return null; } @Override public OpenFlowSwitch getSwitch(Dpid dpid) { if (dpid.equals(Dpid.dpid(DID.uri()))) { current = sw; } else { current = null; } return current; } @Override public OpenFlowSwitch getMasterSwitch(Dpid dpid) { return null; } @Override public OpenFlowSwitch getEqualSwitch(Dpid dpid) { return null; } @Override public void addListener(OpenFlowSwitchListener listener) { } @Override public void removeListener(OpenFlowSwitchListener listener) { } @Override public void addMessageListener(OpenFlowMessageListener listener) { } @Override public void removeMessageListener(OpenFlowMessageListener listener) { } @Override public void addPacketListener(int priority, PacketListener listener) { pktListener = listener; } @Override public void removePacketListener(PacketListener listener) { } @Override public void addEventListener(OpenFlowEventListener listener) { } @Override public void removeEventListener(OpenFlowEventListener listener) { } @Override public void write(Dpid dpid, OFMessage msg) { } @Override public CompletableFuture<OFMessage> writeResponse(Dpid dpid, OFMessage msg) { return null; } @Override public void processPacket(Dpid dpid, OFMessage msg) { OpenFlowPacketContext pktCtx = DefaultOpenFlowPacketContext. packetContextFromPacketIn(sw, (OFPacketIn) msg); pktListener.handlePacket(pktCtx); } @Override public void setRole(Dpid dpid, RoleState role) { } } private class TestOpenFlowSwitch implements OpenFlowSwitch { RoleState state; List<OFMessage> sent = new ArrayList<OFMessage>(); OFFactory factory = OFFactoryVer10.INSTANCE; @Override public void sendMsg(OFMessage msg) { sent.add(msg); } @Override public void sendMsg(List<OFMessage> msgs) { } @Override public void handleMessage(OFMessage fromSwitch) { } @Override public void setRole(RoleState role) { state = role; } @Override public RoleState getRole() { return state; } @Override public List<OFPortDesc> getPorts() { return PLIST; } @Override public OFMeterFeatures getMeterFeatures() { return null; } @Override public OFFactory factory() { return factory; } @Override public String getStringId() { return null; } @Override public long getId() { return 0; } @Override public String manufacturerDescription() { return null; } @Override public String datapathDescription() { return null; } @Override public String hardwareDescription() { return null; } @Override public String softwareDescription() { return null; } @Override public String serialNumber() { return null; } @Override public boolean isConnected() { return true; } @Override public void disconnectSwitch() { } @Override public void returnRoleReply(RoleState requested, RoleState reponse) { } @Override public Device.Type deviceType() { return Device.Type.SWITCH; } @Override public String channelId() { return "1.2.3.4:1"; } } }