diff options
author | Ashlee Young <ashlee@onosfw.com> | 2015-10-23 08:31:31 -0700 |
---|---|---|
committer | Ashlee Young <ashlee@onosfw.com> | 2015-10-23 08:31:31 -0700 |
commit | e52e67767076b29cb01939aa7bdd8fee9d205cc1 (patch) | |
tree | b8c2d28231bccc2a280fea429a9af7297c62f58f /framework/src | |
parent | a912c5ce9968da5936a695064f22083898e7b93d (diff) |
Update ONOS src to commit id 69b36d5d11e81e28e56b46ba44e4b8cd701c5867
Change-Id: I9c13045711dbf9c0181106b66a6bf22c72bcf330
Signed-off-by: Ashlee Young <ashlee@onosfw.com>
Diffstat (limited to 'framework/src')
106 files changed, 2617 insertions, 1097 deletions
diff --git a/framework/src/onos/apps/aaa/src/main/java/org/onosproject/aaa/AAA.java b/framework/src/onos/apps/aaa/src/main/java/org/onosproject/aaa/AAA.java index 479ec7ed..72a5b122 100644 --- a/framework/src/onos/apps/aaa/src/main/java/org/onosproject/aaa/AAA.java +++ b/framework/src/onos/apps/aaa/src/main/java/org/onosproject/aaa/AAA.java @@ -15,10 +15,13 @@ */ package org.onosproject.aaa; +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; import java.net.InetAddress; import java.nio.ByteBuffer; -import java.util.Optional; -import java.util.Set; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import org.apache.felix.scr.annotations.Activate; import org.apache.felix.scr.annotations.Component; @@ -30,20 +33,13 @@ import org.onlab.packet.EAP; import org.onlab.packet.EAPOL; import org.onlab.packet.EthType; import org.onlab.packet.Ethernet; -import org.onlab.packet.IPv4; -import org.onlab.packet.Ip4Address; -import org.onlab.packet.IpAddress; import org.onlab.packet.MacAddress; import org.onlab.packet.RADIUS; import org.onlab.packet.RADIUSAttribute; -import org.onlab.packet.TpPort; -import org.onlab.packet.UDP; -import org.onlab.packet.VlanId; import org.onosproject.core.ApplicationId; import org.onosproject.core.CoreService; import org.onosproject.net.ConnectPoint; import org.onosproject.net.DeviceId; -import org.onosproject.net.Host; import org.onosproject.net.PortNumber; import org.onosproject.net.config.ConfigFactory; import org.onosproject.net.config.NetworkConfigEvent; @@ -53,7 +49,6 @@ import org.onosproject.net.flow.DefaultTrafficSelector; import org.onosproject.net.flow.DefaultTrafficTreatment; import org.onosproject.net.flow.TrafficSelector; import org.onosproject.net.flow.TrafficTreatment; -import org.onosproject.net.host.HostService; import org.onosproject.net.packet.DefaultOutboundPacket; import org.onosproject.net.packet.InboundPacket; import org.onosproject.net.packet.OutboundPacket; @@ -63,6 +58,8 @@ import org.onosproject.net.packet.PacketService; import org.onosproject.xosintegration.VoltTenantService; import org.slf4j.Logger; +import com.google.common.util.concurrent.ThreadFactoryBuilder; + import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY; import static org.onosproject.net.packet.PacketPriority.CONTROL; import static org.slf4j.LoggerFactory.getLogger; @@ -85,10 +82,6 @@ public class AAA { @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected PacketService packetService; - // end host information - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) - protected HostService hostService; - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected VoltTenantService voltTenantService; @@ -121,6 +114,12 @@ public class AAA { // our unique identifier private ApplicationId appId; + // Socket used for UDP communications with RADIUS server + private DatagramSocket radiusSocket; + + // Executor for RADIUS communication thread + private ExecutorService executor; + // Configuration properties factory private final ConfigFactory factory = new ConfigFactory<ApplicationId, AAAConfig>(APP_SUBJECT_FACTORY, @@ -184,7 +183,16 @@ public class AAA { StateMachine.initializeMaps(); - hostService.startMonitoringIp(IpAddress.valueOf(radiusIpAddress)); + try { + radiusSocket = new DatagramSocket(radiusServerPort); + } catch (Exception ex) { + log.error("Can't open RADIUS socket", ex); + } + + executor = Executors.newSingleThreadExecutor( + new ThreadFactoryBuilder() + .setNameFormat("AAA-radius-%d").build()); + executor.execute(radiusListener); } @Deactivate @@ -195,6 +203,24 @@ public class AAA { packetService.removeProcessor(processor); processor = null; StateMachine.destroyMaps(); + radiusSocket.close(); + executor.shutdownNow(); + } + + protected void sendRADIUSPacket(RADIUS radiusPacket) { + + try { + final byte[] data = radiusPacket.serialize(); + final DatagramSocket socket = radiusSocket; + + DatagramPacket packet = + new DatagramPacket(data, data.length, + radiusIpAddress, radiusServerPort); + + socket.send(packet); + } catch (IOException e) { + log.info("Cannot send packet to RADIUS server", e); + } } /** @@ -205,14 +231,6 @@ public class AAA { selector.matchEthType(EthType.EtherType.EAPOL.ethType().toShort()); packetService.requestPackets(selector.build(), CONTROL, appId); - - TrafficSelector radSelector = DefaultTrafficSelector.builder() - .matchEthType(EthType.EtherType.IPV4.ethType().toShort()) - .matchIPProtocol(IPv4.PROTOCOL_UDP) - .matchUdpDst(TpPort.tpPort(radiusServerPort)) - .matchUdpSrc(TpPort.tpPort(radiusServerPort)) - .build(); - packetService.requestPackets(radSelector, CONTROL, appId); } /** @@ -222,14 +240,19 @@ public class AAA { TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); selector.matchEthType(EthType.EtherType.EAPOL.ethType().toShort()); packetService.cancelPackets(selector.build(), CONTROL, appId); + } - TrafficSelector radSelector = DefaultTrafficSelector.builder() - .matchEthType(EthType.EtherType.IPV4.ethType().toShort()) - .matchIPProtocol(IPv4.PROTOCOL_UDP) - .matchUdpDst(TpPort.tpPort(radiusServerPort)) - .matchUdpSrc(TpPort.tpPort(radiusServerPort)) - .build(); - packetService.cancelPackets(radSelector, CONTROL, appId); + /** + * Send the ethernet packet to the supplicant. + * + * @param ethernetPkt the ethernet packet + * @param connectPoint the connect point to send out + */ + private void sendPacketToSupplicant(Ethernet ethernetPkt, ConnectPoint connectPoint) { + TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(connectPoint.port()).build(); + OutboundPacket packet = new DefaultOutboundPacket(connectPoint.deviceId(), + treatment, ByteBuffer.wrap(ethernetPkt.serialize())); + packetService.emit(packet); } // our handler defined as a private inner class @@ -253,26 +276,11 @@ public class AAA { case EAPOL: handleSupplicantPacket(context.inPacket()); break; - case IPV4: - IPv4 ipv4Packet = (IPv4) ethPkt.getPayload(); - Ip4Address srcIp = Ip4Address.valueOf(ipv4Packet.getSourceAddress()); - Ip4Address radiusIp4Address = Ip4Address.valueOf(radiusIpAddress); - if (srcIp.equals(radiusIp4Address) && ipv4Packet.getProtocol() == IPv4.PROTOCOL_UDP) { - // TODO: check for port as well when it's configurable - UDP udpPacket = (UDP) ipv4Packet.getPayload(); - - byte[] datagram = udpPacket.getPayload().serialize(); - RADIUS radiusPacket; - radiusPacket = RADIUS.deserializer().deserialize(datagram, 0, datagram.length); - handleRadiusPacket(radiusPacket); - } - - break; default: log.trace("Skipping Ethernet packet type {}", EthType.EtherType.lookup(ethPkt.getEtherType())); } - } catch (DeserializationException | StateMachineException e) { + } catch (StateMachineException e) { log.warn("Unable to process RADIUS packet:", e); } } @@ -280,23 +288,26 @@ public class AAA { /** * Creates and initializes common fields of a RADIUS packet. * - * @param identifier RADIUS identifier + * @param stateMachine state machine for the request * @param eapPacket EAP packet * @return RADIUS packet */ - private RADIUS getRadiusPayload(byte identifier, EAP eapPacket) { + private RADIUS getRadiusPayload(StateMachine stateMachine, byte identifier, EAP eapPacket) { RADIUS radiusPayload = new RADIUS(RADIUS.RADIUS_CODE_ACCESS_REQUEST, eapPacket.getIdentifier()); + + // set Request Authenticator in StateMachine + stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode()); + radiusPayload.setIdentifier(identifier); radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME, - eapPacket.getData()); + stateMachine.username()); radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP, AAA.this.nasIpAddress.getAddress()); radiusPayload.encapsulateMessage(eapPacket); - radiusPayload.addMessageAuthenticator(AAA.this.radiusSecret); return radiusPayload; } @@ -329,13 +340,13 @@ public class AAA { //send an EAP Request/Identify to the supplicant EAP eapPayload = new EAP(EAP.REQUEST, stateMachine.identifier(), EAP.ATTR_IDENTITY, null); - Ethernet eth = buildEapolResponse(srcMAC, MacAddress.valueOf(1L), + Ethernet eth = buildEapolResponse(srcMAC, MacAddress.valueOf(nasMacAddress), ethPkt.getVlanID(), EAPOL.EAPOL_PACKET, eapPayload); stateMachine.setSupplicantAddress(srcMAC); stateMachine.setVlanId(ethPkt.getVlanID()); - this.sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint()); + sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint()); break; case EAPOL.EAPOL_PACKET: @@ -350,11 +361,10 @@ public class AAA { // request id access to RADIUS stateMachine.setUsername(eapPacket.getData()); - radiusPayload = getRadiusPayload(stateMachine.identifier(), eapPacket); + radiusPayload = getRadiusPayload(stateMachine, stateMachine.identifier(), eapPacket); + radiusPayload.addMessageAuthenticator(AAA.this.radiusSecret); - // set Request Authenticator in StateMachine - stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode()); - sendRadiusMessage(radiusPayload); + sendRADIUSPacket(radiusPayload); // change the state to "PENDING" stateMachine.requestAccess(); @@ -365,24 +375,31 @@ public class AAA { // machine. if (eapPacket.getIdentifier() == stateMachine.challengeIdentifier()) { //send the RADIUS challenge response - radiusPayload = getRadiusPayload(stateMachine.challengeIdentifier(), eapPacket); + radiusPayload = + getRadiusPayload(stateMachine, + stateMachine.identifier(), + eapPacket); radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE, stateMachine.challengeState()); - sendRadiusMessage(radiusPayload); + radiusPayload.addMessageAuthenticator(AAA.this.radiusSecret); + sendRADIUSPacket(radiusPayload); } break; case EAP.ATTR_TLS: // request id access to RADIUS - radiusPayload = getRadiusPayload(stateMachine.identifier(), eapPacket); + radiusPayload = getRadiusPayload(stateMachine, stateMachine.identifier(), eapPacket); radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE, stateMachine.challengeState()); stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode()); - sendRadiusMessage(radiusPayload); - // TODO: this gets called on every fragment, should only be called at TLS-Start - stateMachine.requestAccess(); + radiusPayload.addMessageAuthenticator(AAA.this.radiusSecret); + sendRADIUSPacket(radiusPayload); + + if (stateMachine.state() != StateMachine.STATE_PENDING) { + stateMachine.requestAccess(); + } break; default: @@ -392,14 +409,18 @@ public class AAA { default: log.trace("Skipping EAPOL message {}", eapol.getEapolType()); } + } + } + + class RadiusListener implements Runnable { /** * Handles RADIUS packets. * * @param radiusPacket RADIUS packet coming from the RADIUS server. */ - private void handleRadiusPacket(RADIUS radiusPacket) throws StateMachineException { + protected void handleRadiusPacket(RADIUS radiusPacket) throws StateMachineException { StateMachine stateMachine = StateMachine.lookupStateMachineById(radiusPacket.getIdentifier()); if (stateMachine == null) { log.error("Invalid session identifier, exiting..."); @@ -410,13 +431,16 @@ public class AAA { Ethernet eth; switch (radiusPacket.getCode()) { case RADIUS.RADIUS_CODE_ACCESS_CHALLENGE: - byte[] challengeState = radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_STATE).getValue(); + byte[] challengeState = + radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_STATE).getValue(); eapPayload = radiusPacket.decapsulateMessage(); stateMachine.setChallengeInfo(eapPayload.getIdentifier(), challengeState); eth = buildEapolResponse(stateMachine.supplicantAddress(), - MacAddress.valueOf(1L), stateMachine.vlanId(), EAPOL.EAPOL_PACKET, + MacAddress.valueOf(nasMacAddress), + stateMachine.vlanId(), + EAPOL.EAPOL_PACKET, eapPayload); - this.sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint()); + sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint()); break; case RADIUS.RADIUS_CODE_ACCESS_ACCEPT: //send an EAPOL - Success to the supplicant. @@ -425,9 +449,11 @@ public class AAA { eapPayload = new EAP(); eapPayload = (EAP) eapPayload.deserialize(eapMessage, 0, eapMessage.length); eth = buildEapolResponse(stateMachine.supplicantAddress(), - MacAddress.valueOf(1L), stateMachine.vlanId(), EAPOL.EAPOL_PACKET, + MacAddress.valueOf(nasMacAddress), + stateMachine.vlanId(), + EAPOL.EAPOL_PACKET, eapPayload); - this.sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint()); + sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint()); stateMachine.authorizeAccess(); break; @@ -439,59 +465,45 @@ public class AAA { } } - private void sendRadiusMessage(RADIUS radiusMessage) { - Set<Host> hosts = hostService.getHostsByIp(IpAddress.valueOf(radiusIpAddress)); - Optional<Host> odst = hosts.stream().filter(h -> h.vlan().toShort() == VlanId.UNTAGGED).findFirst(); - - Host dst; - if (!odst.isPresent()) { - log.info("Radius server {} is not present", radiusIpAddress); - return; - } else { - dst = odst.get(); - } - - UDP udp = new UDP(); - IPv4 ip4Packet = new IPv4(); - Ethernet ethPkt = new Ethernet(); - radiusMessage.setParent(udp); - udp.setDestinationPort(radiusServerPort); - udp.setSourcePort(radiusServerPort); - udp.setPayload(radiusMessage); - udp.setParent(ip4Packet); - ip4Packet.setSourceAddress(AAA.this.nasIpAddress.getHostAddress()); - ip4Packet.setDestinationAddress(AAA.this.radiusIpAddress.getHostAddress()); - ip4Packet.setProtocol(IPv4.PROTOCOL_UDP); - ip4Packet.setPayload(udp); - ip4Packet.setParent(ethPkt); - ethPkt.setDestinationMACAddress(radiusMacAddress); - ethPkt.setSourceMACAddress(nasMacAddress); - ethPkt.setEtherType(Ethernet.TYPE_IPV4); - ethPkt.setPayload(ip4Packet); - - TrafficTreatment treatment = DefaultTrafficTreatment.builder() - .setOutput(PortNumber.portNumber(radiusPort)).build(); - OutboundPacket packet = new DefaultOutboundPacket(DeviceId.deviceId(radiusSwitch), - treatment, ByteBuffer.wrap(ethPkt.serialize())); - packetService.emit(packet); - } + @Override + public void run() { + boolean done = false; + int packetNumber = 1; + + log.info("UDP listener thread starting up"); + RADIUS inboundRadiusPacket; + while (!done) { + try { + byte[] packetBuffer = new byte[RADIUS.RADIUS_MAX_LENGTH]; + DatagramPacket inboundBasePacket = + new DatagramPacket(packetBuffer, packetBuffer.length); + DatagramSocket socket = radiusSocket; + socket.receive(inboundBasePacket); + log.info("Packet #{} received", packetNumber++); + try { + inboundRadiusPacket = + RADIUS.deserializer() + .deserialize(inboundBasePacket.getData(), + 0, + inboundBasePacket.getLength()); + handleRadiusPacket(inboundRadiusPacket); + } catch (DeserializationException dex) { + log.error("Cannot deserialize packet", dex); + } catch (StateMachineException sme) { + log.error("Illegal state machine operation", sme); + } - /** - * Send the ethernet packet to the supplicant. - * - * @param ethernetPkt the ethernet packet - * @param connectPoint the connect point to send out - */ - private void sendPacketToSupplicant(Ethernet ethernetPkt, ConnectPoint connectPoint) { - TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(connectPoint.port()).build(); - OutboundPacket packet = new DefaultOutboundPacket(connectPoint.deviceId(), - treatment, ByteBuffer.wrap(ethernetPkt.serialize())); - packetService.emit(packet); + } catch (IOException e) { + log.info("Socket was closed, exiting listener thread"); + done = true; + } + } } - } + RadiusListener radiusListener = new RadiusListener(); + private class InternalConfigListener implements NetworkConfigListener { /** diff --git a/framework/src/onos/apps/aaa/src/main/java/org/onosproject/aaa/AAAConfig.java b/framework/src/onos/apps/aaa/src/main/java/org/onosproject/aaa/AAAConfig.java index c18d2bf2..73be7691 100644 --- a/framework/src/onos/apps/aaa/src/main/java/org/onosproject/aaa/AAAConfig.java +++ b/framework/src/onos/apps/aaa/src/main/java/org/onosproject/aaa/AAAConfig.java @@ -37,13 +37,13 @@ public class AAAConfig extends Config<ApplicationId> { private static final String RADIUS_PORT = "radiusPort"; // RADIUS server IP address - protected static final String DEFAULT_RADIUS_IP = "192.168.1.10"; + protected static final String DEFAULT_RADIUS_IP = "10.128.10.4"; // RADIUS MAC address protected static final String DEFAULT_RADIUS_MAC = "00:00:00:00:01:10"; // NAS IP address - protected static final String DEFAULT_NAS_IP = "192.168.1.11"; + protected static final String DEFAULT_NAS_IP = "10.128.9.244"; // NAS MAC address protected static final String DEFAULT_NAS_MAC = "00:00:00:00:10:01"; diff --git a/framework/src/onos/apps/aaa/src/test/java/org/onosproject/aaa/AAAIntegrationTest.java b/framework/src/onos/apps/aaa/src/test/java/org/onosproject/aaa/AAAIntegrationTest.java new file mode 100644 index 00000000..fb513ced --- /dev/null +++ b/framework/src/onos/apps/aaa/src/test/java/org/onosproject/aaa/AAAIntegrationTest.java @@ -0,0 +1,151 @@ +/* + * Copyright 2014 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.aaa; + +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.onlab.packet.EAP; +import org.onlab.packet.EAPOL; +import org.onlab.packet.Ethernet; +import org.onosproject.core.CoreServiceAdapter; +import org.onosproject.net.config.Config; +import org.onosproject.net.config.NetworkConfigRegistryAdapter; + +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.junit.Assert.assertThat; + +/** + * Set of tests of the ONOS application component. These use an existing RADIUS + * server and sends live packets over the network to it. + */ +@Ignore ("This should not be run as part of the standard build") +public class AAAIntegrationTest extends AAATestBase { + + private AAA aaa; + + /** + * Mocks the network config registry. + */ + @SuppressWarnings("unchecked") + static final class TestNetworkConfigRegistry + extends NetworkConfigRegistryAdapter { + @Override + public <S, C extends Config<S>> C getConfig(S subject, Class<C> configClass) { + return (C) new AAAConfig(); + } + } + + /** + * Sets up the services required by the AAA application. + */ + @Before + public void setUp() { + aaa = new AAA(); + aaa.netCfgService = new TestNetworkConfigRegistry(); + aaa.coreService = new CoreServiceAdapter(); + aaa.packetService = new MockPacketService(); + aaa.activate(); + } + + /** + * Fetches the sent packet at the given index. The requested packet + * must be the last packet on the list. + * + * @param index index into sent packets array + * @return packet + */ + private Ethernet fetchPacket(int index) { + for (int iteration = 0; iteration < 20; iteration++) { + if (savedPackets.size() > index) { + return (Ethernet) savedPackets.get(index); + } else { + try { + Thread.sleep(250); + } catch (Exception ex) { + return null; + } + } + } + return null; + } + + /** + * Tests the authentication path through the AAA application by sending + * packets to the RADIUS server and checking the state machine + * transitions. + * + * @throws Exception when an unhandled error occurs + */ + @Test + public void testAuthentication() throws Exception { + + // (1) Supplicant start up + + Ethernet startPacket = constructSupplicantStartPacket(); + sendPacket(startPacket); + + Ethernet responsePacket = fetchPacket(0); + assertThat(responsePacket, notNullValue()); + checkRadiusPacket(aaa, responsePacket, EAP.REQUEST); + + // (2) Supplicant identify + + Ethernet identifyPacket = constructSupplicantIdentifyPacket(null, EAP.ATTR_IDENTITY, (byte) 1, null); + sendPacket(identifyPacket); + + // State machine should have been created by now + + StateMachine stateMachine = + StateMachine.lookupStateMachineBySessionId(SESSION_ID); + assertThat(stateMachine, notNullValue()); + assertThat(stateMachine.state(), is(StateMachine.STATE_PENDING)); + + // (3) RADIUS MD5 challenge + + Ethernet radiusChallengeMD5Packet = fetchPacket(1); + assertThat(radiusChallengeMD5Packet, notNullValue()); + checkRadiusPacket(aaa, radiusChallengeMD5Packet, EAP.REQUEST); + + + // (4) Supplicant MD5 response + + Ethernet md5RadiusPacket = + constructSupplicantIdentifyPacket(stateMachine, + EAP.ATTR_MD5, + stateMachine.challengeIdentifier(), + radiusChallengeMD5Packet); + sendPacket(md5RadiusPacket); + + + // (5) RADIUS Success + + Ethernet successRadiusPacket = fetchPacket(2); + assertThat(successRadiusPacket, notNullValue()); + EAPOL successEAPOL = (EAPOL) successRadiusPacket.getPayload(); + EAP successEAP = (EAP) successEAPOL.getPayload(); + assertThat(successEAP.getCode(), is(EAP.SUCCESS)); + + // State machine should be in authorized state + + assertThat(stateMachine, notNullValue()); + assertThat(stateMachine.state(), is(StateMachine.STATE_AUTHORIZED)); + + } + +} + diff --git a/framework/src/onos/apps/aaa/src/test/java/org/onosproject/aaa/AAATest.java b/framework/src/onos/apps/aaa/src/test/java/org/onosproject/aaa/AAATest.java index 75a60336..860a7dbd 100644 --- a/framework/src/onos/apps/aaa/src/test/java/org/onosproject/aaa/AAATest.java +++ b/framework/src/onos/apps/aaa/src/test/java/org/onosproject/aaa/AAATest.java @@ -15,164 +15,61 @@ */ package org.onosproject.aaa; -import java.nio.ByteBuffer; -import java.util.LinkedList; -import java.util.List; -import java.util.Set; +import java.net.InetAddress; +import java.net.UnknownHostException; import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.onlab.packet.Data; +import org.onlab.packet.BasePacket; import org.onlab.packet.DeserializationException; import org.onlab.packet.EAP; -import org.onlab.packet.EAPOL; -import org.onlab.packet.EthType; import org.onlab.packet.Ethernet; -import org.onlab.packet.IPv4; import org.onlab.packet.IpAddress; -import org.onlab.packet.MacAddress; import org.onlab.packet.RADIUS; import org.onlab.packet.RADIUSAttribute; -import org.onlab.packet.UDP; -import org.onlab.packet.VlanId; import org.onosproject.core.CoreServiceAdapter; -import org.onosproject.net.Annotations; -import org.onosproject.net.Host; -import org.onosproject.net.HostId; -import org.onosproject.net.HostLocation; import org.onosproject.net.config.Config; import org.onosproject.net.config.NetworkConfigRegistryAdapter; -import org.onosproject.net.host.HostServiceAdapter; -import org.onosproject.net.packet.DefaultInboundPacket; -import org.onosproject.net.packet.DefaultPacketContext; -import org.onosproject.net.packet.InboundPacket; -import org.onosproject.net.packet.OutboundPacket; -import org.onosproject.net.packet.PacketContext; -import org.onosproject.net.packet.PacketProcessor; -import org.onosproject.net.packet.PacketServiceAdapter; -import org.onosproject.net.provider.ProviderId; import com.google.common.base.Charsets; -import com.google.common.collect.ImmutableSet; -import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; -import static org.onosproject.net.NetTestTools.connectPoint; /** * Set of tests of the ONOS application component. */ -public class AAATest { +public class AAATest extends AAATestBase { - MacAddress clientMac = MacAddress.valueOf("1a:1a:1a:1a:1a:1a"); - MacAddress serverMac = MacAddress.valueOf("2a:2a:2a:2a:2a:2a"); + static final String BAD_IP_ADDRESS = "198.51.100.0"; - PacketProcessor packetProcessor; private AAA aaa; - List<Ethernet> savedPackets = new LinkedList<>(); - /** - * Saves the given packet onto the saved packets list. - * - * @param eth packet to save - */ - private void savePacket(Ethernet eth) { - savedPackets.add(eth); + class AAAWithoutRadiusServer extends AAA { + protected void sendRADIUSPacket(RADIUS radiusPacket) { + savePacket(radiusPacket); + } } /** - * Keeps a reference to the PacketProcessor and saves the OutboundPackets. + * Mocks the AAAConfig class to force usage of an unroutable address for the + * RADIUS server. */ - private class MockPacketService extends PacketServiceAdapter { - - @Override - public void addProcessor(PacketProcessor processor, int priority) { - packetProcessor = processor; - } - + static class MockAAAConfig extends AAAConfig { @Override - public void emit(OutboundPacket packet) { + public InetAddress radiusIp() { try { - Ethernet eth = Ethernet.deserializer().deserialize(packet.data().array(), - 0, packet.data().array().length); - savePacket(eth); - } catch (Exception e) { - fail(e.getMessage()); + return InetAddress.getByName(BAD_IP_ADDRESS); + } catch (UnknownHostException ex) { + // can't happen + throw new IllegalStateException(ex); } } } /** - * Mocks the DefaultPacketContext. - */ - private final class TestPacketContext extends DefaultPacketContext { - - private TestPacketContext(long time, InboundPacket inPkt, - OutboundPacket outPkt, boolean block) { - super(time, inPkt, outPkt, block); - } - - @Override - public void send() { - // We don't send anything out. - } - } - - /** - * Mocks a host to allow locating the Radius server. - */ - private static final class MockHost implements Host { - @Override - public HostId id() { - return null; - } - - @Override - public MacAddress mac() { - return null; - } - - @Override - public VlanId vlan() { - return VlanId.vlanId(VlanId.UNTAGGED); - } - - @Override - public Set<IpAddress> ipAddresses() { - return null; - } - - @Override - public HostLocation location() { - return null; - } - - @Override - public Annotations annotations() { - return null; - } - - @Override - public ProviderId providerId() { - return null; - } - } - - /** - * Mocks the Host service. - */ - private static final class MockHostService extends HostServiceAdapter { - @Override - public Set<Host> getHostsByIp(IpAddress ip) { - return ImmutableSet.of(new MockHost()); - } - } - - /** * Mocks the network config registry. */ @SuppressWarnings("unchecked") @@ -180,83 +77,12 @@ public class AAATest { extends NetworkConfigRegistryAdapter { @Override public <S, C extends Config<S>> C getConfig(S subject, Class<C> configClass) { - return (C) new AAAConfig(); + AAAConfig aaaConfig = new MockAAAConfig(); + return (C) aaaConfig; } } /** - * Sends an Ethernet packet to the process method of the Packet Processor. - * - * @param reply Ethernet packet - */ - private void sendPacket(Ethernet reply) { - final ByteBuffer byteBuffer = ByteBuffer.wrap(reply.serialize()); - InboundPacket inPacket = new DefaultInboundPacket(connectPoint("1", 1), - reply, - byteBuffer); - - PacketContext context = new TestPacketContext(127L, inPacket, null, false); - packetProcessor.process(context); - } - - /** - * Constructs an Ethernet packet containing a EAPOL_START Payload. - * - * @return Ethernet packet - */ - private Ethernet constructSupplicantStartPacket() { - Ethernet eth = new Ethernet(); - eth.setDestinationMACAddress(clientMac.toBytes()); - eth.setSourceMACAddress(serverMac.toBytes()); - eth.setEtherType(EthType.EtherType.EAPOL.ethType().toShort()); - eth.setVlanID((short) 2); - - EAP eap = new EAP(EAPOL.EAPOL_START, (byte) 1, EAPOL.EAPOL_START, null); - - //eapol header - EAPOL eapol = new EAPOL(); - eapol.setEapolType(EAPOL.EAPOL_START); - eapol.setPacketLength(eap.getLength()); - - //eap part - eapol.setPayload(eap); - - eth.setPayload(eapol); - eth.setPad(true); - return eth; - } - - /** - * Constructs an Ethernet packet containing identification payload. - * - * @return Ethernet packet - */ - private Ethernet constructSupplicantIdentifyPacket(byte type) { - Ethernet eth = new Ethernet(); - eth.setDestinationMACAddress(clientMac.toBytes()); - eth.setSourceMACAddress(serverMac.toBytes()); - eth.setEtherType(EthType.EtherType.EAPOL.ethType().toShort()); - eth.setVlanID((short) 2); - - String username = "user"; - EAP eap = new EAP(EAP.REQUEST, (byte) 1, type, - username.getBytes(Charsets.US_ASCII)); - eap.setIdentifier((byte) 1); - - // eapol header - EAPOL eapol = new EAPOL(); - eapol.setEapolType(EAPOL.EAPOL_PACKET); - eapol.setPacketLength(eap.getLength()); - - // eap part - eapol.setPayload(eap); - - eth.setPayload(eapol); - eth.setPad(true); - return eth; - } - - /** * Constructs an Ethernet packet containing a RADIUS challenge * packet. * @@ -264,18 +90,9 @@ public class AAATest { * @param challengeType type to use in challenge packet * @return Ethernet packet */ - private Ethernet constructRADIUSCodeAccessChallengePacket(byte challengeCode, byte challengeType) { - Ethernet eth = new Ethernet(); - eth.setDestinationMACAddress(clientMac.toBytes()); - eth.setSourceMACAddress(serverMac.toBytes()); - eth.setEtherType(EthType.EtherType.IPV4.ethType().toShort()); - eth.setVlanID((short) 2); - - IPv4 ipv4 = new IPv4(); - ipv4.setProtocol(IPv4.PROTOCOL_UDP); - ipv4.setSourceAddress(aaa.radiusIpAddress.getHostAddress()); + private RADIUS constructRADIUSCodeAccessChallengePacket(byte challengeCode, byte challengeType) { - String challenge = "1234"; + String challenge = "12345678901234567"; EAP eap = new EAP(challengeType, (byte) 1, challengeType, challenge.getBytes(Charsets.US_ASCII)); @@ -291,13 +108,7 @@ public class AAATest { radius.setAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE, eap.serialize()); - UDP udp = new UDP(); - udp.setPayload(radius); - ipv4.setPayload(udp); - - eth.setPayload(ipv4); - eth.setPad(true); - return eth; + return radius; } /** @@ -305,11 +116,10 @@ public class AAATest { */ @Before public void setUp() { - aaa = new AAA(); + aaa = new AAAWithoutRadiusServer(); aaa.netCfgService = new TestNetworkConfigRegistry(); aaa.coreService = new CoreServiceAdapter(); aaa.packetService = new MockPacketService(); - aaa.hostService = new MockHostService(); aaa.activate(); } @@ -324,60 +134,16 @@ public class AAATest { /** * Extracts the RADIUS packet from a packet sent by the supplicant. * - * @param supplicantPacket packet sent by the supplicant - * @return RADIUS packet + * @param radius RADIUS packet sent by the supplicant * @throws DeserializationException if deserialization of the packet contents * fails. */ - private RADIUS checkAndFetchRADIUSPacketFromSupplicant(Ethernet supplicantPacket) + private void checkRADIUSPacketFromSupplicant(RADIUS radius) throws DeserializationException { - assertThat(supplicantPacket, notNullValue()); - assertThat(supplicantPacket.getVlanID(), is(VlanId.UNTAGGED)); - assertThat(supplicantPacket.getSourceMAC().toString(), is(aaa.nasMacAddress)); - assertThat(supplicantPacket.getDestinationMAC().toString(), is(aaa.radiusMacAddress)); - - assertThat(supplicantPacket.getPayload(), instanceOf(IPv4.class)); - IPv4 ipv4 = (IPv4) supplicantPacket.getPayload(); - assertThat(ipv4, notNullValue()); - assertThat(IpAddress.valueOf(ipv4.getSourceAddress()).toString(), - is(aaa.nasIpAddress.getHostAddress())); - assertThat(IpAddress.valueOf(ipv4.getDestinationAddress()).toString(), - is(aaa.radiusIpAddress.getHostAddress())); - - assertThat(ipv4.getPayload(), instanceOf(UDP.class)); - UDP udp = (UDP) ipv4.getPayload(); - assertThat(udp, notNullValue()); - - assertThat(udp.getPayload(), instanceOf(Data.class)); - Data data = (Data) udp.getPayload(); - RADIUS radius = RADIUS.deserializer() - .deserialize(data.getData(), 0, data.getData().length); assertThat(radius, notNullValue()); - return radius; - } - - /** - * Checks the contents of a RADIUS packet being sent to the RADIUS server. - * - * @param radiusPacket packet to check - * @param code expected code - */ - private void checkRadiusPacket(Ethernet radiusPacket, byte code) { - assertThat(radiusPacket.getVlanID(), is((short) 2)); - - // TODO: These address values seem wrong, but are produced by the current AAA implementation - assertThat(radiusPacket.getSourceMAC(), is(MacAddress.valueOf(1L))); - assertThat(radiusPacket.getDestinationMAC(), is(serverMac)); - assertThat(radiusPacket.getPayload(), instanceOf(EAPOL.class)); - EAPOL eapol = (EAPOL) radiusPacket.getPayload(); - assertThat(eapol, notNullValue()); - - assertThat(eapol.getEapolType(), is(EAPOL.EAPOL_PACKET)); - assertThat(eapol.getPayload(), instanceOf(EAP.class)); - EAP eap = (EAP) eapol.getPayload(); + EAP eap = radius.decapsulateMessage(); assertThat(eap, notNullValue()); - assertThat(eap.getCode(), is(code)); } /** @@ -387,11 +153,10 @@ public class AAATest { * @param index index into sent packets array * @return packet */ - private Ethernet fetchPacket(int index) { - assertThat(savedPackets.size(), is(index + 1)); - Ethernet eth = savedPackets.get(index); - assertThat(eth, notNullValue()); - return eth; + private BasePacket fetchPacket(int index) { + BasePacket packet = savedPackets.get(index); + assertThat(packet, notNullValue()); + return packet; } /** @@ -400,61 +165,64 @@ public class AAATest { * @throws DeserializationException if packed deserialization fails. */ @Test - public void testAuthentication() throws DeserializationException { - - // Our session id will be the device ID ("of:1") with the port ("1") concatenated - String sessionId = "of:11"; + public void testAuthentication() throws Exception { // (1) Supplicant start up Ethernet startPacket = constructSupplicantStartPacket(); sendPacket(startPacket); - Ethernet responsePacket = fetchPacket(0); - checkRadiusPacket(responsePacket, EAP.ATTR_IDENTITY); + Ethernet responsePacket = (Ethernet) fetchPacket(0); + checkRadiusPacket(aaa, responsePacket, EAP.ATTR_IDENTITY); // (2) Supplicant identify - Ethernet identifyPacket = constructSupplicantIdentifyPacket(EAP.ATTR_IDENTITY); + Ethernet identifyPacket = constructSupplicantIdentifyPacket(null, EAP.ATTR_IDENTITY, (byte) 1, null); sendPacket(identifyPacket); - Ethernet radiusIdentifyPacket = fetchPacket(1); + RADIUS radiusIdentifyPacket = (RADIUS) fetchPacket(1); + + checkRADIUSPacketFromSupplicant(radiusIdentifyPacket); - RADIUS radiusAccessRequest = checkAndFetchRADIUSPacketFromSupplicant(radiusIdentifyPacket); - assertThat(radiusAccessRequest, notNullValue()); - assertThat(radiusAccessRequest.getCode(), is(RADIUS.RADIUS_CODE_ACCESS_REQUEST)); - assertThat(new String(radiusAccessRequest.getAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME).getValue()), - is("user")); + assertThat(radiusIdentifyPacket.getCode(), is(RADIUS.RADIUS_CODE_ACCESS_REQUEST)); + assertThat(new String(radiusIdentifyPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME).getValue()), + is("testuser")); IpAddress nasIp = IpAddress.valueOf(IpAddress.Version.INET, - radiusAccessRequest.getAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP) + radiusIdentifyPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP) .getValue()); assertThat(nasIp.toString(), is(aaa.nasIpAddress.getHostAddress())); // State machine should have been created by now StateMachine stateMachine = - StateMachine.lookupStateMachineBySessionId(sessionId); + StateMachine.lookupStateMachineBySessionId(SESSION_ID); assertThat(stateMachine, notNullValue()); assertThat(stateMachine.state(), is(StateMachine.STATE_PENDING)); // (3) RADIUS MD5 challenge - Ethernet radiusCodeAccessChallengePacket = + RADIUS radiusCodeAccessChallengePacket = constructRADIUSCodeAccessChallengePacket(RADIUS.RADIUS_CODE_ACCESS_CHALLENGE, EAP.ATTR_MD5); - sendPacket(radiusCodeAccessChallengePacket); + aaa.radiusListener.handleRadiusPacket(radiusCodeAccessChallengePacket); - Ethernet radiusChallengeMD5Packet = fetchPacket(2); - checkRadiusPacket(radiusChallengeMD5Packet, EAP.ATTR_MD5); + Ethernet radiusChallengeMD5Packet = (Ethernet) fetchPacket(2); + checkRadiusPacket(aaa, radiusChallengeMD5Packet, EAP.ATTR_MD5); // (4) Supplicant MD5 response - Ethernet md5RadiusPacket = constructSupplicantIdentifyPacket(EAP.ATTR_MD5); + Ethernet md5RadiusPacket = + constructSupplicantIdentifyPacket(stateMachine, + EAP.ATTR_MD5, + stateMachine.challengeIdentifier(), + radiusChallengeMD5Packet); sendPacket(md5RadiusPacket); - Ethernet supplicantMD5ResponsePacket = fetchPacket(3); - RADIUS responseMd5RadiusPacket = checkAndFetchRADIUSPacketFromSupplicant(supplicantMD5ResponsePacket); - assertThat(responseMd5RadiusPacket.getIdentifier(), is((byte) 1)); + + RADIUS responseMd5RadiusPacket = (RADIUS) fetchPacket(3); + + checkRADIUSPacketFromSupplicant(responseMd5RadiusPacket); + assertThat(responseMd5RadiusPacket.getIdentifier(), is((byte) 0)); assertThat(responseMd5RadiusPacket.getCode(), is(RADIUS.RADIUS_CODE_ACCESS_REQUEST)); // State machine should be in pending state @@ -462,37 +230,20 @@ public class AAATest { assertThat(stateMachine, notNullValue()); assertThat(stateMachine.state(), is(StateMachine.STATE_PENDING)); - // (5) RADIUS TLS Challenge - - Ethernet radiusCodeAccessChallengeTLSPacket = - constructRADIUSCodeAccessChallengePacket(RADIUS.RADIUS_CODE_ACCESS_CHALLENGE, EAP.ATTR_TLS); - sendPacket(radiusCodeAccessChallengeTLSPacket); + // (5) RADIUS Success - Ethernet radiusChallengeTLSPacket = fetchPacket(4); - checkRadiusPacket(radiusChallengeTLSPacket, EAP.ATTR_TLS); - - // (6) Supplicant TLS response - - Ethernet tlsRadiusPacket = constructSupplicantIdentifyPacket(EAP.ATTR_TLS); - sendPacket(tlsRadiusPacket); - Ethernet supplicantTLSResponsePacket = fetchPacket(5); - RADIUS responseTLSRadiusPacket = checkAndFetchRADIUSPacketFromSupplicant(supplicantTLSResponsePacket); - assertThat(responseTLSRadiusPacket.getIdentifier(), is((byte) 0)); - assertThat(responseTLSRadiusPacket.getCode(), is(RADIUS.RADIUS_CODE_ACCESS_REQUEST)); - - // (7) RADIUS Success - - Ethernet successPacket = + RADIUS successPacket = constructRADIUSCodeAccessChallengePacket(RADIUS.RADIUS_CODE_ACCESS_ACCEPT, EAP.SUCCESS); - sendPacket(successPacket); - Ethernet supplicantSuccessPacket = fetchPacket(6); + aaa.radiusListener.handleRadiusPacket((successPacket)); + Ethernet supplicantSuccessPacket = (Ethernet) fetchPacket(4); - checkRadiusPacket(supplicantSuccessPacket, EAP.SUCCESS); + checkRadiusPacket(aaa, supplicantSuccessPacket, EAP.SUCCESS); // State machine should be in authorized state assertThat(stateMachine, notNullValue()); assertThat(stateMachine.state(), is(StateMachine.STATE_AUTHORIZED)); + } /** @@ -502,7 +253,7 @@ public class AAATest { public void testConfig() { assertThat(aaa.nasIpAddress.getHostAddress(), is(AAAConfig.DEFAULT_NAS_IP)); assertThat(aaa.nasMacAddress, is(AAAConfig.DEFAULT_NAS_MAC)); - assertThat(aaa.radiusIpAddress.getHostAddress(), is(AAAConfig.DEFAULT_RADIUS_IP)); + assertThat(aaa.radiusIpAddress.getHostAddress(), is(BAD_IP_ADDRESS)); assertThat(aaa.radiusMacAddress, is(AAAConfig.DEFAULT_RADIUS_MAC)); } } diff --git a/framework/src/onos/apps/aaa/src/test/java/org/onosproject/aaa/AAATestBase.java b/framework/src/onos/apps/aaa/src/test/java/org/onosproject/aaa/AAATestBase.java new file mode 100644 index 00000000..dffcba2f --- /dev/null +++ b/framework/src/onos/apps/aaa/src/test/java/org/onosproject/aaa/AAATestBase.java @@ -0,0 +1,224 @@ +/* + * Copyright 2015 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.aaa; + +import java.nio.ByteBuffer; +import java.security.MessageDigest; +import java.util.LinkedList; +import java.util.List; + +import org.onlab.packet.BasePacket; +import org.onlab.packet.EAP; +import org.onlab.packet.EAPOL; +import org.onlab.packet.EthType; +import org.onlab.packet.Ethernet; +import org.onlab.packet.MacAddress; +import org.onosproject.net.packet.DefaultInboundPacket; +import org.onosproject.net.packet.DefaultPacketContext; +import org.onosproject.net.packet.InboundPacket; +import org.onosproject.net.packet.OutboundPacket; +import org.onosproject.net.packet.PacketContext; +import org.onosproject.net.packet.PacketProcessor; +import org.onosproject.net.packet.PacketServiceAdapter; + +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; +import static org.onosproject.net.NetTestTools.connectPoint; + +/** + * Common methods for AAA app testing. + */ +public class AAATestBase { + + MacAddress clientMac = MacAddress.valueOf("1a:1a:1a:1a:1a:1a"); + MacAddress serverMac = MacAddress.valueOf("2a:2a:2a:2a:2a:2a"); + + // Our session id will be the device ID ("of:1") with the port ("1") concatenated + static final String SESSION_ID = "of:11"; + + List<BasePacket> savedPackets = new LinkedList<>(); + PacketProcessor packetProcessor; + + /** + * Saves the given packet onto the saved packets list. + * + * @param packet packet to save + */ + void savePacket(BasePacket packet) { + savedPackets.add(packet); + } + + /** + * Keeps a reference to the PacketProcessor and saves the OutboundPackets. + */ + class MockPacketService extends PacketServiceAdapter { + + @Override + public void addProcessor(PacketProcessor processor, int priority) { + packetProcessor = processor; + } + + @Override + public void emit(OutboundPacket packet) { + try { + Ethernet eth = Ethernet.deserializer().deserialize(packet.data().array(), + 0, packet.data().array().length); + savePacket(eth); + } catch (Exception e) { + fail(e.getMessage()); + } + } + } + + /** + * Mocks the DefaultPacketContext. + */ + final class TestPacketContext extends DefaultPacketContext { + + private TestPacketContext(long time, InboundPacket inPkt, + OutboundPacket outPkt, boolean block) { + super(time, inPkt, outPkt, block); + } + + @Override + public void send() { + // We don't send anything out. + } + } + + /** + * Sends an Ethernet packet to the process method of the Packet Processor. + * + * @param reply Ethernet packet + */ + void sendPacket(Ethernet reply) { + final ByteBuffer byteBuffer = ByteBuffer.wrap(reply.serialize()); + InboundPacket inPacket = new DefaultInboundPacket(connectPoint("1", 1), + reply, + byteBuffer); + + PacketContext context = new TestPacketContext(127L, inPacket, null, false); + packetProcessor.process(context); + } + + /** + * Constructs an Ethernet packet containing identification payload. + * + * @return Ethernet packet + */ + Ethernet constructSupplicantIdentifyPacket(StateMachine stateMachine, + byte type, + byte id, + Ethernet radiusChallenge) + throws Exception { + Ethernet eth = new Ethernet(); + eth.setDestinationMACAddress(clientMac.toBytes()); + eth.setSourceMACAddress(serverMac.toBytes()); + eth.setEtherType(EthType.EtherType.EAPOL.ethType().toShort()); + eth.setVlanID((short) 2); + + String username = "testuser"; + byte[] data = username.getBytes(); + + + if (type == EAP.ATTR_MD5) { + String password = "testpassword"; + EAPOL eapol = (EAPOL) radiusChallenge.getPayload(); + EAP eap = (EAP) eapol.getPayload(); + + byte[] identifier = new byte[password.length() + eap.getData().length]; + + identifier[0] = stateMachine.challengeIdentifier(); + System.arraycopy(password.getBytes(), 0, identifier, 1, password.length()); + System.arraycopy(eap.getData(), 1, identifier, 1 + password.length(), 16); + + MessageDigest md = MessageDigest.getInstance("MD5"); + byte[] hash = md.digest(identifier); + data = new byte[17]; + data[0] = (byte) 16; + System.arraycopy(hash, 0, data, 1, 16); + } + EAP eap = new EAP(EAP.RESPONSE, (byte) 1, type, + data); + eap.setIdentifier(id); + + // eapol header + EAPOL eapol = new EAPOL(); + eapol.setEapolType(EAPOL.EAPOL_PACKET); + eapol.setPacketLength(eap.getLength()); + + // eap part + eapol.setPayload(eap); + + eth.setPayload(eapol); + eth.setPad(true); + return eth; + } + + /** + * Constructs an Ethernet packet containing a EAPOL_START Payload. + * + * @return Ethernet packet + */ + Ethernet constructSupplicantStartPacket() { + Ethernet eth = new Ethernet(); + eth.setDestinationMACAddress(clientMac.toBytes()); + eth.setSourceMACAddress(serverMac.toBytes()); + eth.setEtherType(EthType.EtherType.EAPOL.ethType().toShort()); + eth.setVlanID((short) 2); + + EAP eap = new EAP(EAPOL.EAPOL_START, (byte) 2, EAPOL.EAPOL_START, null); + + // eapol header + EAPOL eapol = new EAPOL(); + eapol.setEapolType(EAPOL.EAPOL_START); + eapol.setPacketLength(eap.getLength()); + + // eap part + eapol.setPayload(eap); + + eth.setPayload(eapol); + eth.setPad(true); + return eth; + } + + /** + * Checks the contents of a RADIUS packet being sent to the RADIUS server. + * + * @param radiusPacket packet to check + * @param code expected code + */ + void checkRadiusPacket(AAA aaa, Ethernet radiusPacket, byte code) { + + assertThat(radiusPacket.getSourceMAC(), + is(MacAddress.valueOf(aaa.nasMacAddress))); + assertThat(radiusPacket.getDestinationMAC(), is(serverMac)); + + assertThat(radiusPacket.getPayload(), instanceOf(EAPOL.class)); + EAPOL eapol = (EAPOL) radiusPacket.getPayload(); + assertThat(eapol, notNullValue()); + + assertThat(eapol.getEapolType(), is(EAPOL.EAPOL_PACKET)); + assertThat(eapol.getPayload(), instanceOf(EAP.class)); + EAP eap = (EAP) eapol.getPayload(); + assertThat(eap, notNullValue()); + + assertThat(eap.getCode(), is(code)); + } +} diff --git a/framework/src/onos/apps/aaa/src/test/java/org/onosproject/aaa/StateMachineTest.java b/framework/src/onos/apps/aaa/src/test/java/org/onosproject/aaa/StateMachineTest.java index 04837e85..1838c63e 100644 --- a/framework/src/onos/apps/aaa/src/test/java/org/onosproject/aaa/StateMachineTest.java +++ b/framework/src/onos/apps/aaa/src/test/java/org/onosproject/aaa/StateMachineTest.java @@ -21,7 +21,9 @@ import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; -import static org.junit.Assert.*; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; public class StateMachineTest { diff --git a/framework/src/onos/apps/cordvtn/pom.xml b/framework/src/onos/apps/cordvtn/pom.xml index b8e913d4..1d96108b 100644 --- a/framework/src/onos/apps/cordvtn/pom.xml +++ b/framework/src/onos/apps/cordvtn/pom.xml @@ -54,6 +54,16 @@ <artifactId>onos-ovsdb-api</artifactId> <version>${project.version}</version> </dependency> + <dependency> + <groupId>org.onosproject</groupId> + <artifactId>onos-cli</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.apache.karaf.shell</groupId> + <artifactId>org.apache.karaf.shell.console</artifactId> + <version>3.0.3</version> + </dependency> </dependencies> </project> diff --git a/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtn.java b/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtn.java index ba707800..4b28a14b 100644 --- a/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtn.java +++ b/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtn.java @@ -27,7 +27,6 @@ import org.onlab.util.KryoNamespace; import org.onosproject.cluster.ClusterService; import org.onosproject.core.ApplicationId; import org.onosproject.core.CoreService; -import org.onosproject.mastership.MastershipService; import org.onosproject.net.Device; import org.onosproject.net.DeviceId; import org.onosproject.net.Host; @@ -52,6 +51,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.NoSuchElementException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -75,7 +75,8 @@ public class CordVtn implements CordVtnService { .register(KryoNamespaces.API) .register(DefaultOvsdbNode.class); private static final String DEFAULT_BRIDGE_NAME = "br-int"; - private static final Map<String, String> VXLAN_OPTIONS = new HashMap<String, String>() { + private static final String DEFAULT_TUNNEL = "vxlan"; + private static final Map<String, String> DEFAULT_TUNNEL_OPTIONS = new HashMap<String, String>() { { put("key", "flow"); put("local_ip", "flow"); @@ -98,9 +99,6 @@ public class CordVtn implements CordVtnService { protected HostService hostService; @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) - protected MastershipService mastershipService; - - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected OvsdbController controller; @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) @@ -117,11 +115,10 @@ public class CordVtn implements CordVtnService { private final VmHandler vmHandler = new VmHandler(); private ConsistentMap<DeviceId, OvsdbNode> nodeStore; - private ApplicationId appId; @Activate protected void activate() { - appId = coreService.registerApplication("org.onosproject.cordvtn"); + ApplicationId appId = coreService.registerApplication("org.onosproject.cordvtn"); nodeStore = storageService.<DeviceId, OvsdbNode>consistentMapBuilder() .withSerializer(Serializer.using(NODE_SERIALIZER.build())) .withName("cordvtn-nodestore") @@ -148,38 +145,59 @@ public class CordVtn implements CordVtnService { @Override public void addNode(OvsdbNode ovsdb) { checkNotNull(ovsdb); - nodeStore.put(ovsdb.deviceId(), ovsdb); + + nodeStore.putIfAbsent(ovsdb.deviceId(), ovsdb); + + if (isNodeConnected(ovsdb)) { + init(ovsdb); + } else { + connect(ovsdb); + } } @Override public void deleteNode(OvsdbNode ovsdb) { checkNotNull(ovsdb); + if (deviceService.getDevice(ovsdb.deviceId()) != null) { + if (deviceService.isAvailable(ovsdb.deviceId())) { + log.warn("Cannot delete connected node {}", ovsdb.host()); + return; + } + } + nodeStore.remove(ovsdb.deviceId()); + } + + @Override + public void connect(OvsdbNode ovsdb) { + checkNotNull(ovsdb); + if (!nodeStore.containsKey(ovsdb.deviceId())) { + log.warn("Node {} does not exist", ovsdb.host()); return; } - // check ovsdb and integration bridge connection state first - if (isNodeConnected(ovsdb)) { - log.warn("Cannot delete connected node {}", ovsdb.host()); - } else { - nodeStore.remove(ovsdb.deviceId()); + if (!isNodeConnected(ovsdb)) { + controller.connect(ovsdb.ip(), ovsdb.port()); } } @Override - public void connect(OvsdbNode ovsdb) { + public void disconnect(OvsdbNode ovsdb) { checkNotNull(ovsdb); if (!nodeStore.containsKey(ovsdb.deviceId())) { log.warn("Node {} does not exist", ovsdb.host()); return; } - controller.connect(ovsdb.ip(), ovsdb.port()); + + if (isNodeConnected(ovsdb)) { + OvsdbClientService ovsdbClient = getOvsdbClient(ovsdb); + ovsdbClient.disconnect(); + } } - @Override - public void disconnect(OvsdbNode ovsdb) { + private void init(OvsdbNode ovsdb) { checkNotNull(ovsdb); if (!nodeStore.containsKey(ovsdb.deviceId())) { @@ -187,11 +205,16 @@ public class CordVtn implements CordVtnService { return; } - OvsdbClientService ovsdbClient = getOvsdbClient(ovsdb); - checkNotNull(ovsdbClient); + if (!isNodeConnected(ovsdb)) { + log.warn("Node {} is not connected", ovsdb.host()); + return; + } - if (ovsdbClient.isConnected()) { - ovsdbClient.disconnect(); + if (deviceService.getDevice(ovsdb.intBrId()) == null || + !deviceService.isAvailable(ovsdb.intBrId())) { + createIntegrationBridge(ovsdb); + } else if (!checkVxlanPort(ovsdb)) { + createVxlanPort(ovsdb); } } @@ -235,11 +258,45 @@ public class CordVtn implements CordVtnService { OvsdbClientService ovsdbClient = controller.getOvsdbClient( new OvsdbNodeId(ovsdb.ip(), ovsdb.port().toInt())); if (ovsdbClient == null) { - log.warn("Couldn't find ovsdb client of node {}", ovsdb.host()); + log.debug("Couldn't find ovsdb client for {}", ovsdb.host()); } return ovsdbClient; } + private void createIntegrationBridge(OvsdbNode ovsdb) { + List<ControllerInfo> controllers = new ArrayList<>(); + Sets.newHashSet(clusterService.getNodes()) + .forEach(controller -> { + ControllerInfo ctrlInfo = new ControllerInfo(controller.ip(), OFPORT, "tcp"); + controllers.add(ctrlInfo); + }); + String dpid = ovsdb.intBrId().toString().substring(DPID_BEGIN); + + // TODO change to use bridge config + OvsdbClientService ovsdbClient = getOvsdbClient(ovsdb); + ovsdbClient.createBridge(DEFAULT_BRIDGE_NAME, dpid, controllers); + } + + private void createVxlanPort(OvsdbNode ovsdb) { + // TODO change to use tunnel config and tunnel description + OvsdbClientService ovsdbClient = getOvsdbClient(ovsdb); + ovsdbClient.createTunnel(DEFAULT_BRIDGE_NAME, DEFAULT_TUNNEL, + DEFAULT_TUNNEL, DEFAULT_TUNNEL_OPTIONS); + } + + private boolean checkVxlanPort(OvsdbNode ovsdb) { + // TODO change to use tunnel config + OvsdbClientService ovsdbClient = getOvsdbClient(ovsdb); + try { + ovsdbClient.getPorts().stream() + .filter(p -> p.portName().value().equals(DEFAULT_TUNNEL)) + .findFirst().get(); + } catch (NoSuchElementException e) { + return false; + } + return true; + } + private class InternalDeviceListener implements DeviceListener { @Override @@ -252,8 +309,11 @@ public class CordVtn implements CordVtnService { eventExecutor.submit(() -> handler.connected(device)); break; case DEVICE_AVAILABILITY_CHANGED: - eventExecutor.submit(() -> handler.disconnected(device)); - // TODO handle the case that the device is recovered + if (deviceService.isAvailable(device.id())) { + eventExecutor.submit(() -> handler.connected(device)); + } else { + eventExecutor.submit(() -> handler.disconnected(device)); + } break; default: break; @@ -286,20 +346,10 @@ public class CordVtn implements CordVtnService { public void connected(Device device) { log.info("Ovsdb {} is connected", device.id()); - if (!mastershipService.isLocalMaster(device.id())) { - return; - } - - // TODO change to use bridge config OvsdbNode ovsdb = getNode(device.id()); - OvsdbClientService ovsdbClient = getOvsdbClient(ovsdb); - - List<ControllerInfo> controllers = new ArrayList<>(); - Sets.newHashSet(clusterService.getNodes()).forEach(controller -> - controllers.add(new ControllerInfo(controller.ip(), OFPORT, "tcp"))); - String dpid = ovsdb.intBrId().toString().substring(DPID_BEGIN); - - ovsdbClient.createBridge(DEFAULT_BRIDGE_NAME, dpid, controllers); + if (ovsdb != null) { + init(ovsdb); + } } @Override @@ -314,22 +364,19 @@ public class CordVtn implements CordVtnService { public void connected(Device device) { log.info("Integration Bridge {} is detected", device.id()); - OvsdbNode ovsdb = getNodes().stream() - .filter(node -> node.intBrId().equals(device.id())) - .findFirst().get(); - - if (ovsdb == null) { + OvsdbNode ovsdb; + try { + ovsdb = getNodes().stream() + .filter(node -> node.intBrId().equals(device.id())) + .findFirst().get(); + } catch (NoSuchElementException e) { log.warn("Couldn't find OVSDB associated with {}", device.id()); return; } - if (!mastershipService.isLocalMaster(ovsdb.deviceId())) { - return; + if (!checkVxlanPort(ovsdb)) { + createVxlanPort(ovsdb); } - - // TODO change to use tunnel config and tunnel description - OvsdbClientService ovsdbClient = getOvsdbClient(ovsdb); - ovsdbClient.createTunnel(DEFAULT_BRIDGE_NAME, "vxlan", "vxlan", VXLAN_OPTIONS); } @Override diff --git a/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtnConfigManager.java b/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtnConfigManager.java index f276c7ca..287f2a34 100644 --- a/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtnConfigManager.java +++ b/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtnConfigManager.java @@ -94,7 +94,6 @@ public class CordVtnConfigManager { DefaultOvsdbNode ovsdb = new DefaultOvsdbNode( node.host(), node.ip(), node.port(), node.bridgeId()); cordVtnService.addNode(ovsdb); - cordVtnService.connect(ovsdb); }); } diff --git a/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/OvsdbNode.java b/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/OvsdbNode.java index c5b7a078..7a9a06a6 100644 --- a/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/OvsdbNode.java +++ b/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/OvsdbNode.java @@ -19,11 +19,20 @@ import org.onlab.packet.IpAddress; import org.onlab.packet.TpPort; import org.onosproject.net.DeviceId; +import java.util.Comparator; + /** * Representation of a node with ovsdb server. */ public interface OvsdbNode { + Comparator<OvsdbNode> OVSDB_NODE_COMPARATOR = new Comparator<OvsdbNode>() { + @Override + public int compare(OvsdbNode ovsdb1, OvsdbNode ovsdb2) { + return ovsdb1.host().compareTo(ovsdb2.host()); + } + }; + /** * Returns the IP address of the ovsdb server. * diff --git a/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/cli/OvsdbNodeAddCommand.java b/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/cli/OvsdbNodeAddCommand.java new file mode 100644 index 00000000..88d16341 --- /dev/null +++ b/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/cli/OvsdbNodeAddCommand.java @@ -0,0 +1,65 @@ +/* + * Copyright 2015 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.cordvtn.cli; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onlab.packet.IpAddress; +import org.onlab.packet.TpPort; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.cordvtn.CordVtnService; +import org.onosproject.cordvtn.DefaultOvsdbNode; +import org.onosproject.cordvtn.OvsdbNode; +import org.onosproject.net.DeviceId; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * Adds a new OVSDB nodes. + */ +@Command(scope = "onos", name = "ovsdb-add", + description = "Adds a new OVSDB node to cordvtn") +public class OvsdbNodeAddCommand extends AbstractShellCommand { + + @Argument(index = 0, name = "host", description = "Hostname or IP", + required = true, multiValued = false) + private String host = null; + + @Argument(index = 1, name = "address", + description = "OVSDB server listening address (ip:port)", + required = true, multiValued = false) + private String address = null; + + @Argument(index = 2, name = "bridgeId", + description = "Device ID of integration bridge", + required = true, multiValued = false) + private String bridgeId = null; + + @Override + protected void execute() { + checkArgument(address.contains(":"), "address should be ip:port format"); + checkArgument(bridgeId.startsWith("of:"), "bridgeId should be of:dpid format"); + + CordVtnService service = AbstractShellCommand.get(CordVtnService.class); + String[] ipPort = address.split(":"); + OvsdbNode ovsdb = new DefaultOvsdbNode(host, + IpAddress.valueOf(ipPort[0]), + TpPort.tpPort(Integer.parseInt(ipPort[1])), + DeviceId.deviceId(bridgeId)); + service.addNode(ovsdb); + } +} diff --git a/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/cli/OvsdbNodeConnectCommand.java b/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/cli/OvsdbNodeConnectCommand.java new file mode 100644 index 00000000..e4ca0f3c --- /dev/null +++ b/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/cli/OvsdbNodeConnectCommand.java @@ -0,0 +1,60 @@ +/* + * Copyright 2015 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.cordvtn.cli; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.cordvtn.CordVtnService; +import org.onosproject.cordvtn.OvsdbNode; + +import java.util.NoSuchElementException; + +/** + * Connects to OVSDBs. + */ +@Command(scope = "onos", name = "ovsdb-connect", + description = "Connects to OVSDBs") +public class OvsdbNodeConnectCommand extends AbstractShellCommand { + + @Argument(index = 0, name = "hosts", description = "Hostname(s) or IP(s)", + required = true, multiValued = true) + private String[] hosts = null; + + @Override + protected void execute() { + CordVtnService service = AbstractShellCommand.get(CordVtnService.class); + + for (String host : hosts) { + OvsdbNode ovsdb; + try { + ovsdb = service.getNodes().stream() + .filter(node -> node.host().equals(host)) + .findFirst().get(); + } catch (NoSuchElementException e) { + print("Unable to find %s", host); + continue; + } + + if (service.isNodeConnected(ovsdb)) { + print("OVSDB %s is already in connected state, do nothing", host); + } else { + service.connect(ovsdb); + } + } + } +} diff --git a/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/cli/OvsdbNodeDeleteCommand.java b/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/cli/OvsdbNodeDeleteCommand.java new file mode 100644 index 00000000..a500d0d8 --- /dev/null +++ b/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/cli/OvsdbNodeDeleteCommand.java @@ -0,0 +1,57 @@ +/* + * Copyright 2015 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.cordvtn.cli; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.cordvtn.CordVtnService; +import org.onosproject.cordvtn.OvsdbNode; + +import java.util.NoSuchElementException; + +/** + * Deletes OVSDB nodes from cordvtn. + */ +@Command(scope = "onos", name = "ovsdb-delete", + description = "Deletes OVSDB nodes from cordvtn") +public class OvsdbNodeDeleteCommand extends AbstractShellCommand { + + @Argument(index = 0, name = "hosts", description = "Hostname(s) or IP(s)", + required = true, multiValued = true) + private String[] hosts = null; + + @Override + protected void execute() { + CordVtnService service = AbstractShellCommand.get(CordVtnService.class); + + for (String host : hosts) { + OvsdbNode ovsdb; + try { + ovsdb = service.getNodes().stream() + .filter(node -> node.host().equals(host)) + .findFirst().get(); + + } catch (NoSuchElementException e) { + print("Unable to find %s", host); + continue; + } + + service.deleteNode(ovsdb); + } + } +} diff --git a/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/cli/OvsdbNodeDisconnectCommand.java b/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/cli/OvsdbNodeDisconnectCommand.java new file mode 100644 index 00000000..14e44e08 --- /dev/null +++ b/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/cli/OvsdbNodeDisconnectCommand.java @@ -0,0 +1,60 @@ +/* + * Copyright 2015 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.cordvtn.cli; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.cordvtn.CordVtnService; +import org.onosproject.cordvtn.OvsdbNode; + +import java.util.NoSuchElementException; + +/** + * Disconnects OVSDBs. + */ +@Command(scope = "onos", name = "ovsdb-disconnect", + description = "Disconnects OVSDBs") +public class OvsdbNodeDisconnectCommand extends AbstractShellCommand { + + @Argument(index = 0, name = "hosts", description = "Hostname(s) or IP(s)", + required = true, multiValued = true) + private String[] hosts = null; + + @Override + protected void execute() { + CordVtnService service = AbstractShellCommand.get(CordVtnService.class); + + for (String host : hosts) { + OvsdbNode ovsdb; + try { + ovsdb = service.getNodes().stream() + .filter(node -> node.host().equals(host)) + .findFirst().get(); + } catch (NoSuchElementException e) { + print("Unable to find %s", host); + continue; + } + + if (!service.isNodeConnected(ovsdb)) { + print("OVSDB %s is already in disconnected state, do nothing", host); + } else { + service.disconnect(ovsdb); + } + } + } +} diff --git a/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/cli/OvsdbNodeListCommand.java b/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/cli/OvsdbNodeListCommand.java new file mode 100644 index 00000000..7d125ca6 --- /dev/null +++ b/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/cli/OvsdbNodeListCommand.java @@ -0,0 +1,74 @@ +/* + * Copyright 2015 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.cordvtn.cli; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.cordvtn.CordVtnService; +import org.onosproject.cordvtn.OvsdbNode; + +import java.util.Collections; +import java.util.List; + +/** + * Lists all OVSDB nodes. + */ +@Command(scope = "onos", name = "ovsdbs", + description = "Lists all OVSDB nodes registered in cordvtn application") +public class OvsdbNodeListCommand extends AbstractShellCommand { + + @Override + protected void execute() { + CordVtnService service = AbstractShellCommand.get(CordVtnService.class); + List<OvsdbNode> ovsdbs = service.getNodes(); + Collections.sort(ovsdbs, OvsdbNode.OVSDB_NODE_COMPARATOR); + + if (outputJson()) { + print("%s", json(service, ovsdbs)); + } else { + for (OvsdbNode ovsdb : ovsdbs) { + print("host=%s, address=%s, br-int=%s, state=%s", + ovsdb.host(), + ovsdb.ip().toString() + ":" + ovsdb.port().toString(), + ovsdb.intBrId().toString(), + getState(service, ovsdb)); + } + print("Total %s nodes", service.getNodeCount()); + } + } + + private JsonNode json(CordVtnService service, List<OvsdbNode> ovsdbs) { + ObjectMapper mapper = new ObjectMapper(); + ArrayNode result = mapper.createArrayNode(); + for (OvsdbNode ovsdb : ovsdbs) { + String ipPort = ovsdb.ip().toString() + ":" + ovsdb.port().toString(); + result.add(mapper.createObjectNode() + .put("host", ovsdb.host()) + .put("address", ipPort) + .put("brInt", ovsdb.intBrId().toString()) + .put("state", getState(service, ovsdb))); + } + return result; + } + + private String getState(CordVtnService service, OvsdbNode ovsdb) { + return service.isNodeConnected(ovsdb) ? "CONNECTED" : "DISCONNECTED"; + } +} diff --git a/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/cli/package-info.java b/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/cli/package-info.java new file mode 100644 index 00000000..686172ce --- /dev/null +++ b/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/cli/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2015 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. + */ + +/** + * Console commands to manage OVSDB nodes for cordvtn. + */ +package org.onosproject.cordvtn.cli;
\ No newline at end of file diff --git a/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/package-info.java b/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/package-info.java new file mode 100644 index 00000000..1c13737f --- /dev/null +++ b/framework/src/onos/apps/cordvtn/src/main/java/org/onosproject/cordvtn/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2015 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. + */ + +/** + * Application for provisioning virtual tenant networks. + */ +package org.onosproject.cordvtn;
\ No newline at end of file diff --git a/framework/src/onos/apps/cordvtn/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/framework/src/onos/apps/cordvtn/src/main/resources/OSGI-INF/blueprint/shell-config.xml new file mode 100644 index 00000000..6e172387 --- /dev/null +++ b/framework/src/onos/apps/cordvtn/src/main/resources/OSGI-INF/blueprint/shell-config.xml @@ -0,0 +1,35 @@ +<!-- + ~ Copyright 2015 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. + --> +<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"> + + <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0"> + <command> + <action class="org.onosproject.cordvtn.cli.OvsdbNodeListCommand"/> + </command> + <command> + <action class="org.onosproject.cordvtn.cli.OvsdbNodeAddCommand"/> + </command> + <command> + <action class="org.onosproject.cordvtn.cli.OvsdbNodeDeleteCommand"/> + </command> + <command> + <action class="org.onosproject.cordvtn.cli.OvsdbNodeConnectCommand"/> + </command> + <command> + <action class="org.onosproject.cordvtn.cli.OvsdbNodeDisconnectCommand"/> + </command> + </command-bundle> +</blueprint> diff --git a/framework/src/onos/apps/olt/pom.xml b/framework/src/onos/apps/olt/pom.xml index 180e026a..f803a61a 100644 --- a/framework/src/onos/apps/olt/pom.xml +++ b/framework/src/onos/apps/olt/pom.xml @@ -36,6 +36,15 @@ </properties> <dependencies> + <dependency> + <groupId>org.onosproject</groupId> + <artifactId>onos-cli</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.apache.karaf.shell</groupId> + <artifactId>org.apache.karaf.shell.console</artifactId> + </dependency> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> diff --git a/framework/src/onos/apps/olt/src/main/java/org/onosproject/olt/AccessDeviceConfig.java b/framework/src/onos/apps/olt/src/main/java/org/onosproject/olt/AccessDeviceConfig.java new file mode 100644 index 00000000..90ed7403 --- /dev/null +++ b/framework/src/onos/apps/olt/src/main/java/org/onosproject/olt/AccessDeviceConfig.java @@ -0,0 +1,43 @@ +/* + * Copyright 2015 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.olt; + +import org.onlab.packet.VlanId; +import org.onosproject.net.DeviceId; +import org.onosproject.net.PortNumber; +import org.onosproject.net.config.Config; + +/** + * Config object for access device data. + */ +public class AccessDeviceConfig extends Config<DeviceId> { + + private static final String UPLINK = "uplink"; + private static final String VLAN = "vlan"; + + /** + * Gets the access device configuration for this device. + * + * @return access device configuration + */ + public AccessDeviceData getOlt() { + PortNumber uplink = PortNumber.portNumber(node.path(UPLINK).asText()); + VlanId vlan = VlanId.vlanId(Short.parseShort(node.path(VLAN).asText())); + + return new AccessDeviceData(subject(), uplink, vlan); + } +} diff --git a/framework/src/onos/apps/olt/src/main/java/org/onosproject/olt/AccessDeviceData.java b/framework/src/onos/apps/olt/src/main/java/org/onosproject/olt/AccessDeviceData.java new file mode 100644 index 00000000..f7e40e30 --- /dev/null +++ b/framework/src/onos/apps/olt/src/main/java/org/onosproject/olt/AccessDeviceData.java @@ -0,0 +1,76 @@ +/* + * Copyright 2015 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.olt; + +import org.onlab.packet.VlanId; +import org.onosproject.net.DeviceId; +import org.onosproject.net.PortNumber; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Information about an access device. + */ +public class AccessDeviceData { + private static final String DEVICE_ID_MISSING = "Device ID cannot be null"; + private static final String UPLINK_MISSING = "Uplink cannot be null"; + private static final String VLAN_MISSING = "VLAN ID cannot be null"; + + private final DeviceId deviceId; + private final PortNumber uplink; + private final VlanId vlan; + + /** + * Class constructor. + * + * @param deviceId access device ID + * @param uplink uplink port number + * @param vlan device VLAN ID + */ + public AccessDeviceData(DeviceId deviceId, PortNumber uplink, VlanId vlan) { + this.deviceId = checkNotNull(deviceId, DEVICE_ID_MISSING); + this.uplink = checkNotNull(uplink, UPLINK_MISSING); + this.vlan = checkNotNull(vlan, VLAN_MISSING); + } + + /** + * Retrieves the access device ID. + * + * @return device ID + */ + public DeviceId deviceId() { + return deviceId; + } + + /** + * Retrieves the uplink port number. + * + * @return port number + */ + public PortNumber uplink() { + return uplink; + } + + /** + * Retrieves the VLAN ID assigned to the device. + * + * @return vlan ID + */ + public VlanId vlan() { + return vlan; + } +} diff --git a/framework/src/onos/apps/olt/src/main/java/org/onosproject/olt/AccessDeviceService.java b/framework/src/onos/apps/olt/src/main/java/org/onosproject/olt/AccessDeviceService.java new file mode 100644 index 00000000..bd82f489 --- /dev/null +++ b/framework/src/onos/apps/olt/src/main/java/org/onosproject/olt/AccessDeviceService.java @@ -0,0 +1,41 @@ +/* + * Copyright 2015 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.olt; + +import org.onlab.packet.VlanId; +import org.onosproject.net.ConnectPoint; + +/** + * Service for interacting with an access device (OLT). + */ +public interface AccessDeviceService { + + /** + * Provisions connectivity for a subscriber on an access device. + * + * @param port subscriber's connection point + * @param vlan VLAN ID to provision for subscriber + */ + void provisionSubscriber(ConnectPoint port, VlanId vlan); + + /** + * Removes provisioned connectivity for a subscriber from an access device. + * + * @param port subscriber's connection point + */ + void removeSubscriber(ConnectPoint port); +} diff --git a/framework/src/onos/apps/olt/src/main/java/org/onosproject/olt/OLT.java b/framework/src/onos/apps/olt/src/main/java/org/onosproject/olt/OLT.java index c92f47a2..9aa8865a 100644 --- a/framework/src/onos/apps/olt/src/main/java/org/onosproject/olt/OLT.java +++ b/framework/src/onos/apps/olt/src/main/java/org/onosproject/olt/OLT.java @@ -15,7 +15,6 @@ */ package org.onosproject.olt; - import com.google.common.base.Strings; import org.apache.felix.scr.annotations.Activate; import org.apache.felix.scr.annotations.Component; @@ -24,13 +23,20 @@ import org.apache.felix.scr.annotations.Modified; import org.apache.felix.scr.annotations.Property; import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.ReferenceCardinality; +import org.apache.felix.scr.annotations.Service; import org.onlab.packet.VlanId; import org.onlab.util.Tools; import org.onosproject.core.ApplicationId; import org.onosproject.core.CoreService; +import org.onosproject.net.ConnectPoint; import org.onosproject.net.DeviceId; import org.onosproject.net.Port; import org.onosproject.net.PortNumber; +import org.onosproject.net.config.ConfigFactory; +import org.onosproject.net.config.NetworkConfigEvent; +import org.onosproject.net.config.NetworkConfigListener; +import org.onosproject.net.config.NetworkConfigRegistry; +import org.onosproject.net.config.basics.SubjectFactories; import org.onosproject.net.device.DeviceEvent; import org.onosproject.net.device.DeviceListener; import org.onosproject.net.device.DeviceService; @@ -45,15 +51,17 @@ import org.osgi.service.component.ComponentContext; import org.slf4j.Logger; import java.util.Dictionary; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import static org.slf4j.LoggerFactory.getLogger; /** - * Sample mobility application. Cleans up flowmods when a host moves. + * Provisions rules on access devices. */ +@Service @Component(immediate = true) -public class OLT { - +public class OLT implements AccessDeviceService { private final Logger log = getLogger(getClass()); @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) @@ -65,10 +73,14 @@ public class OLT { @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected CoreService coreService; + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected NetworkConfigRegistry networkConfig; + private final DeviceListener deviceListener = new InternalDeviceListener(); private ApplicationId appId; + private static final VlanId DEFAULT_VLAN = VlanId.vlanId((short) 0); public static final int OFFSET = 200; public static final int UPLINK_PORT = 129; @@ -94,11 +106,39 @@ public class OLT { label = "The gfast device id") private String gfastDevice = GFAST_DEVICE; + private Map<DeviceId, AccessDeviceData> oltData = new ConcurrentHashMap<>(); + + private InternalNetworkConfigListener configListener = + new InternalNetworkConfigListener(); + private static final Class<AccessDeviceConfig> CONFIG_CLASS = + AccessDeviceConfig.class; + + private ConfigFactory<DeviceId, AccessDeviceConfig> configFactory = + new ConfigFactory<DeviceId, AccessDeviceConfig>( + SubjectFactories.DEVICE_SUBJECT_FACTORY, CONFIG_CLASS, "accessDevice") { + @Override + public AccessDeviceConfig createConfig() { + return new AccessDeviceConfig(); + } + }; @Activate public void activate() { appId = coreService.registerApplication("org.onosproject.olt"); + networkConfig.registerConfigFactory(configFactory); + networkConfig.addListener(configListener); + + networkConfig.getSubjects(DeviceId.class, AccessDeviceConfig.class).forEach( + subject -> { + AccessDeviceConfig config = networkConfig.getConfig(subject, AccessDeviceConfig.class); + if (config != null) { + AccessDeviceData data = config.getOlt(); + oltData.put(data.deviceId(), data); + } + } + ); + /*deviceService.addListener(deviceListener); deviceService.getPorts(DeviceId.deviceId(oltDevice)).stream().forEach( @@ -129,6 +169,8 @@ public class OLT { @Deactivate public void deactivate() { + networkConfig.removeListener(configListener); + networkConfig.unregisterConfigFactory(configFactory); log.info("Stopped"); } @@ -136,16 +178,13 @@ public class OLT { public void modified(ComponentContext context) { Dictionary<?, ?> properties = context.getProperties(); - String s = Tools.get(properties, "uplinkPort"); uplinkPort = Strings.isNullOrEmpty(s) ? UPLINK_PORT : Integer.parseInt(s); s = Tools.get(properties, "oltDevice"); oltDevice = Strings.isNullOrEmpty(s) ? OLT_DEVICE : s; - } - private short fetchVlanId(PortNumber port) { long p = port.toLong() + OFFSET; if (p > 4095) { @@ -155,7 +194,6 @@ public class OLT { return (short) p; } - private void provisionVlanOnPort(String deviceId, int uplinkPort, PortNumber p, short vlanId) { DeviceId did = DeviceId.deviceId(deviceId); @@ -198,7 +236,73 @@ public class OLT { flowObjectiveService.forward(did, upFwd); flowObjectiveService.forward(did, downFwd); + } + + @Override + public void provisionSubscriber(ConnectPoint port, VlanId vlan) { + AccessDeviceData olt = oltData.get(port.deviceId()); + + if (olt == null) { + log.warn("No data found for OLT device {}", port.deviceId()); + return; + } + + provisionVlans(olt.deviceId(), olt.uplink(), port.port(), vlan, olt.vlan()); + } + + private void provisionVlans(DeviceId deviceId, PortNumber uplinkPort, + PortNumber subscriberPort, + VlanId subscriberVlan, VlanId deviceVlan) { + + TrafficSelector upstream = DefaultTrafficSelector.builder() + .matchVlanId(DEFAULT_VLAN) + .matchInPort(subscriberPort) + .build(); + + TrafficSelector downstream = DefaultTrafficSelector.builder() + .matchVlanId(deviceVlan) + .matchInPort(uplinkPort) + .build(); + + TrafficTreatment upstreamTreatment = DefaultTrafficTreatment.builder() + .setVlanId(subscriberVlan) + .pushVlan() + .setVlanId(deviceVlan) + .setOutput(uplinkPort) + .build(); + TrafficTreatment downstreamTreatment = DefaultTrafficTreatment.builder() + .popVlan() + .setVlanId(DEFAULT_VLAN) + .setOutput(subscriberPort) + .build(); + + + ForwardingObjective upFwd = DefaultForwardingObjective.builder() + .withFlag(ForwardingObjective.Flag.VERSATILE) + .withPriority(1000) + .makePermanent() + .withSelector(upstream) + .fromApp(appId) + .withTreatment(upstreamTreatment) + .add(); + + ForwardingObjective downFwd = DefaultForwardingObjective.builder() + .withFlag(ForwardingObjective.Flag.VERSATILE) + .withPriority(1000) + .makePermanent() + .withSelector(downstream) + .fromApp(appId) + .withTreatment(downstreamTreatment) + .add(); + + flowObjectiveService.forward(deviceId, upFwd); + flowObjectiveService.forward(deviceId, downFwd); + } + + @Override + public void removeSubscriber(ConnectPoint port) { + throw new UnsupportedOperationException("Not yet implemented"); } private class InternalDeviceListener implements DeviceListener { @@ -226,7 +330,27 @@ public class OLT { } } + private class InternalNetworkConfigListener implements NetworkConfigListener { + @Override + public void event(NetworkConfigEvent event) { + switch (event.type()) { -} - + case CONFIG_ADDED: + case CONFIG_UPDATED: + if (event.configClass().equals(CONFIG_CLASS)) { + AccessDeviceConfig config = + networkConfig.getConfig((DeviceId) event.subject(), CONFIG_CLASS); + if (config != null) { + oltData.put(config.getOlt().deviceId(), config.getOlt()); + } + } + break; + case CONFIG_UNREGISTERED: + case CONFIG_REMOVED: + default: + break; + } + } + } +} diff --git a/framework/src/onos/apps/olt/src/main/java/org/onosproject/olt/SubscriberAddCommand.java b/framework/src/onos/apps/olt/src/main/java/org/onosproject/olt/SubscriberAddCommand.java new file mode 100644 index 00000000..d9b4559b --- /dev/null +++ b/framework/src/onos/apps/olt/src/main/java/org/onosproject/olt/SubscriberAddCommand.java @@ -0,0 +1,58 @@ +/* + * Copyright 2015 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.olt; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onlab.packet.VlanId; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DeviceId; +import org.onosproject.net.PortNumber; + +/** + * Adds a subscriber to an access device. + */ +@Command(scope = "onos", name = "add-subscriber-access", + description = "Adds a subscriber to an access device") +public class SubscriberAddCommand extends AbstractShellCommand { + + @Argument(index = 0, name = "deviceId", description = "Access device ID", + required = true, multiValued = false) + private String strDeviceId = null; + + @Argument(index = 1, name = "port", description = "Subscriber port number", + required = true, multiValued = false) + private String strPort = null; + + @Argument(index = 2, name = "vlanId", + description = "VLAN ID to add", + required = true, multiValued = false) + private String strVlanId = null; + + @Override + protected void execute() { + AccessDeviceService service = AbstractShellCommand.get(AccessDeviceService.class); + + DeviceId deviceId = DeviceId.deviceId(strDeviceId); + PortNumber port = PortNumber.portNumber(strPort); + VlanId vlan = VlanId.vlanId(Short.parseShort(strVlanId)); + ConnectPoint connectPoint = new ConnectPoint(deviceId, port); + + service.provisionSubscriber(connectPoint, vlan); + } +} diff --git a/framework/src/onos/apps/olt/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/framework/src/onos/apps/olt/src/main/resources/OSGI-INF/blueprint/shell-config.xml new file mode 100644 index 00000000..00ebe9d1 --- /dev/null +++ b/framework/src/onos/apps/olt/src/main/resources/OSGI-INF/blueprint/shell-config.xml @@ -0,0 +1,29 @@ +<!-- + ~ Copyright 2015 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. + --> +<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"> + + <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0"> + <command> + <action class="org.onosproject.olt.SubscriberAddCommand"/> + <completers> + <ref component-id="deviceIdCompleter"/> + <null/> + </completers> + </command> + </command-bundle> + + <bean id="deviceIdCompleter" class="org.onosproject.cli.net.DeviceIdCompleter"/> +</blueprint> diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java index 8b447af4..40ee55fc 100644 --- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java +++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java @@ -93,7 +93,7 @@ public class DefaultRoutingHandler { try { populationStatus = Status.STARTED; rulePopulator.resetCounter(); - log.info("Starts to populate routing rules"); + log.info("Starting to populate segment-routing rules"); log.debug("populateAllRoutingRules: populationStatus is STARTED"); for (Device sw : srManager.deviceService.getDevices()) { @@ -117,7 +117,7 @@ public class DefaultRoutingHandler { log.debug("populateAllRoutingRules: populationStatus is SUCCEEDED"); populationStatus = Status.SUCCEEDED; - log.info("Completes routing rule population. Total # of rules pushed : {}", + log.info("Completed routing rule population. Total # of rules pushed : {}", rulePopulator.getCounter()); return true; } finally { @@ -426,7 +426,7 @@ public class DefaultRoutingHandler { .get(itrIdx); for (DeviceId targetSw : swViaMap.keySet()) { Set<DeviceId> nextHops = new HashSet<>(); - + log.debug("** Iter: {} root: {} target: {}", itrIdx, destSw, targetSw); for (ArrayList<DeviceId> via : swViaMap.get(targetSw)) { if (via.isEmpty()) { nextHops.add(destSw); @@ -456,7 +456,7 @@ public class DefaultRoutingHandler { // rule for both subnet and router IP. if (config.isEdgeDevice(targetSw) && config.isEdgeDevice(destSw)) { List<Ip4Prefix> subnets = config.getSubnets(destSw); - log.debug("populateEcmpRoutingRulePartial in device {} towards {} for subnets {}", + log.debug("* populateEcmpRoutingRulePartial in device {} towards {} for subnets {}", targetSw, destSw, subnets); result = rulePopulator.populateIpRuleForSubnet(targetSw, subnets, @@ -468,7 +468,7 @@ public class DefaultRoutingHandler { Ip4Address routerIp = config.getRouterIp(destSw); IpPrefix routerIpPrefix = IpPrefix.valueOf(routerIp, IpPrefix.MAX_INET_MASK_LENGTH); - log.debug("populateEcmpRoutingRulePartial in device {} towards {} for router IP {}", + log.debug("* populateEcmpRoutingRulePartial in device {} towards {} for router IP {}", targetSw, destSw, routerIpPrefix); result = rulePopulator.populateIpRuleForRouter(targetSw, routerIpPrefix, destSw, nextHops); if (!result) { @@ -479,7 +479,7 @@ public class DefaultRoutingHandler { } else if (config.isEdgeDevice(targetSw)) { Ip4Address routerIp = config.getRouterIp(destSw); IpPrefix routerIpPrefix = IpPrefix.valueOf(routerIp, IpPrefix.MAX_INET_MASK_LENGTH); - log.debug("populateEcmpRoutingRulePartial in device {} towards {} for router IP {}", + log.debug("* populateEcmpRoutingRulePartial in device {} towards {} for router IP {}", targetSw, destSw, routerIpPrefix); result = rulePopulator.populateIpRuleForRouter(targetSw, routerIpPrefix, destSw, nextHops); if (!result) { @@ -488,7 +488,7 @@ public class DefaultRoutingHandler { } // Populates MPLS rules to all routers - log.debug("populateEcmpRoutingRulePartial in device{} towards {} for all MPLS rules", + log.debug("* populateEcmpRoutingRulePartial in device{} towards {} for all MPLS rules", targetSw, destSw); result = rulePopulator.populateMplsRule(targetSw, destSw, nextHops); if (!result) { @@ -500,7 +500,7 @@ public class DefaultRoutingHandler { /** * Populates table miss entries for all tables, and pipeline rules for VLAN - * and TACM tables. + * and TCAM tables. XXX rename/rethink * * @param deviceId Switch ID to set the rules */ @@ -534,6 +534,8 @@ public class DefaultRoutingHandler { /** * Resume the flow rule population process if it was aborted for any reason. * Mostly the process is aborted when the groups required are not set yet. + * XXX is this called? + * */ public void resumePopulationProcess() { statusLock.lock(); diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DeviceConfiguration.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DeviceConfiguration.java index eef1b147..0bc155b8 100644 --- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DeviceConfiguration.java +++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DeviceConfiguration.java @@ -134,7 +134,7 @@ public class DeviceConfiguration implements DeviceProperties { @Override public int getSegmentId(DeviceId deviceId) { if (deviceConfigMap.get(deviceId) != null) { - log.debug("getSegmentId for device{} is {}", + log.trace("getSegmentId for device{} is {}", deviceId, deviceConfigMap.get(deviceId).nodeSid); return deviceConfigMap.get(deviceId).nodeSid; @@ -189,7 +189,7 @@ public class DeviceConfiguration implements DeviceProperties { @Override public MacAddress getDeviceMac(DeviceId deviceId) { if (deviceConfigMap.get(deviceId) != null) { - log.debug("getDeviceMac for device{} is {}", + log.trace("getDeviceMac for device{} is {}", deviceId, deviceConfigMap.get(deviceId).mac); return deviceConfigMap.get(deviceId).mac; @@ -209,7 +209,7 @@ public class DeviceConfiguration implements DeviceProperties { */ public Ip4Address getRouterIp(DeviceId deviceId) { if (deviceConfigMap.get(deviceId) != null) { - log.debug("getDeviceIp for device{} is {}", + log.trace("getDeviceIp for device{} is {}", deviceId, deviceConfigMap.get(deviceId).ip); return deviceConfigMap.get(deviceId).ip; @@ -231,7 +231,7 @@ public class DeviceConfiguration implements DeviceProperties { @Override public boolean isEdgeDevice(DeviceId deviceId) { if (deviceConfigMap.get(deviceId) != null) { - log.debug("isEdgeDevice for device{} is {}", + log.trace("isEdgeDevice for device{} is {}", deviceId, deviceConfigMap.get(deviceId).isEdge); return deviceConfigMap.get(deviceId).isEdge; @@ -297,7 +297,7 @@ public class DeviceConfiguration implements DeviceProperties { */ public List<Ip4Address> getSubnetGatewayIps(DeviceId deviceId) { if (deviceConfigMap.get(deviceId) != null) { - log.debug("getSubnetGatewayIps for device{} is {}", + log.trace("getSubnetGatewayIps for device{} is {}", deviceId, deviceConfigMap.get(deviceId).gatewayIps.values()); return new ArrayList<>(deviceConfigMap.get(deviceId).gatewayIps.values()); @@ -314,7 +314,7 @@ public class DeviceConfiguration implements DeviceProperties { */ public List<Ip4Prefix> getSubnets(DeviceId deviceId) { if (deviceConfigMap.get(deviceId) != null) { - log.debug("getSubnets for device{} is {}", + log.trace("getSubnets for device{} is {}", deviceId, deviceConfigMap.get(deviceId).subnets.values()); return new ArrayList<>(deviceConfigMap.get(deviceId).subnets.values()); diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/ECMPShortestPathGraph.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/ECMPShortestPathGraph.java index 2e2041c4..e9a59bae 100644 --- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/ECMPShortestPathGraph.java +++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/ECMPShortestPathGraph.java @@ -31,7 +31,7 @@ import java.util.List; /** * This class creates bandwidth constrained breadth first tree and returns paths - * from root Device to leaf Devicees which satisfies the bandwidth condition. If + * from root Device to leaf Devices which satisfies the bandwidth condition. If * bandwidth parameter is not specified, the normal breadth first tree will be * calculated. The paths are snapshot paths at the point of the class * instantiation. @@ -281,7 +281,7 @@ public class ECMPShortestPathGraph { * Return the complete info of the computed ECMP paths for each Device * learned in multiple iterations from the root Device. * - * @return the hash table of Devicees learned in multiple Dijkstra + * @return the hash table of Devices learned in multiple Dijkstra * iterations and corresponding ECMP paths to it from the root * Device */ @@ -305,8 +305,8 @@ public class ECMPShortestPathGraph { * Return the complete info of the computed ECMP paths for each Device * learned in multiple iterations from the root Device. * - * @return the hash table of Devicees learned in multiple Dijkstra - * iterations and corresponding ECMP paths in terms of Devicees to + * @return the hash table of Devices learned in multiple Dijkstra + * iterations and corresponding ECMP paths in terms of Devices to * be traversed to it from the root Device */ public HashMap<Integer, HashMap<DeviceId, diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IpHandler.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IpHandler.java index e37fe52a..14ce679b 100644 --- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IpHandler.java +++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IpHandler.java @@ -115,7 +115,7 @@ public class IpHandler { /** * Forwards IP packets in the buffer to the destination IP address. * It is called when the controller finds the destination MAC address - * via ARP responsees. + * via ARP responses. * * @param deviceId switch device ID * @param destIpAddress destination IP address diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java index d802be91..7641571d 100644 --- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java +++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java @@ -150,7 +150,7 @@ public class RoutingRulePopulator { /** * Populates IP flow rules for the router IP address. * - * @param deviceId device ID to set the rules + * @param deviceId target device ID to set the rules * @param ipPrefix the IP address of the destination router * @param destSw device ID of the destination router * @param nextHops next hop switch ID list @@ -210,9 +210,9 @@ public class RoutingRulePopulator { } /** - * Populates MPLS flow rules to all transit routers. + * Populates MPLS flow rules to all routers. * - * @param deviceId device ID of the switch to set the rules + * @param deviceId target device ID of the switch to set the rules * @param destSwId destination switch device ID * @param nextHops next hops switch ID list * @return true if all rules are set successfully, false otherwise @@ -379,7 +379,7 @@ public class RoutingRulePopulator { .addCondition(Criteria.matchEthDst(config .getDeviceMac(deviceId))); fob.permit().fromApp(srManager.appId); - log.debug("populateTableVlan: Installing filtering objective for router mac"); + log.debug("populateTableTMac: Installing filtering objective for router mac"); srManager.flowObjectiveService. filter(deviceId, fob.add(new SRObjectiveContext(deviceId, diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java index 9011160c..eb2cf569 100644 --- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java +++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java @@ -296,7 +296,8 @@ public class SegmentRoutingManager implements SegmentRoutingService { } /** - * Returns the GrouopKey object for the device and the NighborSet given. + * Returns the GroupKey object for the device and the NeighborSet given. + * XXX is this called * * @param ns NeightborSet object for the GroupKey * @return GroupKey object for the NeighborSet diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultEdgeGroupHandler.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultEdgeGroupHandler.java index 3dc312df..c960adca 100644 --- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultEdgeGroupHandler.java +++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultEdgeGroupHandler.java @@ -35,13 +35,14 @@ import org.onosproject.store.service.EventuallyConsistentMap; * where D0 and D3 are edge devices and D1 and D2 are transit devices. * Assume device D0 is connected to 2 neighbors (D1 and D2 ). * The following groups will be created in D0: - * 1) all ports to D1 + with no label push, - * 2) all ports to D1 + with label 102 pushed, - * 3) all ports to D1 + with label 103 pushed, + * 1) all ports to D1 + with no label push, // direct attach case, seen + * 2) all ports to D1 + with label 102 pushed, // this is not needed + * 3) all ports to D1 + with label 103 pushed, // maybe needed, sometimes seen * 4) all ports to D2 + with no label push, * 5) all ports to D2 + with label 101 pushed, * 6) all ports to D2 + with label 103 pushed, - * 7) all ports to D1 and D2 + with label 103 pushed + * 7) all ports to D1 and D2 + with label 103 pushed // ecmp case + * 8) what about ecmp no label case */ public class DefaultEdgeGroupHandler extends DefaultGroupHandler { diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/virtualport/VirtualPortService.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/virtualport/VirtualPortService.java index 05ebccf9..0a3ea2cd 100644 --- a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/virtualport/VirtualPortService.java +++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/virtualport/VirtualPortService.java @@ -18,6 +18,7 @@ package org.onosproject.vtnrsc.virtualport; import java.util.Collection; import org.onosproject.net.DeviceId; +import org.onosproject.vtnrsc.FixedIp; import org.onosproject.vtnrsc.TenantId; import org.onosproject.vtnrsc.TenantNetworkId; import org.onosproject.vtnrsc.VirtualPort; @@ -44,6 +45,14 @@ public interface VirtualPortService { VirtualPort getPort(VirtualPortId virtualPortId); /** + * Returns the virtualPort associated with the fixedIP. + * + * @param fixedIP the fixedIP identifier + * @return virtualPort. + */ + VirtualPort getPort(FixedIp fixedIP); + + /** * Returns the collection of the currently known virtualPort. * @return collection of VirtualPort. */ diff --git a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/virtualport/impl/VirtualPortManager.java b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/virtualport/impl/VirtualPortManager.java index 926809c9..c45373b9 100644 --- a/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/virtualport/impl/VirtualPortManager.java +++ b/framework/src/onos/apps/vtn/vtnrsc/src/main/java/org/onosproject/vtnrsc/virtualport/impl/VirtualPortManager.java @@ -17,9 +17,12 @@ package org.onosproject.vtnrsc.virtualport.impl; import static com.google.common.base.Preconditions.checkNotNull; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -68,6 +71,7 @@ public class VirtualPortManager implements VirtualPortService { private static final String TENANTID_NOT_NULL = "TenantId cannot be null"; private static final String NETWORKID_NOT_NULL = "NetworkId cannot be null"; private static final String DEVICEID_NOT_NULL = "DeviceId cannot be null"; + private static final String FIXEDIP_NOT_NULL = "FixedIp cannot be null"; protected Map<VirtualPortId, VirtualPort> vPortStore; protected ApplicationId appId; @@ -125,6 +129,25 @@ public class VirtualPortManager implements VirtualPortService { } @Override + public VirtualPort getPort(FixedIp fixedIP) { + checkNotNull(fixedIP, FIXEDIP_NOT_NULL); + List<VirtualPort> vPorts = new ArrayList<>(); + vPortStore.values().stream().forEach(p -> { + Iterator<FixedIp> fixedIps = p.fixedIps().iterator(); + while (fixedIps.hasNext()) { + if (fixedIps.next().equals(fixedIP)) { + vPorts.add(p); + break; + } + } + }); + if (vPorts.size() == 0) { + return null; + } + return vPorts.get(0); + } + + @Override public Collection<VirtualPort> getPorts() { return Collections.unmodifiableCollection(vPortStore.values()); } diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/ConnectivityIntentCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/ConnectivityIntentCommand.java index 6c33f45c..62cf042a 100644 --- a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/ConnectivityIntentCommand.java +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/ConnectivityIntentCommand.java @@ -166,6 +166,10 @@ public abstract class ConnectivityIntentCommand extends AbstractShellCommand { required = false, multiValued = false) private String pushVlan = null; + @Option(name = "--setQueue", description = "Set Queue ID", + required = false, multiValued = false) + private String setQueue = null; + // Priorities @Option(name = "-p", aliases = "--priority", description = "Priority", required = false, multiValued = false) @@ -327,6 +331,10 @@ public abstract class ConnectivityIntentCommand extends AbstractShellCommand { treatmentBuilder.setVlanId(VlanId.vlanId(Short.parseShort(pushVlan))); emptyTreatment = false; } + if (!isNullOrEmpty(setQueue)) { + treatmentBuilder.setQueue(Long.parseLong(setQueue)); + emptyTreatment = false; + } if (emptyTreatment) { return DefaultTrafficTreatment.emptyTreatment(); diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/InterfaceAddCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/InterfaceAddCommand.java index eefb711a..4fd9b0df 100644 --- a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/InterfaceAddCommand.java +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/InterfaceAddCommand.java @@ -43,7 +43,7 @@ public class InterfaceAddCommand extends AbstractShellCommand { @Option(name = "-m", aliases = "--mac", description = "MAC address of the interface", - required = true, multiValued = false) + required = false, multiValued = false) private String mac = null; @Option(name = "-i", aliases = "--ip", @@ -68,10 +68,12 @@ public class InterfaceAddCommand extends AbstractShellCommand { } } + MacAddress macAddr = mac == null ? null : MacAddress.valueOf(mac); + VlanId vlanId = vlan == null ? VlanId.NONE : VlanId.vlanId(Short.parseShort(vlan)); Interface intf = new Interface(ConnectPoint.deviceConnectPoint(connectPoint), - ipAddresses, MacAddress.valueOf(mac), vlanId); + ipAddresses, macAddr, vlanId); interfaceService.add(intf); } diff --git a/framework/src/onos/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/framework/src/onos/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml index 28461e27..cf76febe 100644 --- a/framework/src/onos/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml +++ b/framework/src/onos/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml @@ -146,6 +146,8 @@ <action class="org.onosproject.cli.net.AnnotateDeviceCommand"/> <completers> <ref component-id="deviceIdCompleter"/> + <null/> + <null/> </completers> </command> diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java index a628725c..6174cef6 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java @@ -237,6 +237,7 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { case NOACTION: case OUTPUT: case GROUP: + case QUEUE: case L0MODIFICATION: case L2MODIFICATION: case L3MODIFICATION: @@ -381,6 +382,11 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { } @Override + public Builder setQueue(long queueId) { + return add(Instructions.setQueue(queueId)); + } + + @Override public TrafficTreatment.Builder meter(MeterId meterId) { return add(Instructions.meterTraffic(meterId)); } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java index 33753afa..c7fe8b85 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java @@ -190,14 +190,14 @@ public interface TrafficTreatment { /** * Push MPLS ether type. * - * @return a treatment builder. + * @return a treatment builder */ Builder pushMpls(); /** * Pops MPLS ether type. * - * @return a treatment builder. + * @return a treatment builder */ Builder popMpls(); @@ -205,7 +205,7 @@ public interface TrafficTreatment { * Pops MPLS ether type and set the new ethertype. * * @param etherType an ether type - * @return a treatment builder. + * @return a treatment builder * @deprecated in Drake Release */ @Deprecated @@ -215,22 +215,22 @@ public interface TrafficTreatment { * Pops MPLS ether type and set the new ethertype. * * @param etherType an ether type - * @return a treatment builder. + * @return a treatment builder */ Builder popMpls(EthType etherType); /** * Sets the mpls label. * - * @param mplsLabel MPLS label. - * @return a treatment builder. + * @param mplsLabel MPLS label + * @return a treatment builder */ Builder setMpls(MplsLabel mplsLabel); /** * Sets the mpls bottom-of-stack indicator bit. * - * @param mplsBos boolean to set BOS=1 (true) or BOS=0 (false). + * @param mplsBos boolean to set BOS=1 (true) or BOS=0 (false) * @return a treatment builder. */ Builder setMplsBos(boolean mplsBos); @@ -261,6 +261,14 @@ public interface TrafficTreatment { Builder group(GroupId groupId); /** + * Sets the Queue ID. + * + * @param queueId a queue ID + * @return a treatment builder + */ + Builder setQueue(long queueId); + + /** * Sets a meter to be used by this flow. * * @param meterId a meter id @@ -280,14 +288,14 @@ public interface TrafficTreatment { /** * Pops outermost VLAN tag. * - * @return a treatment builder. + * @return a treatment builder */ Builder popVlan(); /** * Pushes a new VLAN tag. * - * @return a treatment builder. + * @return a treatment builder */ Builder pushVlan(); @@ -327,8 +335,8 @@ public interface TrafficTreatment { /** * Sets the tunnel id. * - * @param tunnelId a tunnel id. - * @return a treatment builder. + * @param tunnelId a tunnel id + * @return a treatment builder */ Builder setTunnelId(long tunnelId); diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/ArpPaCriterion.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/ArpPaCriterion.java new file mode 100644 index 00000000..ba5a03d8 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/ArpPaCriterion.java @@ -0,0 +1,80 @@ +/* + * Copyright 2015 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.net.flow.criteria; + +import static com.google.common.base.MoreObjects.toStringHelper; + +import java.util.Objects; + +import org.onlab.packet.Ip4Address; + +/** + * Implementation of arp spa or tpa address criterion. + */ +public final class ArpPaCriterion implements Criterion { + private final Ip4Address ip; + private final Type type; + + /** + * Constructor. + * + * @param ip the Ip4 Address to match. + * @param type the match type. Should be one of the following: + * Type.ARP_SPA, Type.ARP_TPA + */ + ArpPaCriterion(Ip4Address ip, Type type) { + this.ip = ip; + this.type = type; + } + + @Override + public Type type() { + return this.type; + } + + /** + * Gets the Ip4 Address to match. + * + * @return the Ip4 Address to match + */ + public Ip4Address ip() { + return this.ip; + } + + @Override + public String toString() { + return toStringHelper(type().toString()) + .add("ip", ip).toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type().ordinal(), ip); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof ArpPaCriterion) { + ArpPaCriterion that = (ArpPaCriterion) obj; + return Objects.equals(ip, that.ip) && + Objects.equals(type, that.type); + } + return false; + } +}
\ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/Criteria.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/Criteria.java index ae940bdc..778d50a5 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/Criteria.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/Criteria.java @@ -16,6 +16,7 @@ package org.onosproject.net.flow.criteria; import org.onlab.packet.EthType; +import org.onlab.packet.Ip4Address; import org.onlab.packet.Ip6Address; import org.onlab.packet.IpPrefix; import org.onlab.packet.MacAddress; @@ -25,11 +26,11 @@ import org.onlab.packet.VlanId; import org.onosproject.net.IndexedLambda; import org.onosproject.net.Lambda; import org.onosproject.net.OchSignal; +import org.onosproject.net.OchSignalType; import org.onosproject.net.OduSignalId; import org.onosproject.net.OduSignalType; import org.onosproject.net.PortNumber; import org.onosproject.net.flow.criteria.Criterion.Type; -import org.onosproject.net.OchSignalType; /** * Factory class to create various traffic selection criteria. @@ -508,6 +509,16 @@ public final class Criteria { return new OduSignalTypeCriterion(signalType); } + /** + * Creates a match on IPv4 source field using the specified value. + * + * @param ip ipv4 source value + * @return match criterion + */ + public static Criterion matchArpTpa(Ip4Address ip) { + return new ArpPaCriterion(ip, Type.ARP_TPA); + } + public static Criterion dummy() { return new DummyCriterion(); } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instruction.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instruction.java index eddbbb71..2f6a1cc1 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instruction.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instruction.java @@ -49,6 +49,12 @@ public interface Instruction { GROUP, /** + * Signifies that the traffic should be enqueued to an already-configured + queue on a port. + */ + QUEUE, + + /** * Signifies that traffic should be metered according to a meter. */ METER, diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java index 26981e5e..8868bf7c 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java @@ -94,6 +94,17 @@ public final class Instructions { return new GroupInstruction(groupId); } + /** + * Creates a set-queue instruction. + * + * @param queueId Queue Id + * @return set-queue instruction + */ + public static SetQueueInstruction setQueue(final long queueId) { + checkNotNull(queueId, "queue ID cannot be null"); + return new SetQueueInstruction(queueId); + } + public static MeterInstruction meterTraffic(final MeterId meterId) { checkNotNull(meterId, "meter id cannot be null"); return new MeterInstruction(meterId); @@ -625,6 +636,50 @@ public final class Instructions { } /** + * Set-Queue Instruction. + */ + public static final class SetQueueInstruction implements Instruction { + private final long queueId; + + private SetQueueInstruction(long queueId) { + this.queueId = queueId; + } + + public long queueId() { + return queueId; + } + + @Override + public Type type() { + return Type.QUEUE; + } + + @Override + public String toString() { + return toStringHelper(type().toString()) + .add("queueId", queueId).toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type().ordinal(), queueId); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof SetQueueInstruction) { + SetQueueInstruction that = (SetQueueInstruction) obj; + return Objects.equals(queueId, that.queueId); + + } + return false; + } + } + + /** * A meter instruction. */ public static final class MeterInstruction implements Instruction { diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/DeviceHighlight.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/DeviceHighlight.java index 0ce6592c..0cc15475 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/DeviceHighlight.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/DeviceHighlight.java @@ -17,16 +17,16 @@ package org.onosproject.ui.topo; /** - * Denotes the highlighting to apply to a device. + * Denotes the highlighting to be applied to a device. */ public class DeviceHighlight extends NodeHighlight { + /** + * Constructs a device highlight entity. + * + * @param deviceId the device identifier + */ public DeviceHighlight(String deviceId) { super(TopoElementType.DEVICE, deviceId); } - - // TODO: implement device highlighting: - // - visual highlight - // - badging - } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/NodeBadge.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/NodeBadge.java new file mode 100644 index 00000000..7b517111 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/NodeBadge.java @@ -0,0 +1,220 @@ +/* + * Copyright 2015 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.ui.topo; + +/** + * Designates a badge to be applied to a node in the topology view. + */ +public final class NodeBadge { + + private static final String EMPTY = ""; + + /** Designates the badge status. */ + public enum Status { + INFO("i"), + WARN("w"), + ERROR("e"); + + private String code; + + Status(String code) { + this.code = code; + } + + @Override + public String toString() { + return "{" + code + "}"; + } + + /** Returns the status code in string form. */ + public String code() { + return code; + } + } + + private final Status status; + private final boolean isGlyph; + private final String text; + private final String message; + + // only instantiated through static methods. + private NodeBadge(Status status, boolean isGlyph, String text, String message) { + this.status = status == null ? Status.INFO : status; + this.isGlyph = isGlyph; + this.text = text; + this.message = message; + } + + @Override + public String toString() { + return "{Badge " + status + + " (" + text + ")" + + (isGlyph ? "*G " : " ") + + "\"" + message + "\"}"; + } + + /** + * Returns the badge status. + * + * @return badge status + */ + public Status status() { + return status; + } + + /** + * Returns true if the text for this badge designates a glyph ID. + * + * @return true if badge uses glyph + */ + public boolean isGlyph() { + return isGlyph; + } + + /** + * Returns the text for the badge. + * Note that if {@link #isGlyph} is true, the text is a glyph ID, otherwise + * the text is displayed verbatim in the badge. + * + * @return text for badge + */ + public String text() { + return text; + } + + /** + * Returns the message associated with the badge. + * + * @return associated message + */ + public String message() { + return message; + } + + private static String nonNull(String s) { + return s == null ? EMPTY : s; + } + + /** + * Returns an arbitrary text badge, with default status. + * + * @param txt the text + * @return node badge to display text + */ + public static NodeBadge text(String txt) { + // TODO: consider length constraint on txt (3 chars?) + return new NodeBadge(Status.INFO, false, nonNull(txt), null); + } + + /** + * Returns a glyph badge, with default status. + * + * @param gid the glyph ID + * @return node badge to display glyph + */ + public static NodeBadge glyph(String gid) { + return new NodeBadge(Status.INFO, true, nonNull(gid), null); + } + + /** + * Returns a numeric badge, with default status. + * + * @param n the number + * @return node badge to display a number + */ + public static NodeBadge number(int n) { + // TODO: consider constraints, e.g. 1 <= n <= 999 + return new NodeBadge(Status.INFO, false, Integer.toString(n), null); + } + + /** + * Returns an arbitrary text badge, with the given status. + * + * @param s the status + * @param txt the text + * @return node badge to display text + */ + public static NodeBadge text(Status s, String txt) { + // TODO: consider length constraint on txt (3 chars?) + return new NodeBadge(s, false, nonNull(txt), null); + } + + /** + * Returns a glyph badge, with the given status. + * + * @param s the status + * @param gid the glyph ID + * @return node badge to display glyph + */ + public static NodeBadge glyph(Status s, String gid) { + return new NodeBadge(s, true, nonNull(gid), null); + } + + + /** + * Returns a numeric badge, with the given status and optional message. + * + * @param s the status + * @param n the number + * @return node badge to display a number + */ + public static NodeBadge number(Status s, int n) { + // TODO: consider constraints, e.g. 1 <= n <= 999 + return new NodeBadge(s, false, Integer.toString(n), null); + } + + /** + * Returns an arbitrary text badge, with the given status and optional + * message. + * + * @param s the status + * @param txt the text + * @param msg the optional message + * @return node badge to display text + */ + public static NodeBadge text(Status s, String txt, String msg) { + // TODO: consider length constraint on txt (3 chars?) + return new NodeBadge(s, false, nonNull(txt), msg); + } + + /** + * Returns a glyph badge, with the given status and optional message. + * + * @param s the status + * @param gid the glyph ID + * @param msg the optional message + * @return node badge to display glyph + */ + public static NodeBadge glyph(Status s, String gid, String msg) { + return new NodeBadge(s, true, nonNull(gid), msg); + } + + + /** + * Returns a numeric badge, with the given status and optional message. + * + * @param s the status + * @param n the number + * @param msg the optional message + * @return node badge to display a number + */ + public static NodeBadge number(Status s, int n, String msg) { + // TODO: consider constraints, e.g. 1 <= n <= 999 + return new NodeBadge(s, false, Integer.toString(n), msg); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/NodeHighlight.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/NodeHighlight.java index 61e10c56..69235089 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/NodeHighlight.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/NodeHighlight.java @@ -20,7 +20,34 @@ package org.onosproject.ui.topo; * Parent class of {@link DeviceHighlight} and {@link HostHighlight}. */ public abstract class NodeHighlight extends AbstractHighlight { + + private NodeBadge badge; + + /** + * Constructs a node highlight entity. + * + * @param type element type + * @param elementId element identifier + */ public NodeHighlight(TopoElementType type, String elementId) { super(type, elementId); } + + /** + * Sets the badge for this node. + * + * @param badge badge to apply + */ + public void setBadge(NodeBadge badge) { + this.badge = badge; + } + + /** + * Returns the badge for this node, if any. + * + * @return badge, or null + */ + public NodeBadge badge() { + return badge; + } } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/TopoConstants.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/TopoConstants.java index 0f42b628..e2034fa7 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/TopoConstants.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/TopoConstants.java @@ -32,14 +32,17 @@ public final class TopoConstants { public static final class Glyphs { public static final String UNKNOWN = "unknown"; public static final String BIRD = "bird"; + public static final String QUERY = "query"; public static final String NODE = "node"; public static final String SWITCH = "switch"; public static final String ROADM = "roadm"; public static final String ENDSTATION = "endstation"; public static final String ROUTER = "router"; public static final String BGP_SPEAKER = "bgpSpeaker"; + public static final String MICROWAVE = "microwave"; public static final String CHAIN = "chain"; public static final String CROWN = "crown"; + public static final String LOCK = "lock"; public static final String TOPO = "topo"; public static final String REFRESH = "refresh"; public static final String GARBAGE = "garbage"; diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/TopoJson.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/TopoJson.java index 8df03169..4030abdc 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/TopoJson.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/TopoJson.java @@ -37,6 +37,11 @@ public final class TopoJson { static final String ID = "id"; static final String LABEL = "label"; static final String CSS = "css"; + static final String BADGE = "badge"; + static final String STATUS = "status"; + static final String TXT = "txt"; + static final String GID = "gid"; + static final String MSG = "msg"; static final String TITLE = "title"; static final String TYPE = "type"; @@ -97,12 +102,26 @@ public final class TopoJson { return payload; } + private static ObjectNode json(NodeBadge b) { + ObjectNode n = objectNode() + .put(STATUS, b.status().code()) + .put(b.isGlyph() ? GID : TXT, b.text()); + if (b.message() != null) { + n.put(MSG, b.message()); + } + return n; + } + private static ObjectNode json(DeviceHighlight dh) { ObjectNode n = objectNode() .put(ID, dh.elementId()); if (dh.subdued()) { n.put(SUBDUE, true); } + NodeBadge badge = dh.badge(); + if (badge != null) { + n.set(BADGE, json(badge)); + } return n; } diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/NodeBadgeTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/NodeBadgeTest.java new file mode 100644 index 00000000..c8243695 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/NodeBadgeTest.java @@ -0,0 +1,112 @@ +/* + * Copyright 2015 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.ui.topo; + +import org.junit.Test; +import org.onosproject.ui.topo.NodeBadge.Status; + +import static org.junit.Assert.assertEquals; + +/** + * Unit tests for {@link NodeBadge}. + */ +public class NodeBadgeTest { + + private static final String MSG = "a msg"; + private static final String TXT = "text"; + private static final String GID = "glyph-id"; + private static final int NUM = 42; + private static final String NUM_STR = Integer.toString(NUM); + + private static final String WR_S = "wrong status"; + private static final String WR_B = "wrong boolean"; + private static final String WR_T = "wrong text"; + private static final String WR_M = "wrong message"; + private static final String WR_SF = "wrong string format"; + + private NodeBadge badge; + + private void checkFields(NodeBadge b, Status s, boolean g, + String txt, String msg) { + assertEquals(WR_S, s, b.status()); + assertEquals(WR_B, g, b.isGlyph()); + assertEquals(WR_T, txt, b.text()); + assertEquals(WR_M, msg, b.message()); + } + + @Test + public void badgeTypes() { + assertEquals(WR_SF, "i", Status.INFO.code()); + assertEquals(WR_SF, "w", Status.WARN.code()); + assertEquals(WR_SF, "e", Status.ERROR.code()); + assertEquals("unexpected size", 3, Status.values().length); + } + + @Test + public void textOnly() { + badge = NodeBadge.text(TXT); + checkFields(badge, Status.INFO, false, TXT, null); + } + + @Test + public void glyphOnly() { + badge = NodeBadge.glyph(GID); + checkFields(badge, Status.INFO, true, GID, null); + } + + @Test + public void numberOnly() { + badge = NodeBadge.number(NUM); + checkFields(badge, Status.INFO, false, NUM_STR, null); + } + + @Test + public void textInfo() { + badge = NodeBadge.text(Status.INFO, TXT); + checkFields(badge, Status.INFO, false, TXT, null); + } + + @Test + public void glyphWarn() { + badge = NodeBadge.glyph(Status.WARN, GID); + checkFields(badge, Status.WARN, true, GID, null); + } + + @Test + public void numberError() { + badge = NodeBadge.number(Status.ERROR, NUM); + checkFields(badge, Status.ERROR, false, NUM_STR, null); + } + + @Test + public void textInfoMsg() { + badge = NodeBadge.text(Status.INFO, TXT, MSG); + checkFields(badge, Status.INFO, false, TXT, MSG); + } + + @Test + public void glyphWarnMsg() { + badge = NodeBadge.glyph(Status.WARN, GID, MSG); + checkFields(badge, Status.WARN, true, GID, MSG); + } + + @Test + public void numberErrorMsg() { + badge = NodeBadge.number(Status.ERROR, NUM, MSG); + checkFields(badge, Status.ERROR, false, NUM_STR, MSG); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/TopoJsonTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/TopoJsonTest.java index ac0051cd..50aabf8e 100644 --- a/framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/TopoJsonTest.java +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/TopoJsonTest.java @@ -21,14 +21,22 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import org.junit.Test; import org.onosproject.ui.JsonUtils; import org.onosproject.ui.topo.Highlights.Amount; +import org.onosproject.ui.topo.NodeBadge.Status; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; /** * Unit tests for {@link TopoJson}. */ public class TopoJsonTest { + private static final String DEV1 = "device-1"; + private static final String DEV2 = "device-2"; + private static final String SOME_MSG = "Hello there"; + private static final String GID = "glyph-ID"; + private ObjectNode payload; private void checkArrayLength(String key, int expLen) { @@ -68,4 +76,42 @@ public class TopoJsonTest { String subdue = JsonUtils.string(payload, TopoJson.SUBDUE); assertEquals("not max", "max", subdue); } + + @Test + public void badgedDevice() { + Highlights h = new Highlights(); + DeviceHighlight dh = new DeviceHighlight(DEV1); + dh.setBadge(NodeBadge.number(7)); + h.add(dh); + + dh = new DeviceHighlight(DEV2); + dh.setBadge(NodeBadge.glyph(Status.WARN, GID, SOME_MSG)); + h.add(dh); + + payload = TopoJson.json(h); +// System.out.println(payload); + + // dig into the payload, and verify the badges are set on the devices + ArrayNode a = (ArrayNode) payload.get(TopoJson.DEVICES); + + ObjectNode d = (ObjectNode) a.get(0); + assertEquals("wrong device id", DEV1, d.get(TopoJson.ID).asText()); + + ObjectNode b = (ObjectNode) d.get(TopoJson.BADGE); + assertNotNull("missing badge", b); + assertEquals("wrong status code", "i", b.get(TopoJson.STATUS).asText()); + assertEquals("wrong text", "7", b.get(TopoJson.TXT).asText()); + assertNull("glyph?", b.get(TopoJson.GID)); + assertNull("msg?", b.get(TopoJson.MSG)); + + d = (ObjectNode) a.get(1); + assertEquals("wrong device id", DEV2, d.get(TopoJson.ID).asText()); + + b = (ObjectNode) d.get(TopoJson.BADGE); + assertNotNull("missing badge", b); + assertEquals("wrong status code", "w", b.get(TopoJson.STATUS).asText()); + assertNull("text?", b.get(TopoJson.TXT)); + assertEquals("wrong text", GID, b.get(TopoJson.GID).asText()); + assertEquals("wrong message", SOME_MSG, b.get(TopoJson.MSG).asText()); + } } diff --git a/framework/src/onos/docs/internal-apps b/framework/src/onos/docs/internal-apps index 71aacd03..c930c05f 100644 --- a/framework/src/onos/docs/internal-apps +++ b/framework/src/onos/docs/internal-apps @@ -27,4 +27,5 @@ org.onosproject.vtn* org.onosproject.cord* org.onosproject.mcast* org.onosproject.mfwd* +org.onosproject.mlb* org.onosproject.igmp.impl diff --git a/framework/src/onos/docs/internal-netconf b/framework/src/onos/docs/internal-netconf index 40c159f4..161ad9cc 100644 --- a/framework/src/onos/docs/internal-netconf +++ b/framework/src/onos/docs/internal-netconf @@ -1 +1,2 @@ +org.onosproject.netconf* org.onosproject.provider.netconf* diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/CpqdOFDPA1Pipeline.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/CpqdOFDPA1Pipeline.java index f72bde09..c9ef451e 100644 --- a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/CpqdOFDPA1Pipeline.java +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/CpqdOFDPA1Pipeline.java @@ -169,7 +169,7 @@ public class CpqdOFDPA1Pipeline extends OFDPA1Pipeline { })); } - private void processAclTable() { + protected void processAclTable() { //table miss entry - catch all to executed action-set FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OLTPipeline.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OLTPipeline.java index eebb2e22..c735af3f 100644 --- a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OLTPipeline.java +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OLTPipeline.java @@ -30,7 +30,6 @@ import org.onosproject.net.device.DefaultDeviceDescription; import org.onosproject.net.device.DeviceDescription; import org.onosproject.net.device.DeviceProvider; import org.onosproject.net.device.DeviceProviderRegistry; -import org.onosproject.net.device.DeviceProviderService; import org.onosproject.net.device.DeviceService; import org.onosproject.net.driver.AbstractHandlerBehaviour; import org.onosproject.net.flow.DefaultFlowRule; @@ -86,13 +85,13 @@ public class OLTPipeline extends AbstractHandlerBehaviour implements Pipeliner { flowRuleService = serviceDirectory.get(FlowRuleService.class); coreService = serviceDirectory.get(CoreService.class); - try { + /*try { DeviceProviderService providerService = registry.register(provider); providerService.deviceConnected(deviceId, description(deviceId, DEVICE, OLT)); } finally { registry.unregister(provider); - } + }*/ appId = coreService.registerApplication( "org.onosproject.driver.OLTPipeline"); @@ -109,12 +108,12 @@ public class OLTPipeline extends AbstractHandlerBehaviour implements Pipeliner { PacketPriority.CONTROL.priorityValue(), appId, 0, true, null); - flowRuleService.applyFlowRules(flowRule); + //flowRuleService.applyFlowRules(flowRule); } @Override public void filter(FilteringObjective filter) { - throw new UnsupportedOperationException("Single table does not filter."); + throw new UnsupportedOperationException("OLT does not filter."); } @Override @@ -140,19 +139,11 @@ public class OLTPipeline extends AbstractHandlerBehaviour implements Pipeliner { TrafficSelector selector = fwd.selector(); TrafficTreatment treatment = fwd.treatment(); - if ((fwd.treatment().deferred().size() == 0) && - (fwd.treatment().immediate().size() == 0) && - (fwd.treatment().tableTransition() == null) && - (!fwd.treatment().clearedDeferred())) { - TrafficTreatment.Builder flowTreatment = DefaultTrafficTreatment.builder(); - flowTreatment.add(Instructions.createDrop()); - treatment = flowTreatment.build(); - } FlowRule.Builder ruleBuilder = DefaultFlowRule.builder() .forDevice(deviceId) .withSelector(selector) - .withTreatment(fwd.treatment()) + .withTreatment(treatment) .fromApp(fwd.appId()) .withPriority(fwd.priority()); @@ -162,9 +153,7 @@ public class OLTPipeline extends AbstractHandlerBehaviour implements Pipeliner { ruleBuilder.makeTemporary(fwd.timeout()); } - switch (fwd.op()) { - case ADD: flowBuilder.add(ruleBuilder.build()); break; @@ -190,16 +179,16 @@ public class OLTPipeline extends AbstractHandlerBehaviour implements Pipeliner { } } })); - } @Override public void next(NextObjective nextObjective) { - throw new UnsupportedOperationException("Single table does not next hop."); + throw new UnsupportedOperationException("OLT does not next hop."); } /** * Build a device description. + * * @param deviceId a deviceId * @param key the key of the annotation * @param value the value for the annotation diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OpenVSwitchPipeline.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OpenVSwitchPipeline.java index 270e76a2..5d098390 100644 --- a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OpenVSwitchPipeline.java +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OpenVSwitchPipeline.java @@ -21,12 +21,14 @@ import java.util.Collection; import java.util.Collections; import org.onlab.osgi.ServiceDirectory; +import org.onosproject.core.ApplicationId; import org.onosproject.core.CoreService; import org.onosproject.net.DeviceId; import org.onosproject.net.behaviour.Pipeliner; import org.onosproject.net.behaviour.PipelinerContext; import org.onosproject.net.device.DeviceService; import org.onosproject.net.flow.DefaultFlowRule; +import org.onosproject.net.flow.DefaultTrafficSelector; import org.onosproject.net.flow.DefaultTrafficTreatment; import org.onosproject.net.flow.FlowRule; import org.onosproject.net.flow.FlowRuleOperations; @@ -56,11 +58,13 @@ public class OpenVSwitchPipeline extends DefaultSingleTablePipeline private ServiceDirectory serviceDirectory; protected FlowObjectiveStore flowObjectiveStore; protected DeviceId deviceId; + protected ApplicationId appId; protected FlowRuleService flowRuleService; protected DeviceService deviceService; private static final int TIME_OUT = 0; - private static final int MAC_TABLE = 40; - private static final int PORT_TABLE = 0; + private static final int CLASSIFIER_TABLE = 0; + private static final int MAC_TABLE = 50; + private static final int TABLE_MISS_PRIORITY = 0; @Override public void init(DeviceId deviceId, PipelinerContext context) { @@ -71,9 +75,9 @@ public class OpenVSwitchPipeline extends DefaultSingleTablePipeline coreService = serviceDirectory.get(CoreService.class); flowRuleService = serviceDirectory.get(FlowRuleService.class); flowObjectiveStore = context.store(); - coreService + appId = coreService .registerApplication("org.onosproject.driver.OpenVSwitchPipeline"); - + initializePipeline(); } @Override @@ -125,6 +129,60 @@ public class OpenVSwitchPipeline extends DefaultSingleTablePipeline super.next(nextObjective); } + private void initializePipeline() { + processClassifierTable(true); + processMacTable(true); + } + + private void processClassifierTable(boolean install) { + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); + + treatment.transition(MAC_TABLE); + + FlowRule rule; + rule = DefaultFlowRule.builder().forDevice(deviceId) + .withSelector(selector.build()) + .withTreatment(treatment.build()) + .withPriority(TABLE_MISS_PRIORITY).fromApp(appId) + .makePermanent().forTable(CLASSIFIER_TABLE).build(); + + applyRules(install, rule); + } + + private void processMacTable(boolean install) { + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); + + treatment.drop(); + + FlowRule rule; + rule = DefaultFlowRule.builder().forDevice(deviceId) + .withSelector(selector.build()) + .withTreatment(treatment.build()) + .withPriority(TABLE_MISS_PRIORITY).fromApp(appId) + .makePermanent().forTable(MAC_TABLE).build(); + + applyRules(install, rule); + } + + private void applyRules(boolean install, FlowRule rule) { + FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); + + ops = install ? ops.add(rule) : ops.remove(rule); + flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { + @Override + public void onSuccess(FlowRuleOperations ops) { + log.info("ONOSW provisioned " + rule.tableId() + " table"); + } + + @Override + public void onError(FlowRuleOperations ops) { + log.info("ONOSW failed to provision " + rule.tableId() + " table"); + } + })); + } + private Collection<FlowRule> processForward(ForwardingObjective fwd) { switch (fwd.flag()) { case SPECIFIC: @@ -164,7 +222,7 @@ public class OpenVSwitchPipeline extends DefaultSingleTablePipeline tb.allInstructions().forEach(t -> newTraffic.add(t)); newTraffic.transition(MAC_TABLE); ruleBuilder.withTreatment(newTraffic.build()); - ruleBuilder.forTable(PORT_TABLE); + ruleBuilder.forTable(CLASSIFIER_TABLE); } return Collections.singletonList(ruleBuilder.build()); } diff --git a/framework/src/onos/etc/init/onos.conf b/framework/src/onos/etc/init/onos.conf deleted file mode 100644 index 779df905..00000000 --- a/framework/src/onos/etc/init/onos.conf +++ /dev/null @@ -1,37 +0,0 @@ -description "Open Network Operating System" -author "ON.Lab" - -start on (net-device-up - and local-filesystems - and runlevel [2345]) -stop on runlevel [016] - -console output -kill timeout 60 -respawn - -env LANG=en_US.UTF-8 - -pre-start script - [ -f /opt/onos/options ] && . /opt/onos/options - ONOS_USER=${ONOS_USER:-root} - - # Ensure that the environment is initialized - [ -d /opt/onos ] && mkdir /opt/onos/var 2>/dev/null && chown $ONOS_USER.$ONOS_USER /opt/onos/var - [ -d /opt/onos ] && mkdir /opt/onos/config 2>/dev/null && chown $ONOS_USER.$ONOS_USER /opt/onos/config - # TODO make karaf version configurable - [ -d /opt/onos ] && [ ! -h /opt/onos/log ] \ - && ln -s /opt/onos/apache-karaf-3.0.3/data/log /opt/onos/log || : -end script - -pre-stop script - /opt/onos/bin/onos halt 2>>/opt/onos/var/stderr.log - sleep 1 -end script - -script - [ -f /opt/onos/options ] && . /opt/onos/options - start-stop-daemon --signal INT --start --chuid ${ONOS_USER:-root} \ - --exec /opt/onos/bin/onos-service -- ${ONOS_OPTS:-server} \ - >/opt/onos/var/stdout.log 2>/opt/onos/var/stderr.log -end script diff --git a/framework/src/onos/etc/org.ops4j.pax.url.mvn.cfg b/framework/src/onos/etc/org.ops4j.pax.url.mvn.cfg deleted file mode 100644 index 15167a3b..00000000 --- a/framework/src/onos/etc/org.ops4j.pax.url.mvn.cfg +++ /dev/null @@ -1,101 +0,0 @@ -################################################################################ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You 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. -# -################################################################################ - -# -# If set to true, the following property will not allow any certificate to be used -# when accessing Maven repositories through SSL -# -#org.ops4j.pax.url.mvn.certificateCheck= - -# -# Path to the local Maven settings file. -# The repositories defined in this file will be automatically added to the list -# of default repositories if the 'org.ops4j.pax.url.mvn.repositories' property -# below is not set. -# The following locations are checked for the existence of the settings.xml file -# * 1. looks for the specified url -# * 2. if not found looks for ${user.home}/.m2/settings.xml -# * 3. if not found looks for ${maven.home}/conf/settings.xml -# * 4. if not found looks for ${M2_HOME}/conf/settings.xml -# -#org.ops4j.pax.url.mvn.settings= - -# -# Path to the local Maven repository which is used to avoid downloading -# artifacts when they already exist locally. -# The value of this property will be extracted from the settings.xml file -# above, or defaulted to: -# System.getProperty( "user.home" ) + "/.m2/repository" -# -#org.ops4j.pax.url.mvn.localRepository= - -# -# Default this to false. It's just weird to use undocumented repos -# -org.ops4j.pax.url.mvn.useFallbackRepositories=false - -# -# Uncomment if you don't wanna use the proxy settings -# from the Maven conf/settings.xml file -# -# org.ops4j.pax.url.mvn.proxySupport=false - -# -# Comma separated list of repositories scanned when resolving an artifact. -# Those repositories will be checked before iterating through the -# below list of repositories and even before the local repository -# A repository url can be appended with zero or more of the following flags: -# @snapshots : the repository contains snaphots -# @noreleases : the repository does not contain any released artifacts -# -# The following property value will add the system folder as a repo. -# -org.ops4j.pax.url.mvn.defaultRepositories=\ - file:${karaf.home}/${karaf.default.repository}@id=system.repository@snapshots,\ - file:${karaf.data}/kar@id=kar.repository@multi@snapshots - -# Use the default local repo (e.g.~/.m2/repository) as a "remote" repo -#org.ops4j.pax.url.mvn.defaultLocalRepoAsRemote=false - -# -# Comma separated list of repositories scanned when resolving an artifact. -# The default list includes the following repositories: -# http://repo1.maven.org/maven2@id=central -# http://repository.springsource.com/maven/bundles/release@id=spring.ebr -# http://repository.springsource.com/maven/bundles/external@id=spring.ebr.external -# http://zodiac.springsource.com/maven/bundles/release@id=gemini -# http://repository.apache.org/content/groups/snapshots-group@id=apache@snapshots@noreleases -# https://oss.sonatype.org/content/repositories/snapshots@id=sonatype.snapshots.deploy@snapshots@noreleases -# https://oss.sonatype.org/content/repositories/ops4j-snapshots@id=ops4j.sonatype.snapshots.deploy@snapshots@noreleases -# To add repositories to the default ones, prepend '+' to the list of repositories -# to add. -# A repository url can be appended with zero or more of the following flags: -# @snapshots : the repository contains snapshots -# @noreleases : the repository does not contain any released artifacts -# @id=repository.id : the id for the repository, just like in the settings.xml this is optional but recommended -# -org.ops4j.pax.url.mvn.repositories= \ - ${org.ops4j.pax.url.mvn.defaultRepositories}, \ - http://repo1.maven.org/maven2@id=central, \ - http://repository.springsource.com/maven/bundles/release@id=spring.ebr.release, \ - http://repository.springsource.com/maven/bundles/external@id=spring.ebr.external, \ - http://zodiac.springsource.com/maven/bundles/release@id=gemini, \ - http://repository.apache.org/content/groups/snapshots-group@id=apache@snapshots@noreleases, \ - https://oss.sonatype.org/content/repositories/snapshots@id=sonatype.snapshots.deploy@snapshots@noreleases, \ - https://oss.sonatype.org/content/repositories/ops4j-snapshots@id=ops4j.sonatype.snapshots.deploy@snapshots@noreleases diff --git a/framework/src/onos/etc/org.ops4j.pax.web.cfg b/framework/src/onos/etc/org.ops4j.pax.web.cfg deleted file mode 100644 index c8fb3b3d..00000000 --- a/framework/src/onos/etc/org.ops4j.pax.web.cfg +++ /dev/null @@ -1,12 +0,0 @@ -org.osgi.service.http.port=8181 -org.osgi.service.http.port.secure=8443 - -org.osgi.service.http.enabled=true -org.osgi.service.http.secure.enabled=false - -org.ops4j.pax.web.ssl.keystore=etc/keystore -org.ops4j.pax.web.ssl.password=OBF:1xtn1w1u1uob1xtv1y7z1xtn1unn1w1o1xtv -org.ops4j.pax.web.ssl.keypassword=OBF:1xtn1w1u1uob1xtv1y7z1xtn1unn1w1o1xtv - -org.ops4j.pax.web.session.url=none -org.ops4j.pax.web.config.file=./etc/jetty.xml diff --git a/framework/src/onos/etc/samples/linkGraph.cfg b/framework/src/onos/etc/samples/linkGraph.cfg deleted file mode 100644 index 41ce5bdc..00000000 --- a/framework/src/onos/etc/samples/linkGraph.cfg +++ /dev/null @@ -1,27 +0,0 @@ -# NullLinkProvider topology description (config file). -# -# Dot-style topology graph. Each controller's topology begins with -# -# graph <node ID>, followed by a list of links between braces. -# -# The links are either bidirectional (--) or directed (->). The directed -# edges are used to connect together Null devices of different controllers. -# The endpoint has the format: -# -# devID:port:NodeId -# -# The NodeId is only added if the destination is another node's device. -# -graph 192.168.56.20 { - 0:0 -- 1:0 - 1:1 -> 0:0:192.168.56.30 - 1:2 -- 2:0 - 2:1 -> 1:0:192.168.56.30 -} -graph 192.168.56.30 { - 0:0 -> 1:1:192.168.56.20 - 0:1 -- 1:1 - 1:0 -> 2:1:192.168.56.20 - 1:2 -- 2:0 -} -# Bugs: Comments cannot be appended to a line to be read. diff --git a/framework/src/onos/etc/samples/org.onosproject.fwd.ReactiveForwarding.cfg b/framework/src/onos/etc/samples/org.onosproject.fwd.ReactiveForwarding.cfg deleted file mode 100644 index 4befc706..00000000 --- a/framework/src/onos/etc/samples/org.onosproject.fwd.ReactiveForwarding.cfg +++ /dev/null @@ -1,79 +0,0 @@ -# -# Sample configuration for onos-app-fwd. -# - -# -# Reactive flows default matching is InPort, Src MAC, Dst MAC and EtherType fields -# - -# -# Enable packet-out only forwarding. -# This flag affects to both IPv4 and IPv6. -# -# packetOutOnly = true - -# -# Enable forwarding of the first packet by using OFPP_TABLE port in the -# PacketOut message instead of sending it directly to the switch port -# -# packetOutOfppTable = true - -# -# Timeout of reactively installed flows (in seconds). -# Default is 10 sec -# -# flowTimeout = 10 - -# -# Priority of reactively installed flows -# -# flowPriority = 10 - -# -# Enable IPv6 forwarding. -# -# ipv6Forwarding = true - -# -# Flows matching destination MAC only - as legacy L2 switches -# - This option overrides all other options below -# -# matchDstMacOnly = true - -# -# Matching of VLAN ID in Ethernet header -# -# matchVlanId = true - -# -# Matching of IPv4 addresses and Protocol field -# - must be enabled to match IPv4 DSCP, TCP/UDP ports and ICMP type/code -# -# matchIpv4Address = true - -# -# Matching of IPv4 DSCP and ECN fields -# -# matchIpv4Dscp = true - -# -# Matching of IPv6 addresses and Next-Header field -# - must be enabled to match IPv6 Flow Label, TCP/UDP ports and ICMP type/code -# -# matchIpv6Address = true - -# -# Matching of IPv6 Flow Label -# -# matchIpv6FlowLabel = true - -# -# Matching of TCP/UDP ports for IPv4 and IPv6 -# -# matchTcpUdpPorts = true - -# -# Matching of ICMP Type and Code fields for IPv4 and IPv6 -# -# matchIcmpFields = true - diff --git a/framework/src/onos/etc/samples/org.onosproject.provider.host.impl.HostLocationProvider.cfg b/framework/src/onos/etc/samples/org.onosproject.provider.host.impl.HostLocationProvider.cfg deleted file mode 100644 index 6d3a50d9..00000000 --- a/framework/src/onos/etc/samples/org.onosproject.provider.host.impl.HostLocationProvider.cfg +++ /dev/null @@ -1,13 +0,0 @@ -# -# Sample configuration for Host Location Provider -# - -# -# Enable host removal on port/device down events. -# -# hostRemovalEnabled = true - -# -# Enable using IPv6 Neighbor Discovery by the Host Location Provider. -# -# ipv6NeighborDiscovery = true diff --git a/framework/src/onos/etc/samples/org.onosproject.provider.lldp.impl.LLDPLinkProvider.cfg b/framework/src/onos/etc/samples/org.onosproject.provider.lldp.impl.LLDPLinkProvider.cfg deleted file mode 100644 index 6eb39a11..00000000 --- a/framework/src/onos/etc/samples/org.onosproject.provider.lldp.impl.LLDPLinkProvider.cfg +++ /dev/null @@ -1,21 +0,0 @@ -# -# Sample configuration for link discovery -# - -# -# Disable Link Dicovery Permanently (Note: changing this property at runtime will have NO effect) -# WARNING: This should only be used for special projects like bgprouter, where ONOS is controlling -# a single switch -# -#disableLinkDiscovery = true - -# -# Enable Broadcast Discovery Protocol (EthType=0x8942) -# -#useBDDP = false - -# -# Disable LLDP's received from specific devices -# Details of the devices are in the file configured below -# -#lldpSuppression = ../config/lldp_suppresion.json diff --git a/framework/src/onos/etc/samples/org.onosproject.provider.netconf.device.impl.NetconfDeviceProvider.cfg b/framework/src/onos/etc/samples/org.onosproject.provider.netconf.device.impl.NetconfDeviceProvider.cfg deleted file mode 100644 index 30ed0c26..00000000 --- a/framework/src/onos/etc/samples/org.onosproject.provider.netconf.device.impl.NetconfDeviceProvider.cfg +++ /dev/null @@ -1,11 +0,0 @@ -# -# Instance-specific configurations, in this case, the number of -# devices per node. -# -devConfigs = cisco:cisco@192.168.56.20:2022:inactive,sdn:rocks@192.168.56.30:22:inactive - -# -# Number of ports per device. This is global to all devices -# on all instances. -# -# numPorts = 8 diff --git a/framework/src/onos/etc/samples/org.onosproject.provider.nil.device.impl.NullDeviceProvider.cfg b/framework/src/onos/etc/samples/org.onosproject.provider.nil.device.impl.NullDeviceProvider.cfg deleted file mode 100644 index 194bf037..00000000 --- a/framework/src/onos/etc/samples/org.onosproject.provider.nil.device.impl.NullDeviceProvider.cfg +++ /dev/null @@ -1,11 +0,0 @@ -# -# Instance-specific configurations, in this case, the number of -# devices per node. -# -devConfigs = 192.168.56.20:3,192.168.56.30:3 - -# -# Number of ports per device. This is global to all devices -# on all instances. -# -# numPorts = 8 diff --git a/framework/src/onos/etc/samples/org.onosproject.provider.nil.link.impl.NullLinkProvider.cfg b/framework/src/onos/etc/samples/org.onosproject.provider.nil.link.impl.NullLinkProvider.cfg deleted file mode 100644 index ef72b1ee..00000000 --- a/framework/src/onos/etc/samples/org.onosproject.provider.nil.link.impl.NullLinkProvider.cfg +++ /dev/null @@ -1,16 +0,0 @@ -# -# Sample configurations for the NullLinkProvider. -# - -# -# If enabled, sets the time between LinkEvent generation, -# in microseconds. -# - -#eventRate = 1000000 - -# -# If enabled, points to the full path to the topology file. -# - -#cfgFile = /tmp/foo.cfg diff --git a/framework/src/onos/etc/samples/org.onosproject.provider.nil.packet.impl.NullPacketProvider.cfg b/framework/src/onos/etc/samples/org.onosproject.provider.nil.packet.impl.NullPacketProvider.cfg deleted file mode 100644 index db4342c0..00000000 --- a/framework/src/onos/etc/samples/org.onosproject.provider.nil.packet.impl.NullPacketProvider.cfg +++ /dev/null @@ -1,4 +0,0 @@ -# -# Uncomment and tweak to tune the rate of Packet events (per second) -# -# pktRate = 100 diff --git a/framework/src/onos/etc/samples/org.onosproject.proxyarp.ProxyArp.cfg b/framework/src/onos/etc/samples/org.onosproject.proxyarp.ProxyArp.cfg deleted file mode 100644 index 108de136..00000000 --- a/framework/src/onos/etc/samples/org.onosproject.proxyarp.ProxyArp.cfg +++ /dev/null @@ -1,8 +0,0 @@ -# -# Sample configuration for onos-app-proxyarp. -# - -# -# Enable IPv6 Neighbor Discovery. -# -# ipv6NeighborDiscovery = true diff --git a/framework/src/onos/etc/samples/org.onosproject.routing.bgp.BgpSessionManager.cfg b/framework/src/onos/etc/samples/org.onosproject.routing.bgp.BgpSessionManager.cfg deleted file mode 100644 index fbcc13f9..00000000 --- a/framework/src/onos/etc/samples/org.onosproject.routing.bgp.BgpSessionManager.cfg +++ /dev/null @@ -1,8 +0,0 @@ -# -# Sample configuration for onos-app-sdnip. -# - -# -# The port number that SDN-IP listens for incoming BGP connections on. -# -# bgpPort=2000
\ No newline at end of file diff --git a/framework/src/onos/etc/samples/org.onosproject.xos.XOS.cfg b/framework/src/onos/etc/samples/org.onosproject.xos.XOS.cfg deleted file mode 100644 index e69de29b..00000000 --- a/framework/src/onos/etc/samples/org.onosproject.xos.XOS.cfg +++ /dev/null diff --git a/framework/src/onos/etc/users.properties b/framework/src/onos/etc/users.properties deleted file mode 100644 index 9f7a2667..00000000 --- a/framework/src/onos/etc/users.properties +++ /dev/null @@ -1,34 +0,0 @@ -################################################################################ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You 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. -# -################################################################################ - -# -# This file contains the users, groups, and roles. -# Each line has to be of the format: -# -# USER=PASSWORD,ROLE1,ROLE2,... -# USER=PASSWORD,_g_:GROUP,... -# _g_\:GROUP=ROLE1,ROLE2,... -# -# All users, grousp, and roles entered in this file are available after Karaf startup -# and modifiable via the JAAS command group. These users reside in a JAAS domain -# with the name "karaf". -# -karaf = karaf,_g_:admingroup -onos = rocks,_g_:admingroup -_g_\:admingroup = group,admin,manager,viewer,webconsole diff --git a/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/config/basics/InterfaceConfig.java b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/config/basics/InterfaceConfig.java index 592336c2..9f2d4105 100644 --- a/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/config/basics/InterfaceConfig.java +++ b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/config/basics/InterfaceConfig.java @@ -39,7 +39,6 @@ public class InterfaceConfig extends Config<ConnectPoint> { public static final String MAC = "mac"; public static final String VLAN = "vlan"; - public static final String MAC_MISSING_ERROR = "Must have a MAC address for each interface"; public static final String CONFIG_VALUE_ERROR = "Error parsing config value"; /** @@ -55,15 +54,12 @@ public class InterfaceConfig extends Config<ConnectPoint> { for (JsonNode intfNode : array) { Set<InterfaceIpAddress> ips = getIps(intfNode); - if (intfNode.path(MAC).isMissingNode()) { - throw new ConfigException(MAC_MISSING_ERROR); - } - - MacAddress mac = MacAddress.valueOf(intfNode.path(MAC).asText()); + String mac = intfNode.path(MAC).asText(); + MacAddress macAddr = mac.isEmpty() ? null : MacAddress.valueOf(mac); VlanId vlan = getVlan(intfNode); - interfaces.add(new Interface(subject, ips, mac, vlan)); + interfaces.add(new Interface(subject, ips, macAddr, vlan)); } } catch (IllegalArgumentException e) { throw new ConfigException(CONFIG_VALUE_ERROR, e); @@ -79,7 +75,10 @@ public class InterfaceConfig extends Config<ConnectPoint> { */ public void addInterface(Interface intf) { ObjectNode intfNode = array.addObject(); - intfNode.put(MAC, intf.mac().toString()); + + if (intf.mac() != null) { + intfNode.put(MAC, intf.mac().toString()); + } if (!intf.ipAddresses().isEmpty()) { intfNode.set(IPS, putIps(intf.ipAddresses())); diff --git a/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/intf/Interface.java b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/intf/Interface.java index 69d14bce..b9d3eadf 100644 --- a/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/intf/Interface.java +++ b/framework/src/onos/incubator/api/src/main/java/org/onosproject/incubator/net/intf/Interface.java @@ -30,7 +30,8 @@ import static com.google.common.base.Preconditions.checkNotNull; /** * An Interface maps network configuration information (such as addresses and - * vlans) to a port in the network. + * vlans) to a port in the network. This is considered a L2/L3 network + * interface. */ @Beta public class Interface { @@ -51,9 +52,9 @@ public class Interface { Set<InterfaceIpAddress> ipAddresses, MacAddress macAddress, VlanId vlan) { this.connectPoint = checkNotNull(connectPoint); - this.ipAddresses = Sets.newHashSet(checkNotNull(ipAddresses)); - this.macAddress = checkNotNull(macAddress); - this.vlan = checkNotNull(vlan); + this.ipAddresses = ipAddresses == null ? Sets.newHashSet() : ipAddresses; + this.macAddress = macAddress == null ? MacAddress.NONE : macAddress; + this.vlan = vlan == null ? VlanId.NONE : vlan; } /** diff --git a/framework/src/onos/openflow/api/src/main/java/org/onosproject/openflow/controller/OpenFlowSwitch.java b/framework/src/onos/openflow/api/src/main/java/org/onosproject/openflow/controller/OpenFlowSwitch.java index 1b6810be..51a2ce42 100644 --- a/framework/src/onos/openflow/api/src/main/java/org/onosproject/openflow/controller/OpenFlowSwitch.java +++ b/framework/src/onos/openflow/api/src/main/java/org/onosproject/openflow/controller/OpenFlowSwitch.java @@ -30,6 +30,14 @@ public interface OpenFlowSwitch { /** * Writes the message to the driver. * + * Note: + * Calling {@link #sendMsg(OFMessage)} does NOT guarantee the messages to be + * transmitted on the wire in order, especially during role transition. + * The messages may be reordered at the switch side. + * + * Calling {@link #sendMsg(List)} guarantee the messages inside the list + * to be transmitted on the wire in order. + * * @param msg the message to write */ void sendMsg(OFMessage msg); diff --git a/framework/src/onos/openflow/api/src/main/java/org/onosproject/openflow/controller/driver/AbstractOpenFlowSwitch.java b/framework/src/onos/openflow/api/src/main/java/org/onosproject/openflow/controller/driver/AbstractOpenFlowSwitch.java index 2f6357bd..2c19837e 100644 --- a/framework/src/onos/openflow/api/src/main/java/org/onosproject/openflow/controller/driver/AbstractOpenFlowSwitch.java +++ b/framework/src/onos/openflow/api/src/main/java/org/onosproject/openflow/controller/driver/AbstractOpenFlowSwitch.java @@ -79,6 +79,8 @@ public abstract class AbstractOpenFlowSwitch extends AbstractHandlerBehaviour protected OFFeaturesReply features; protected OFDescStatsReply desc; + List<OFMessage> messagesPendingMastership; + @Override public void init(Dpid dpid, OFDescStatsReply desc, OFVersion ofv) { this.dpid = dpid; @@ -96,16 +98,21 @@ public abstract class AbstractOpenFlowSwitch extends AbstractHandlerBehaviour } @Override - public void sendMsg(OFMessage m) { - if (role == RoleState.MASTER && channel.isConnected()) { - channel.write(Collections.singletonList(m)); - } + public void sendMsg(OFMessage msg) { + this.sendMsg(Collections.singletonList(msg)); } @Override public final void sendMsg(List<OFMessage> msgs) { if (role == RoleState.MASTER && channel.isConnected()) { channel.write(msgs); + } else if (messagesPendingMastership != null) { + messagesPendingMastership.addAll(msgs); + log.debug("Enqueue message for switch {}. queue size after is {}", + dpid, messagesPendingMastership.size()); + } else { + log.warn("Dropping message for switch {} (role: {}, connected: {}): {}", + dpid, role, channel.isConnected(), msgs); } } @@ -232,6 +239,12 @@ public abstract class AbstractOpenFlowSwitch extends AbstractHandlerBehaviour @Override public final void transitionToMasterSwitch() { this.agent.transitionToMasterSwitch(dpid); + if (messagesPendingMastership != null) { + this.sendMsg(messagesPendingMastership); + log.debug("Sending {} pending messages to switch {}", + messagesPendingMastership.size(), dpid); + messagesPendingMastership = null; + } } @Override @@ -278,6 +291,11 @@ public abstract class AbstractOpenFlowSwitch extends AbstractHandlerBehaviour log.debug("Sending role {} to switch {}", role, getStringId()); if (role == RoleState.SLAVE || role == RoleState.EQUAL) { this.role = role; + } else { + if (messagesPendingMastership == null) { + log.debug("Initializing new queue for switch {}", dpid); + messagesPendingMastership = new ArrayList<>(); + } } } else { this.role = role; diff --git a/framework/src/onos/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OFMessageEncoder.java b/framework/src/onos/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OFMessageEncoder.java index df7865d3..4c1b16fe 100644 --- a/framework/src/onos/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OFMessageEncoder.java +++ b/framework/src/onos/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OFMessageEncoder.java @@ -25,7 +25,6 @@ import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.handler.codec.oneone.OneToOneEncoder; import org.projectfloodlight.openflow.protocol.OFMessage; - /** * Encode an openflow message for output into a ChannelBuffer, for use in a * netty pipeline. @@ -50,7 +49,9 @@ public class OFMessageEncoder extends OneToOneEncoder { ChannelBuffer buf = ChannelBuffers.dynamicBuffer(); for (OFMessage ofm : msglist) { - ofm.writeTo(buf); + if (ofm != null) { + ofm.writeTo(buf); + } } return buf; } diff --git a/framework/src/onos/opt/onos/.empty b/framework/src/onos/opt/onos/.empty deleted file mode 100644 index e69de29b..00000000 --- a/framework/src/onos/opt/onos/.empty +++ /dev/null diff --git a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/driver/DefaultOvsdbClient.java b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/driver/DefaultOvsdbClient.java index 2575a256..3280ad34 100644 --- a/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/driver/DefaultOvsdbClient.java +++ b/framework/src/onos/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/driver/DefaultOvsdbClient.java @@ -175,14 +175,19 @@ public class DefaultOvsdbClient * * @param dbName the ovsdb database name * @param tableName the ovsdb table name - * @return ovsRowStore, empty if row store is find + * @return ovsRowStore, empty store if no rows exist in the table */ private OvsdbRowStore getRowStore(String dbName, String tableName) { OvsdbTableStore tableStore = getTableStore(dbName); if (tableStore == null) { return null; } - return tableStore.getRows(tableName); + + OvsdbRowStore rowStore = tableStore.getRows(tableName); + if (rowStore == null) { + rowStore = new OvsdbRowStore(); + } + return rowStore; } /** diff --git a/framework/src/onos/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java b/framework/src/onos/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java index 329df20b..a7e334f4 100644 --- a/framework/src/onos/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java +++ b/framework/src/onos/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java @@ -319,6 +319,9 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr } DeviceId did = deviceId(uri(dpid)); OpenFlowSwitch sw = controller.getSwitch(dpid); + if (sw == null) { + return; + } ChassisId cId = new ChassisId(dpid.value()); @@ -339,9 +342,14 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr providerService.updatePorts(did, buildPortDescriptions(sw)); PortStatsCollector psc = - new PortStatsCollector(controller.getSwitch(dpid), portStatsPollFrequency); + new PortStatsCollector(sw, portStatsPollFrequency); psc.start(); collectors.put(dpid, psc); + + //figure out race condition for collectors.remove() and collectors.put() + if (controller.getSwitch(dpid) == null) { + switchRemoved(dpid); + } } @Override @@ -364,6 +372,9 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr } DeviceId did = deviceId(uri(dpid)); OpenFlowSwitch sw = controller.getSwitch(dpid); + if (sw == null) { + return; + } providerService.updatePorts(did, buildPortDescriptions(sw)); } diff --git a/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowEntryBuilder.java b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowEntryBuilder.java index cf918605..1039d049 100644 --- a/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowEntryBuilder.java +++ b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowEntryBuilder.java @@ -55,6 +55,7 @@ import org.projectfloodlight.openflow.protocol.action.OFActionCircuit; import org.projectfloodlight.openflow.protocol.action.OFActionExperimenter; import org.projectfloodlight.openflow.protocol.action.OFActionGroup; import org.projectfloodlight.openflow.protocol.action.OFActionOutput; +import org.projectfloodlight.openflow.protocol.action.OFActionSetQueue; import org.projectfloodlight.openflow.protocol.action.OFActionPopMpls; import org.projectfloodlight.openflow.protocol.action.OFActionSetDlDst; import org.projectfloodlight.openflow.protocol.action.OFActionSetDlSrc; @@ -333,6 +334,10 @@ public class FlowEntryBuilder { OFActionGroup group = (OFActionGroup) act; builder.group(new DefaultGroupId(group.getGroup().getGroupNumber())); break; + case SET_QUEUE: + OFActionSetQueue setQueue = (OFActionSetQueue) act; + builder.setQueue(setQueue.getQueueId()); + break; case STRIP_VLAN: case POP_VLAN: builder.popVlan(); @@ -350,7 +355,6 @@ public class FlowEntryBuilder { case SET_NW_ECN: case SET_NW_TOS: case SET_NW_TTL: - case SET_QUEUE: case ENQUEUE: default: diff --git a/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer13.java b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer13.java index cc265758..64b4360a 100644 --- a/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer13.java +++ b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer13.java @@ -26,6 +26,7 @@ import org.onosproject.net.flow.instructions.Instruction; import org.onosproject.net.flow.instructions.Instructions; import org.onosproject.net.flow.instructions.Instructions.GroupInstruction; import org.onosproject.net.flow.instructions.Instructions.OutputInstruction; +import org.onosproject.net.flow.instructions.Instructions.SetQueueInstruction; import org.onosproject.net.flow.instructions.L0ModificationInstruction; import org.onosproject.net.flow.instructions.L0ModificationInstruction.ModLambdaInstruction; import org.onosproject.net.flow.instructions.L0ModificationInstruction.ModOchSignalInstruction; @@ -50,6 +51,7 @@ import org.projectfloodlight.openflow.protocol.OFFlowModFlags; import org.projectfloodlight.openflow.protocol.action.OFAction; import org.projectfloodlight.openflow.protocol.action.OFActionGroup; import org.projectfloodlight.openflow.protocol.action.OFActionOutput; +import org.projectfloodlight.openflow.protocol.action.OFActionSetQueue; import org.projectfloodlight.openflow.protocol.instruction.OFInstruction; import org.projectfloodlight.openflow.protocol.match.Match; import org.projectfloodlight.openflow.protocol.oxm.OFOxm; @@ -244,6 +246,12 @@ public class FlowModBuilderVer13 extends FlowModBuilder { .setGroup(OFGroup.of(group.groupId().id())); actions.add(groupBuilder.build()); break; + case QUEUE: + SetQueueInstruction queue = (SetQueueInstruction) i; + OFActionSetQueue.Builder queueBuilder = factory().actions().buildSetQueue() + .setQueueId(queue.queueId()); + actions.add(queueBuilder.build()); + break; case TABLE: //FIXME: should not occur here. tableFound = true; diff --git a/framework/src/onos/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/OpenFlowGroupProvider.java b/framework/src/onos/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/OpenFlowGroupProvider.java index 78650fe6..8acf08ee 100644 --- a/framework/src/onos/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/OpenFlowGroupProvider.java +++ b/framework/src/onos/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/OpenFlowGroupProvider.java @@ -334,12 +334,20 @@ public class OpenFlowGroupProvider extends AbstractProvider implements GroupProv @Override public void switchAdded(Dpid dpid) { OpenFlowSwitch sw = controller.getSwitch(dpid); + if (sw == null) { + return; + } if (isGroupSupported(sw)) { GroupStatsCollector gsc = new GroupStatsCollector( controller.getSwitch(dpid), POLL_INTERVAL); gsc.start(); collectors.put(dpid, gsc); } + + //figure out race condition + if (controller.getSwitch(dpid) == null) { + switchRemoved(dpid); + } } @Override diff --git a/framework/src/onos/tools/package/config/samples/network-cfg.json b/framework/src/onos/tools/package/config/samples/network-cfg.json index c2af8b81..92328479 100644 --- a/framework/src/onos/tools/package/config/samples/network-cfg.json +++ b/framework/src/onos/tools/package/config/samples/network-cfg.json @@ -28,8 +28,8 @@ "routerMac" : "00:00:00:00:01:80", "isEdgeRouter" : true, "adjacencySids" : [ - { "sid" : 100, "port" : [2, 3] }, - { "sid" : 200, "port" : [4, 5] } + { "sid" : 100, "ports" : [2, 3] }, + { "sid" : 200, "ports" : [4, 5] } ] } }, diff --git a/framework/src/onos/tools/package/config/samples/segmentrouting_dell.conf b/framework/src/onos/tools/package/config/samples/segmentrouting_dell.conf deleted file mode 100644 index be489a65..00000000 --- a/framework/src/onos/tools/package/config/samples/segmentrouting_dell.conf +++ /dev/null @@ -1,93 +0,0 @@ -{ - "comment": " Multilayer topology description and configuration", - "restrictSwitches": true, - "restrictLinks": true, - - "switchConfig": - [ - { "nodeDpid" : "of:00010001e88b9368", "name": "Dell-R1", "type": "Router_SR", "allowed": true, - "latitude": 80.80, "longitude": 90.10, - "params": { "routerIp": "192.168.0.1/32", - "routerMac": "00:01:e8:8b:93:6b", - "nodeSid": 101, - "isEdgeRouter" : true, - "subnets": [ - { "portNo": 46, "subnetIp": "10.200.1.1/24" } - ] - } - }, - - { "nodeDpid": "of:00010001e88b939b", "name": "Dell-R2", "type": "Router_SR", "allowed": true, - "latitude": 80.80, "longitude": 90.10, - "params": { "routerIp": "192.168.0.2/32", - "routerMac": "00:01:e8:8b:93:9e", - "nodeSid": 102, - "isEdgeRouter" : true, - "subnets": [ - { "portNo": 46, "subnetIp": "10.200.2.1/24" } - ] - } - }, - - { "nodeDpid": "of:00010001e88b938c", "name": "Dell-R3", "type": "Router_SR", "allowed": true, - "latitude": 80.80, "longitude": 90.10, - "params": { "routerIp": "192.168.0.3/32", - "routerMac": "00:01:e8:8b:93:8f", - "nodeSid": 103, - "isEdgeRouter" : true, - "subnets": [ - { "portNo": 46, "subnetIp": "10.200.3.1/24" } - ] - } - }, - - { "nodeDpid": "of:00010001e88b93ad", "name": "Dell-R4", "type": "Router_SR", "allowed": true, - "latitude": 80.80, "longitude": 90.10, - "params": { "routerIp": "192.168.0.4/32", - "routerMac": "00:01:e8:8b:93:b0", - "nodeSid": 104, - "isEdgeRouter" : true, - "subnets": [ - { "portNo": 46, "subnetIp": "10.200.4.1/24" } - ] - } - }, - - { "nodeDpid": "of:00010001e88b93bc", "name": "Dell-R5", "type": "Router_SR", "allowed": true, - "latitude": 80.80, "longitude": 90.10, - "params": { "routerIp": "192.168.0.5/32", - "routerMac": "00:01:e8:8b:93:bf", - "nodeSid": 105, - "isEdgeRouter" : false - } - }, - - { "nodeDpid": "of:00010001e88b93c2", "name": "Dell-R6", "type": "Router_SR", "allowed": true, - "latitude": 80.80, "longitude": 90.10, - "params": { "routerIp": "192.168.0.6/32", - "routerMac": "00:01:e8:8b:93:c5", - "nodeSid": 106, - "isEdgeRouter" : false - } - }, - - { "nodeDpid": "of:00010001e88b9398", "name": "Dell-R7", "type": "Router_SR", "allowed": true, - "latitude": 80.80, "longitude": 90.10, - "params": { "routerIp": "192.168.0.7/32", - "routerMac": "00:01:e8:8b:93:9b", - "nodeSid": 107, - "isEdgeRouter": false - } - }, - - { "nodeDpid": "of:00010001e88b27e3", "name": "Dell-R8", "type": "Router_SR", "allowed": true, - "latitude": 80.80, "longitude": 90.10, - "params": { "routerIp": "192.168.0.8/32", - "routerMac": "00:01:e8:8b:27:e6", - "nodeSid": 108, - "isEdgeRouter": false - } - } - - ] -} diff --git a/framework/src/onos/tools/test/scenarios/sequential-example.xml b/framework/src/onos/tools/test/scenarios/sequential-example.xml new file mode 100644 index 00000000..eee32d30 --- /dev/null +++ b/framework/src/onos/tools/test/scenarios/sequential-example.xml @@ -0,0 +1,27 @@ +<!-- + ~ Copyright 2015 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. + --> +<scenario name="example" description="sequential scenario example"> + <group name="Wrapup"> + <!-- 'starts' is a comma-separated list of patterns that name steps starting the current iteration of the sequence --> + <!-- 'ends' is a comma-separated list of patterns that name steps ending the previous iteration of the sequence --> + <!-- In this example each Final-Check-Logs-(N) will become dependent on Fetch-Logs-(N-1), for N > 1 --> + <sequential var="${OC#}" starts="Final-Check-Logs-${#}" ends="Fetch-Logs-${#-1}"> + <step name="Final-Check-Logs-${#}" exec="onos-check-logs ${OC#}"/> + <step name="Fetch-Logs-${#}" exec="onos-fetch-logs ${OC#}" + cwd="${WORKSPACE}/tmp/stc" requires="~^"/> + </sequential> + </group> +</scenario> diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/EthType.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/EthType.java index 561c9307..b3b79e2c 100644 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/EthType.java +++ b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/EthType.java @@ -45,7 +45,7 @@ public class EthType { private final Deserializer<?> deserializer; /** - * Constucts a new ethertype. + * Constructs a new ethertype. * * @param ethType The actual ethertype * @param type it's textual representation diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/MacAddress.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/MacAddress.java index 89cddbae..cb7f2013 100644 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/MacAddress.java +++ b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/MacAddress.java @@ -22,6 +22,7 @@ import java.util.Arrays; */ public class MacAddress { + public static final MacAddress NONE = valueOf("a4:23:05:00:00:00"); public static final MacAddress ZERO = valueOf("00:00:00:00:00:00"); public static final MacAddress BROADCAST = valueOf("ff:ff:ff:ff:ff:ff"); diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/PIM.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/PIM.java index d9a5e83f..e6ef0aed 100755 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/PIM.java +++ b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/PIM.java @@ -43,6 +43,9 @@ public class PIM extends BasePacket { public static final int PIM_HEADER_LEN = 4; + public static final byte ADDRESS_FAMILY_IP4 = 0x1; + public static final byte ADDRESS_FAMILY_IP6 = 0x2; + public static final Map<Byte, Deserializer<? extends IPacket>> PROTOCOL_DESERIALIZER_MAP = new HashMap<>(); diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/PIMAddrGroup.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/PIMAddrGroup.java index be4ab19a..0db82afb 100644 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/PIMAddrGroup.java +++ b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/PIMAddrGroup.java @@ -17,9 +17,11 @@ package org.onlab.packet.pim; import org.onlab.packet.DeserializationException; import org.onlab.packet.Ip4Address; +import org.onlab.packet.Ip6Address; import org.onlab.packet.IpAddress; import org.onlab.packet.IpPrefix; -import org.onlab.packet.Ip6Address; +import org.onlab.packet.PIM; + import java.nio.ByteBuffer; @@ -41,7 +43,7 @@ public class PIMAddrGroup { * PIM Encoded Group Address. */ public PIMAddrGroup() { - this.family = 4; + this.family = PIM.ADDRESS_FAMILY_IP4; this.encType = 0; this.reserved = 0; this.bBit = false; @@ -83,7 +85,7 @@ public class PIMAddrGroup { public void setAddr(IpPrefix pfx) { this.addr = pfx.address(); this.masklen = (byte) pfx.prefixLength(); - this.family = (byte) ((this.addr.isIp4()) ? 4 : 6); + this.family = (byte) ((this.addr.isIp4()) ? PIM.ADDRESS_FAMILY_IP4 : PIM.ADDRESS_FAMILY_IP6); } /** @@ -181,9 +183,9 @@ public class PIMAddrGroup { checkInput(bb.array(), bb.position(), bb.limit() - bb.position(), ENC_GROUP_IPV4_BYTE_LENGTH); this.family = bb.get(); - if (family != 4 && family != 6) { + if (family != PIM.ADDRESS_FAMILY_IP4 && family != PIM.ADDRESS_FAMILY_IP6) { throw new DeserializationException("Illegal IP version number: " + family + "\n"); - } else if (family == 6) { + } else if (family == PIM.ADDRESS_FAMILY_IP6) { // Check for one less by since we have already read the first byte of the packet. checkInput(bb.array(), bb.position(), bb.limit() - bb.position(), ENC_GROUP_IPV6_BYTE_LENGTH - 1); @@ -201,9 +203,9 @@ public class PIMAddrGroup { this.reserved |= 0x7d; this.masklen = bb.get(); - if (this.family == 4) { + if (this.family == PIM.ADDRESS_FAMILY_IP4) { this.addr = IpAddress.valueOf(bb.getInt()); - } else if (this.family == 6) { + } else if (this.family == PIM.ADDRESS_FAMILY_IP6) { this.addr = Ip6Address.valueOf(bb.array(), 2); } return this; diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/PIMAddrSource.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/PIMAddrSource.java index 21526408..762dad56 100644 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/PIMAddrSource.java +++ b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/PIMAddrSource.java @@ -17,9 +17,10 @@ package org.onlab.packet.pim; import org.onlab.packet.DeserializationException; import org.onlab.packet.Ip4Address; +import org.onlab.packet.Ip6Address; import org.onlab.packet.IpAddress; import org.onlab.packet.IpPrefix; -import org.onlab.packet.Ip6Address; +import org.onlab.packet.PIM; import java.nio.ByteBuffer; @@ -66,7 +67,7 @@ public class PIMAddrSource { } private void init() { - this.family = 4; + this.family = PIM.ADDRESS_FAMILY_IP4; this.encType = 0; this.reserved = 0; this.sBit = true; @@ -92,7 +93,7 @@ public class PIMAddrSource { public void setAddr(IpPrefix spfx) { this.addr = spfx.address(); this.masklen = (byte) spfx.prefixLength(); - this.family = (byte) ((this.addr.isIp4()) ? 4 : 6); + this.family = (byte) ((this.addr.isIp4()) ? PIM.ADDRESS_FAMILY_IP4 : PIM.ADDRESS_FAMILY_IP6); } /** @@ -156,7 +157,7 @@ public class PIMAddrSource { */ public int getByteSize() { int size = 4; - size += addr.isIp4() ? 4 : 16; + size += addr.isIp4() ? PIM.ADDRESS_FAMILY_IP4 : PIM.ADDRESS_FAMILY_IP6; return size; } @@ -202,9 +203,9 @@ public class PIMAddrSource { checkInput(bb.array(), bb.position(), bb.limit() - bb.position(), ENC_SOURCE_IPV4_BYTE_LENGTH); this.family = bb.get(); - if (family != 4 && family != 6) { + if (family != PIM.ADDRESS_FAMILY_IP4 && family != PIM.ADDRESS_FAMILY_IP6) { throw new DeserializationException("Illegal IP version number: " + family + "\n"); - } else if (family == 6) { + } else if (family == PIM.ADDRESS_FAMILY_IP6) { // Check for one less by since we have already read the first byte of the packet. checkInput(bb.array(), bb.position(), bb.limit() - bb.position(), ENC_SOURCE_IPV6_BYTE_LENGTH - 1); @@ -226,9 +227,9 @@ public class PIMAddrSource { this.reserved &= 0xf8; this.masklen = bb.get(); - if (this.family == 4) { + if (this.family == PIM.ADDRESS_FAMILY_IP4) { this.addr = IpAddress.valueOf(bb.getInt()); - } else if (this.family == 6) { + } else if (this.family == PIM.ADDRESS_FAMILY_IP6) { this.addr = Ip6Address.valueOf(bb.array(), 2); } return this; diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/PIMAddrUnicast.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/PIMAddrUnicast.java index a6ba3895..3327a8e7 100644 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/PIMAddrUnicast.java +++ b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/PIMAddrUnicast.java @@ -15,10 +15,13 @@ */ package org.onlab.packet.pim; + + import org.onlab.packet.DeserializationException; import org.onlab.packet.Ip4Address; -import org.onlab.packet.IpAddress; import org.onlab.packet.Ip6Address; +import org.onlab.packet.IpAddress; +import org.onlab.packet.PIM; import java.nio.ByteBuffer; @@ -36,7 +39,7 @@ public class PIMAddrUnicast { * PIM Encoded Source Address. */ public PIMAddrUnicast() { - this.family = 4; + this.family = PIM.ADDRESS_FAMILY_IP4; this.encType = 0; } @@ -48,9 +51,9 @@ public class PIMAddrUnicast { public PIMAddrUnicast(String addr) { this.addr = IpAddress.valueOf(addr); if (this.addr.isIp4()) { - this.family = 4; + this.family = PIM.ADDRESS_FAMILY_IP4; } else { - this.family = 6; + this.family = PIM.ADDRESS_FAMILY_IP6; } this.encType = 0; } @@ -63,9 +66,9 @@ public class PIMAddrUnicast { public void setAddr(IpAddress addr) { this.addr = addr; if (this.addr.isIp4()) { - this.family = 4; + this.family = PIM.ADDRESS_FAMILY_IP4; } else { - this.family = 6; + this.family = PIM.ADDRESS_FAMILY_IP6; } } @@ -121,17 +124,17 @@ public class PIMAddrUnicast { this.family = bb.get(); // If we have IPv6 we need to ensure we have adequate buffer space. - if (this.family != 4 && this.family != 6) { + if (this.family != PIM.ADDRESS_FAMILY_IP4 && this.family != PIM.ADDRESS_FAMILY_IP6) { throw new DeserializationException("Invalid address family: " + this.family); - } else if (this.family == 6) { + } else if (this.family == PIM.ADDRESS_FAMILY_IP6) { // Subtract -1 from ENC_UNICAST_IPv6 BYTE_LENGTH because we read one byte for family previously. checkInput(bb.array(), bb.position(), bb.limit() - bb.position(), ENC_UNICAST_IPV6_BYTE_LENGTH - 1); } this.encType = bb.get(); - if (this.family == 4) { + if (this.family == PIM.ADDRESS_FAMILY_IP4) { this.addr = IpAddress.valueOf(bb.getInt()); - } else if (this.family == 6) { + } else if (this.family == PIM.ADDRESS_FAMILY_IP6) { this.addr = Ip6Address.valueOf(bb.array(), 2); } return this; diff --git a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Compiler.java b/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Compiler.java index add71eb5..919cbd5b 100644 --- a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Compiler.java +++ b/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Compiler.java @@ -48,6 +48,7 @@ public class Compiler { private static final String GROUP = "group"; private static final String STEP = "step"; private static final String PARALLEL = "parallel"; + private static final String SEQUENTIAL = "sequential"; private static final String DEPENDENCY = "dependency"; private static final String LOG_DIR = "[@logDir]"; @@ -59,12 +60,16 @@ public class Compiler { private static final String IF = "[@if]"; private static final String UNLESS = "[@unless]"; private static final String VAR = "[@var]"; + private static final String STARTS = "[@starts]"; + private static final String ENDS = "[@ends]"; private static final String FILE = "[@file]"; private static final String NAMESPACE = "[@namespace]"; static final String PROP_START = "${"; static final String PROP_END = "}"; + private static final String HASH = "#"; + private static final String HASH_PREV = "#-1"; private final Scenario scenario; @@ -72,7 +77,7 @@ public class Compiler { private final Map<String, Step> inactiveSteps = Maps.newHashMap(); private final Map<String, String> requirements = Maps.newHashMap(); private final Set<Dependency> dependencies = Sets.newHashSet(); - private final List<Integer> parallels = Lists.newArrayList(); + private final List<Integer> clonables = Lists.newArrayList(); private ProcessFlow processFlow; private File logDir; @@ -175,6 +180,10 @@ public class Compiler { cfg.configurationsAt(PARALLEL) .forEach(c -> processParallelGroup(c, namespace, parentGroup)); + // Scan all sequential groups + cfg.configurationsAt(SEQUENTIAL) + .forEach(c -> processSequentialGroup(c, namespace, parentGroup)); + // Scan all dependencies cfg.configurationsAt(DEPENDENCY) .forEach(c -> processDependency(c, namespace)); @@ -309,14 +318,62 @@ public class Compiler { int i = 1; while (condition(var, i).length() > 0) { - parallels.add(0, i); + clonables.add(0, i); + compile(cfg, namespace, parentGroup); + clonables.remove(0); + i++; + } + } + + /** + * Processes a sequential clone group directive. + * + * @param cfg hierarchical definition + * @param namespace optional namespace + * @param parentGroup optional parent group + */ + private void processSequentialGroup(HierarchicalConfiguration cfg, + String namespace, Group parentGroup) { + String var = cfg.getString(VAR); + String starts = cfg.getString(STARTS); + String ends = cfg.getString(ENDS); + print("sequential var=%s", var); + + int i = 1; + while (condition(var, i).length() > 0) { + clonables.add(0, i); compile(cfg, namespace, parentGroup); - parallels.remove(0); + if (i > 1) { + processSequentialRequirements(starts, ends, namespace); + } + clonables.remove(0); i++; } } /** + * Hooks starts of this sequence tier to the previous tier. + * + * @param starts comma-separated list of start steps + * @param ends comma-separated list of end steps + * @param namespace optional namespace + */ + private void processSequentialRequirements(String starts, String ends, + String namespace) { + for (String s : split(starts)) { + String start = expand(prefix(s, namespace)); + String reqs = requirements.get(s); + for (String n : split(ends)) { + boolean isSoft = n.startsWith("~"); + String name = n.replaceFirst("^~", ""); + name = (isSoft ? "~" : "") + expand(prefix(name, namespace)); + reqs = reqs == null ? name : (reqs + "," + name); + } + requirements.put(start, reqs); + } + } + + /** * Returns the elaborated repetition construct conditional. * * @param var repetition var property @@ -413,9 +470,11 @@ public class Compiler { String prop = pString.substring(start + PROP_START.length(), end); String value; if (prop.equals(HASH)) { - value = parallels.get(0).toString(); + value = Integer.toString(clonables.get(0)); + } else if (prop.equals(HASH_PREV)) { + value = Integer.toString(clonables.get(0) - 1); } else if (prop.endsWith(HASH)) { - pString = pString.replaceFirst("#}", parallels.get(0).toString() + "}"); + pString = pString.replaceFirst("#}", clonables.get(0) + "}"); last = start; continue; } else { diff --git a/framework/src/onos/utils/stc/src/test/java/org/onlab/stc/CompilerTest.java b/framework/src/onos/utils/stc/src/test/java/org/onlab/stc/CompilerTest.java index d70eff08..59b55307 100644 --- a/framework/src/onos/utils/stc/src/test/java/org/onlab/stc/CompilerTest.java +++ b/framework/src/onos/utils/stc/src/test/java/org/onlab/stc/CompilerTest.java @@ -69,8 +69,8 @@ public class CompilerTest { ProcessFlow flow = compiler.processFlow(); assertSame("incorrect scenario", scenario, compiler.scenario()); - assertEquals("incorrect step count", 24, flow.getVertexes().size()); - assertEquals("incorrect dependency count", 16, flow.getEdges().size()); + assertEquals("incorrect step count", 33, flow.getVertexes().size()); + assertEquals("incorrect dependency count", 26, flow.getEdges().size()); assertEquals("incorrect logDir", new File(TEST_DIR.getAbsolutePath(), "foo"), compiler.logDir()); diff --git a/framework/src/onos/utils/stc/src/test/resources/org/onlab/stc/scenario.xml b/framework/src/onos/utils/stc/src/test/resources/org/onlab/stc/scenario.xml index 34e67fd5..533b11ea 100644 --- a/framework/src/onos/utils/stc/src/test/resources/org/onlab/stc/scenario.xml +++ b/framework/src/onos/utils/stc/src/test/resources/org/onlab/stc/scenario.xml @@ -44,4 +44,11 @@ <step name="ding-${#}" exec="asdads" requires="ping-${#},pong-${#}"/> <dependency name="maybe" requires="ding-${#}"/> </parallel> + + <sequential var="${TOC#}" requires="alpha" starts="fifi-${#},gigi-${#}" ends="gaga-${#-1}"> + <step name="fifi-${#}" exec="asdads ${TOC#}"/> + <step name="gigi-${#}" exec="asdads"/> + <step name="gaga-${#}" exec="asdads" requires="fifi-${#},gigi-${#}"/> + <dependency name="maybe" requires="gaga-${#}"/> + </sequential> </scenario>
\ No newline at end of file diff --git a/framework/src/onos/web/gui/src/main/webapp/app/fw/svg/glyph.js b/framework/src/onos/web/gui/src/main/webapp/app/fw/svg/glyph.js index 28f262a1..d8dce362 100644 --- a/framework/src/onos/web/gui/src/main/webapp/app/fw/svg/glyph.js +++ b/framework/src/onos/web/gui/src/main/webapp/app/fw/svg/glyph.js @@ -49,6 +49,8 @@ // otn, roadm_otn, firewall, balancer, ips, ids, // controller, virtual, fiber_switch, other + // NOTE: when adding glyphs, please also update TopoConstants.Glyphs class. + glyphDataSet = { _viewbox: "0 0 110 110", diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoD3.js b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoD3.js index d29748b1..1f061dd6 100644 --- a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoD3.js +++ b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoD3.js @@ -218,6 +218,24 @@ .attr('transform', sus.translate(dx, dy)); } + function updateDeviceBadge(d) { + // TODO: Fix this WIP + var node = d.el, + bsel; + + if (d.badge) { + bsel = node.append('g') + .classed('badge', true) + .attr('transform', sus.translate(-14, -14)); + + bsel.append('circle') + .attr('r', 14); + bsel.append('text') + .attr('transform', sus.translate(-5, 3)) + .text('42'); + } + } + function updateHostLabel(d) { var label = trimLabel(hostLabel(d)); d.el.select('text').text(label); @@ -241,6 +259,7 @@ var node = d.el; node.classed('online', d.online); updateDeviceLabel(d); + updateDeviceBadge(d); api.posNode(d, true); } diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoForce.js b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoForce.js index dbe8f9f5..f00b87fa 100644 --- a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoForce.js +++ b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoForce.js @@ -860,6 +860,16 @@ }); } + function clearNodeDeco() { + node.selectAll('g.badge').remove(); + } + + function removeNodeBadges() { + network.nodes.forEach(function (d) { + d.badge = null; + }); + } + function updateLinkLabelModel() { // create the backing data for showing labels.. var data = []; @@ -923,6 +933,8 @@ function mkOverlayApi() { return { + clearNodeDeco: clearNodeDeco, + removeNodeBadges: removeNodeBadges, clearLinkTrafficStyle: clearLinkTrafficStyle, removeLinkLabels: removeLinkLabels, findLinkById: tms.findLinkById, diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoOverlay.js b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoOverlay.js index 74fa2f24..9a3b4358 100644 --- a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoOverlay.js +++ b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoOverlay.js @@ -294,7 +294,8 @@ unsupLink( key, [less] ) */ - // TODO: clear node highlighting + api.clearNodeDeco(); + api.removeNodeBadges(); api.clearLinkTrafficStyle(); api.removeLinkLabels(); @@ -319,8 +320,11 @@ }); data.devices.forEach(function (device) { - var ddata = api.findNodeById(device.id); + var ddata = api.findNodeById(device.id), + badgeData = device.badge || null; + if (ddata && !ddata.el.empty()) { + ddata.badge = badgeData; if (!device.subdue) { api.unsupNode(ddata.id, less); } diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_1_addInstance.json b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_1_addInstance.json new file mode 100644 index 00000000..cdb95361 --- /dev/null +++ b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_1_addInstance.json @@ -0,0 +1,14 @@ +{ + "event": "addInstance", + "payload": { + "id": "ONOS", + "ip": "192.168.56.101", + "online": true, + "uiAttached": true, + "switches": 2, + "labels": [ + "ONOS", + "192.168.56.101" + ] + } +} diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_2_addDevice_s1.json b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_2_addDevice_s1.json new file mode 100644 index 00000000..2e9d30f2 --- /dev/null +++ b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_2_addDevice_s1.json @@ -0,0 +1,18 @@ +{ + "event": "addDevice", + "payload": { + "id": "of:0000000000000001", + "type": "switch", + "online": true, + "master": "ONOS", + "labels": [ + "", + "switch-1", + "of:0000000000000001" + ], + "metaUi": { + "x": 200, + "y": 200 + } + } +} diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_3_addDevice_s2.json b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_3_addDevice_s2.json new file mode 100644 index 00000000..79c04d3a --- /dev/null +++ b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_3_addDevice_s2.json @@ -0,0 +1,18 @@ +{ + "event": "addDevice", + "payload": { + "id": "of:0000000000000002", + "type": "switch", + "online": true, + "master": "ONOS", + "labels": [ + "", + "switch-2", + "of:0000000000000002" + ], + "metaUi": { + "x": 400, + "y": 220 + } + } +} diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_4_addLink_1_2.json b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_4_addLink_1_2.json new file mode 100644 index 00000000..fb952837 --- /dev/null +++ b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_4_addLink_1_2.json @@ -0,0 +1,16 @@ +{ + "event": "addLink", + "payload": { + "id": "of:0000000000000001/5-of:0000000000000002/7", + "type": "direct", + "online": true, + "linkWidth": 2, + "src": "of:0000000000000001", + "srcPort": "5", + "dst": "of:0000000000000002", + "dstPort": "7", + "props" : { + "BW": "70 Gb" + } + } +} diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_5_showHighlights_clear.json b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_5_showHighlights_clear.json new file mode 100644 index 00000000..615efd25 --- /dev/null +++ b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_5_showHighlights_clear.json @@ -0,0 +1,8 @@ +{ + "event": "showHighlights", + "payload": { + "devices": [], + "hosts": [], + "links": [] + } +} diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_6_showHighlights_stuff.json b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_6_showHighlights_stuff.json new file mode 100644 index 00000000..74c42c5c --- /dev/null +++ b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_6_showHighlights_stuff.json @@ -0,0 +1,30 @@ +{ + "event": "showHighlights", + "payload": { + "devices": [ + { + "id": "of:0000000000000001", + "badge": { + "status": "e", + "gid": "xMark", + "msg": "x marks the spot" + } + }, + { + "id": "of:0000000000000002", + "badge": { + "status": "w", + "txt": "7" + } + } + ], + "hosts": [], + "links": [ + { + "css": "primary", + "id": "of:0000000000000001/5-of:0000000000000002/7", + "label": "Antz!" + } + ] + } +} diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_7_showHighlights_clear.json b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_7_showHighlights_clear.json new file mode 100644 index 00000000..615efd25 --- /dev/null +++ b/framework/src/onos/web/gui/src/test/_karma/ev/badges/ev_7_showHighlights_clear.json @@ -0,0 +1,8 @@ +{ + "event": "showHighlights", + "payload": { + "devices": [], + "hosts": [], + "links": [] + } +} diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/badges/scenario.json b/framework/src/onos/web/gui/src/test/_karma/ev/badges/scenario.json new file mode 100644 index 00000000..0ca4f4f4 --- /dev/null +++ b/framework/src/onos/web/gui/src/test/_karma/ev/badges/scenario.json @@ -0,0 +1,12 @@ +{ + "comments": [ + "Demo of adding badges to devices" + ], + "title": "Demo adding badges", + "params": { + "lastAuto": 5 + }, + "description": [ + "Demonstrate the device badging feature." + ] +} diff --git a/framework/src/onos/web/gui/src/test/_karma/ev/traffic/scenario.json b/framework/src/onos/web/gui/src/test/_karma/ev/traffic/scenario.json index 57c03733..4e7ce4f8 100644 --- a/framework/src/onos/web/gui/src/test/_karma/ev/traffic/scenario.json +++ b/framework/src/onos/web/gui/src/test/_karma/ev/traffic/scenario.json @@ -1,6 +1,8 @@ { "comments": [ - "Stepping through showTraffic" + "Stepping through showTraffic", + "NOTE: showTraffic event is deprecated", + " This needs to be re-worked to use showHighlights" ], "title": "Show Traffic Scenario", "params": { |