diff options
Diffstat (limited to 'framework/src/onos/providers')
27 files changed, 1699 insertions, 1939 deletions
diff --git a/framework/src/onos/providers/bgp/topology/src/test/java/org/onosproject/provider/bgp/topology/impl/BgpTopologyProviderTest.java b/framework/src/onos/providers/bgp/topology/src/test/java/org/onosproject/provider/bgp/topology/impl/BgpTopologyProviderTest.java index 30bb4470..37576e44 100755 --- a/framework/src/onos/providers/bgp/topology/src/test/java/org/onosproject/provider/bgp/topology/impl/BgpTopologyProviderTest.java +++ b/framework/src/onos/providers/bgp/topology/src/test/java/org/onosproject/provider/bgp/topology/impl/BgpTopologyProviderTest.java @@ -31,6 +31,7 @@ import org.onosproject.bgp.controller.BgpCfg; import org.onosproject.bgp.controller.BgpController; import org.onosproject.bgp.controller.BgpId; import org.onosproject.bgp.controller.BgpPeer; +import org.onosproject.bgp.controller.BgpLocalRib; import org.onosproject.bgp.controller.BgpNodeListener; import org.onosproject.bgp.controller.BgpPeerManager; import org.onosproject.bgpio.exceptions.BgpParseException; @@ -208,6 +209,17 @@ public class BgpTopologyProviderTest { return 0; } + @Override + public BgpLocalRib bgpLocalRibVpn() { + // TODO Auto-generated method stub + return null; + } + + @Override + public BgpLocalRib bgpLocalRib() { + // TODO Auto-generated method stub + return null; + } @Override public BgpPeerManager peerManager() { diff --git a/framework/src/onos/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LldpLinkProvider.java b/framework/src/onos/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LldpLinkProvider.java index 94abebaa..668d59c0 100644 --- a/framework/src/onos/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LldpLinkProvider.java +++ b/framework/src/onos/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LldpLinkProvider.java @@ -570,7 +570,7 @@ public class LldpLinkProvider extends AbstractProvider implements LinkProvider { case DEVICE_AVAILABILITY_CHANGED: if (deviceService.isAvailable(deviceId)) { log.debug("Device up {}", deviceId); - updateDevice(device); + updateDevice(device).ifPresent(ld -> updatePorts(ld, deviceId)); } else { log.debug("Device down {}", deviceId); removeDevice(deviceId); diff --git a/framework/src/onos/providers/netcfghost/pom.xml b/framework/src/onos/providers/netcfghost/pom.xml new file mode 100644 index 00000000..15363c8d --- /dev/null +++ b/framework/src/onos/providers/netcfghost/pom.xml @@ -0,0 +1,65 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ 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. + --> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <artifactId>onos-providers</artifactId> + <groupId>org.onosproject</groupId> + <version>1.4.0-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>onos-netcfg-host-provider</artifactId> + <packaging>bundle</packaging> + + <description> + Host provider that uses network config service to discover hosts. + </description> + <url>http://onosproject.org</url> + + <properties> + <onos.app.name>org.onosproject.netcfghostprovider</onos.app.name> + <onos.app.origin>ON.Lab</onos.app.origin> + </properties> + + <dependencies> + <dependency> + <groupId>org.onosproject</groupId> + <artifactId>onos-api</artifactId> + </dependency> + + <dependency> + <groupId>org.onosproject</groupId> + <artifactId>onlab-osgi</artifactId> + </dependency> + + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.11</version> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.easymock</groupId> + <artifactId>easymock</artifactId> + <scope>test</scope> + </dependency> + </dependencies> + +</project> diff --git a/framework/src/onos/providers/netcfghost/src/main/java/org/onosproject/provider/netcfghost/NetworkConfigHostProvider.java b/framework/src/onos/providers/netcfghost/src/main/java/org/onosproject/provider/netcfghost/NetworkConfigHostProvider.java new file mode 100644 index 00000000..767cfb7f --- /dev/null +++ b/framework/src/onos/providers/netcfghost/src/main/java/org/onosproject/provider/netcfghost/NetworkConfigHostProvider.java @@ -0,0 +1,196 @@ +/* + * Copyright 2014-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.provider.netcfghost; + +import org.apache.felix.scr.annotations.Activate; +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Deactivate; +import org.apache.felix.scr.annotations.Reference; +import org.apache.felix.scr.annotations.ReferenceCardinality; +import org.onlab.packet.IpAddress; +import org.onlab.packet.MacAddress; +import org.onlab.packet.VlanId; +import org.onosproject.core.ApplicationId; +import org.onosproject.core.CoreService; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.Host; +import org.onosproject.net.HostId; +import org.onosproject.net.HostLocation; +import org.onosproject.net.config.NetworkConfigEvent; +import org.onosproject.net.config.NetworkConfigListener; +import org.onosproject.net.config.NetworkConfigRegistry; +import org.onosproject.net.config.basics.BasicHostConfig; +import org.onosproject.net.host.DefaultHostDescription; +import org.onosproject.net.host.HostDescription; +import org.onosproject.net.host.HostProvider; +import org.onosproject.net.host.HostProviderRegistry; +import org.onosproject.net.host.HostProviderService; +import org.onosproject.net.provider.AbstractProvider; +import org.onosproject.net.provider.ProviderId; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.util.Set; + +/** + * Host provider that uses network config service to discover hosts. + */ +@Component(immediate = true) +public class NetworkConfigHostProvider extends AbstractProvider implements HostProvider { + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected CoreService coreService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected HostProviderRegistry providerRegistry; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected NetworkConfigRegistry networkConfigRegistry; + + private static final String APP_NAME = "org.onosproject.provider.netcfghost"; + private ApplicationId appId; + protected HostProviderService providerService; + + private final Logger log = LoggerFactory.getLogger(getClass()); + private final InternalNetworkConfigListener networkConfigListener = + new InternalNetworkConfigListener(); + + /** + * Creates an network config host location provider. + */ + public NetworkConfigHostProvider() { + super(new ProviderId("host", APP_NAME)); + } + + @Activate + protected void activate() { + appId = coreService.registerApplication(APP_NAME); + providerService = providerRegistry.register(this); + networkConfigRegistry.addListener(networkConfigListener); + readInitialConfig(); + log.info("Started"); + } + + @Deactivate + protected void deactivate() { + networkConfigRegistry.removeListener(networkConfigListener); + providerRegistry.unregister(this); + providerService = null; + log.info("Stopped"); + } + + @Override + public void triggerProbe(Host host) { + /* + * Note: In CORD deployment, we assume that all hosts are configured. + * Therefore no probe is required. + */ + } + + /** + * Adds host information. + * IP information will be appended if host exists. + * + * @param mac MAC address of the host + * @param vlan VLAN ID of the host + * @param hloc Location of the host + * @param ips Set of IP addresses of the host + */ + protected void addHost(MacAddress mac, VlanId vlan, HostLocation hloc, Set<IpAddress> ips) { + HostId hid = HostId.hostId(mac, vlan); + HostDescription desc = new DefaultHostDescription(mac, vlan, hloc, ips); + providerService.hostDetected(hid, desc, false); + } + + /** + * Updates host information. + * IP information will be replaced if host exists. + * + * @param mac MAC address of the host + * @param vlan VLAN ID of the host + * @param hloc Location of the host + * @param ips Set of IP addresses of the host + */ + protected void updateHost(MacAddress mac, VlanId vlan, HostLocation hloc, Set<IpAddress> ips) { + HostId hid = HostId.hostId(mac, vlan); + HostDescription desc = new DefaultHostDescription(mac, vlan, hloc, ips); + providerService.hostDetected(hid, desc, true); + } + + /** + * Removes host information. + * + * @param mac MAC address of the host + * @param vlan VLAN ID of the host + */ + protected void removeHost(MacAddress mac, VlanId vlan) { + HostId hid = HostId.hostId(mac, vlan); + providerService.hostVanished(hid); + } + + private void readInitialConfig() { + networkConfigRegistry.getSubjects(HostId.class).forEach(hostId -> { + MacAddress mac = hostId.mac(); + VlanId vlan = hostId.vlanId(); + BasicHostConfig hostConfig = + networkConfigRegistry.getConfig(hostId, BasicHostConfig.class); + Set<IpAddress> ipAddresses = hostConfig.ipAddresses(); + ConnectPoint location = hostConfig.location(); + HostLocation hloc = new HostLocation(location, System.currentTimeMillis()); + addHost(mac, vlan, hloc, ipAddresses); + }); + } + + private class InternalNetworkConfigListener implements NetworkConfigListener { + @Override + public void event(NetworkConfigEvent event) { + // Do not process non-host, register and unregister events + if (!event.configClass().equals(BasicHostConfig.class) || + event.type() == NetworkConfigEvent.Type.CONFIG_REGISTERED || + event.type() == NetworkConfigEvent.Type.CONFIG_UNREGISTERED) { + return; + } + + HostId hostId = (HostId) event.subject(); + MacAddress mac = hostId.mac(); + VlanId vlan = hostId.vlanId(); + BasicHostConfig hostConfig = + networkConfigRegistry.getConfig(hostId, BasicHostConfig.class); + Set<IpAddress> ipAddresses = null; + HostLocation hloc = null; + + // Note: There will be no config presented in the CONFIG_REMOVE case + if (hostConfig != null) { + ipAddresses = hostConfig.ipAddresses(); + ConnectPoint location = hostConfig.location(); + hloc = new HostLocation(location, System.currentTimeMillis()); + } + + switch (event.type()) { + case CONFIG_ADDED: + addHost(mac, vlan, hloc, ipAddresses); + break; + case CONFIG_UPDATED: + updateHost(mac, vlan, hloc, ipAddresses); + break; + case CONFIG_REMOVED: + removeHost(mac, vlan); + break; + default: + break; + } + } + } +} diff --git a/framework/src/onos/providers/netcfghost/src/main/java/org/onosproject/provider/netcfghost/package-info.java b/framework/src/onos/providers/netcfghost/src/main/java/org/onosproject/provider/netcfghost/package-info.java new file mode 100644 index 00000000..a56b9a80 --- /dev/null +++ b/framework/src/onos/providers/netcfghost/src/main/java/org/onosproject/provider/netcfghost/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2014-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. + */ + +/** + * Host provider that uses network config service to discover hosts. + */ +package org.onosproject.provider.netcfghost; diff --git a/framework/src/onos/providers/netcfghost/src/test/java/org/onosproject/provider/netcfghost/NetworkConfigHostProviderTest.java b/framework/src/onos/providers/netcfghost/src/test/java/org/onosproject/provider/netcfghost/NetworkConfigHostProviderTest.java new file mode 100644 index 00000000..a4f057cf --- /dev/null +++ b/framework/src/onos/providers/netcfghost/src/test/java/org/onosproject/provider/netcfghost/NetworkConfigHostProviderTest.java @@ -0,0 +1,132 @@ +/* + * Copyright 2014-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.provider.netcfghost; + +import org.junit.Before; +import org.junit.Test; +import org.onlab.packet.IpAddress; +import org.onlab.packet.MacAddress; +import org.onlab.packet.VlanId; +import org.onosproject.net.DeviceId; +import org.onosproject.net.HostId; +import org.onosproject.net.HostLocation; +import org.onosproject.net.PortNumber; +import org.onosproject.net.host.DefaultHostDescription; +import org.onosproject.net.host.HostDescription; +import org.onosproject.net.host.HostProvider; +import org.onosproject.net.host.HostProviderService; +import org.onosproject.net.provider.AbstractProviderService; + +import java.util.HashSet; +import java.util.Set; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThat; + +/** + * Set of tests of the host location provider for CORD. + */ +public class NetworkConfigHostProviderTest { + private NetworkConfigHostProvider provider = new NetworkConfigHostProvider(); + private MockHostProviderService providerService = new MockHostProviderService(provider); + + private MacAddress mac = MacAddress.valueOf("c0:ff:ee:c0:ff:ee"); + private VlanId vlan = VlanId.vlanId(VlanId.UNTAGGED); + private DeviceId deviceId = DeviceId.deviceId("of:0000000000000001"); + private PortNumber port = PortNumber.portNumber(5); + private HostLocation hloc = new HostLocation(deviceId, port, 100); + private Set<IpAddress> ips = new HashSet<>(); + private HostId hostId = HostId.hostId(mac, vlan); + private HostDescription hostDescription; + + @Before + public void setUp() { + provider.providerService = providerService; + + // Initialize test variables + ips.add(IpAddress.valueOf("10.0.0.1")); + ips.add(IpAddress.valueOf("192.168.0.1")); + hostDescription = new DefaultHostDescription(mac, vlan, hloc, ips); + } + + @Test + public void testAddHost() throws Exception { + provider.addHost(mac, vlan, hloc, ips); + assertThat(providerService.hostId, is(hostId)); + assertThat(providerService.hostDescription, is(hostDescription)); + assertThat(providerService.event, is("hostDetected")); + providerService.clear(); + } + + @Test + public void testUpdateHost() throws Exception { + provider.updateHost(mac, vlan, hloc, ips); + assertThat(providerService.hostId, is(hostId)); + assertThat(providerService.hostDescription, is(hostDescription)); + assertThat(providerService.event, is("hostDetected")); + providerService.clear(); + } + + @Test + public void testRemoveHost() throws Exception { + provider.removeHost(mac, vlan); + assertThat(providerService.hostId, is(hostId)); + assertNull(providerService.hostDescription); + assertThat(providerService.event, is("hostVanished")); + providerService.clear(); + } + + /** + * Mock HostProviderService. + */ + private class MockHostProviderService + extends AbstractProviderService<HostProvider> + implements HostProviderService { + private HostId hostId = null; + private HostDescription hostDescription = null; + private String event = null; + + public MockHostProviderService(HostProvider provider) { + super(provider); + } + + @Override + public void hostDetected(HostId hostId, HostDescription hostDescription, boolean replaceIps) { + this.hostId = hostId; + this.hostDescription = hostDescription; + this.event = "hostDetected"; + } + + @Override + public void hostVanished(HostId hostId) { + this.hostId = hostId; + this.event = "hostVanished"; + } + + @Override + public void removeIpFromHost(HostId hostId, IpAddress ipAddress) { + // Note: This method is never used. + } + + public void clear() { + this.hostId = null; + this.hostDescription = null; + this.event = null; + } + } +} diff --git a/framework/src/onos/providers/netconf/app/pom.xml b/framework/src/onos/providers/netconf/app/pom.xml index 4a19ae8e..0aa55ff5 100644 --- a/framework/src/onos/providers/netconf/app/pom.xml +++ b/framework/src/onos/providers/netconf/app/pom.xml @@ -37,12 +37,7 @@ <artifactId>onos-netconf-provider-device</artifactId> <version>${project.version}</version> </dependency> - <dependency> - <groupId>org.onosproject</groupId> - <artifactId>onos-netconf-provider-flow</artifactId> - <version>${project.version}</version> - </dependency> - <!-- TODO: add other dependencies here as more bundles are added to the app --> + <!-- Add other dependencies here as more bundles are added to the app --> </dependencies> </project> diff --git a/framework/src/onos/providers/netconf/flow/pom.xml b/framework/src/onos/providers/netconf/flow/pom.xml deleted file mode 100644 index 7ccd552f..00000000 --- a/framework/src/onos/providers/netconf/flow/pom.xml +++ /dev/null @@ -1,259 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ 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. - --> -<project xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> - <modelVersion>4.0.0</modelVersion> - - <parent> - <groupId>org.onosproject</groupId> - <artifactId>onos-netconf-providers</artifactId> - <version>1.4.0-SNAPSHOT</version> - <relativePath>../pom.xml</relativePath> - </parent> - - <artifactId>onos-netconf-provider-flow</artifactId> - <packaging>bundle</packaging> - - <dependencies> - <dependency> - <groupId>org.osgi</groupId> - <artifactId>org.osgi.compendium</artifactId> - </dependency> - <dependency> - <groupId>ch.ethz.ganymed</groupId> - <artifactId>ganymed-ssh2</artifactId> - <version>262</version> - </dependency> - <dependency> - <!-- TODO: change this appropriately when the official TailF JNC is available --> - <groupId>org.onosproject</groupId> - <artifactId>jnc</artifactId> - <version>1.0</version> - </dependency> - <dependency> - <groupId>org.jdom</groupId> - <artifactId>jdom2</artifactId> - <version>2.0.5</version> - </dependency> - <dependency> - <groupId>jaxen</groupId> - <artifactId>jaxen</artifactId> - <version>1.1.4</version> - <optional>true</optional> - </dependency> - <dependency> - <groupId>org.osgi</groupId> - <artifactId>org.osgi.core</artifactId> - </dependency> - <dependency> - <groupId>org.onosproject</groupId> - <artifactId>onlab-junit</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.easymock</groupId> - <artifactId>easymock</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.onosproject</groupId> - <artifactId>onos-yang-tool</artifactId> - <version>1.3</version> - </dependency> - </dependencies> - - <build> - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-shade-plugin</artifactId> - <version>2.3</version> - <configuration> - <filters> - <filter> - <artifact>com.tailf:JNC</artifact> - <includes> - <include>com/tailf/jnc/**</include> - </includes> - </filter> - <filter> - <artifact>ch.ethz.ganymed:ganymed-ssh2</artifact> - <includes> - <include>ch/ethz/ssh2/**</include> - </includes> - </filter> - <filter> - <artifact>org.jdom:jdom2</artifact> - <includes> - <include>org/jdom2/**</include> - </includes> - </filter> - <filter> - <artifact>org.onosproject:onos-yang-tool</artifact> - <includes> - <include>org/opendaylight/yang/gen/**</include> - </includes> - </filter> - </filters> - </configuration> - <executions> - <execution> - <phase>package</phase> - <goals> - <goal>shade</goal> - </goals> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-scr-plugin</artifactId> - </plugin> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-bundle-plugin</artifactId> - <configuration> - <instructions> - <Export-Package> - com.tailf.jnc, - ch.ethz.ssh2, - ch.ethz.ssh2.auth, - ch.ethz.ssh2.channel, - ch.ethz.ssh2.crypto, - ch.ethz.ssh2.crypto.cipher, - ch.ethz.ssh2.crypto.dh, - ch.ethz.ssh2.crypto.digest, - ch.ethz.ssh2.log, - ch.ethz.ssh2.packets, - ch.ethz.ssh2.server, - ch.ethz.ssh2.sftp, - ch.ethz.ssh2.signature, - ch.ethz.ssh2.transport, - ch.ethz.ssh2.util, - org.jdom2, - org.jdom2.input, - org.jdom2.output, - org.jdom2.adapters, - org.jdom2.filter, - org.jdom2.internal, - org.jdom2.located, - org.jdom2.transform, - org.jdom2.util, - org.jdom2.xpath, - org.jdom2.input.sax, - org.jdom2.input.stax, - org.jdom2.output.support, - org.jdom2.xpath.jaxen, - org.jdom2.xpath.util, - org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520, - org.opendaylight.yangtools.yang.data.impl.schema.tree, - org.opendaylight.yangtools.yang.data.impl.codec, - org.opendaylight.yangtools.yang.model.parser.api, - org.opendaylight.yangtools.yang.data.impl.schema.nodes, - org.opendaylight.yangtools.yang.binding.util, - org.opendaylight.yangtools.yang.data.impl, - org.opendaylight.yangtools.sal.binding.generator.impl, - org.opendaylight.yangtools.yang.parser.impl.util, - org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.packet.fields.rev140625, - org.opendaylight.yangtools.yang.data.api, - org.opendaylight.yangtools.objcache.spi, - org.opendaylight.yangtools.yang.data.impl.schema.transform.base.parser, - org.opendaylight.yangtools.maven.sal.api.gen.plugin, - org.opendaylight.yangtools.yang.data.impl.schema.builder.impl, - org.opendaylight.yangtools.yang.data.api.schema.tree, - org.opendaylight.yangtools.binding.generator.util, - org.opendaylight.yangtools.sal.binding.generator.spi, - org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715, - org.opendaylight.yangtools.yang2sources.spi, - org.opendaylight.yangtools.yang.model.repo.api, - org.opendaylight.yangtools.util, - org.opendaylight.yangtools.yang.parser.util, - org.opendaylight.yangtools.yang.data.api.schema.stream, - org.opendaylight.yangtools.yang.data.impl.schema.transform.base.serializer, - org.opendaylight.yangtools.concepts, - org.opendaylight.yangtools.yang.binding, - org.opendaylight.yangtools.yang.model.util.repo, - org.opendaylight.yangtools.yang.wadl.generator.maven, - org.opendaylight.yangtools.yang.data.api.schema, - org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.access.list.access.list.entries.matches.ace.type, - org.opendaylight.yangtools.concepts.util, - org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.access.list.access.list.entries, - org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.access.list.access.list.entries.matches.ace.type.ace.ip.ace.ip.version, - org.opendaylight.yangtools.sal.binding.model.api, - org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.access.list.access.list.entries.matches.ace.type.ace.ip, - org.opendaylight.yangtools.yang.data.impl.schema.builder.api, - org.opendaylight.yangtools.util.concurrent, - org.opendaylight.yangtools.yang.parser.builder.impl, - org.opendaylight.yangtools.yang.data.impl.schema.transform.base, - org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.access.list.access.list.entries.actions.packet.handling, - org.opendaylight.yangtools.sal.binding.model.api.type.builder, - org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.packet.fields.rev140625.acl.transport.header.fields, - org.opendaylight.yangtools.yang2sources.plugin, - org.opendaylight.yangtools.yang.data.impl.codec.xml, - org.opendaylight.yangtools.antlrv4.code.gen, - org.opendaylight.yangtools.yang.parser.builder.util, - org.opendaylight.yangtools.yang.data.impl.schema.transform, - org.opendaylight.yangtools.yang.model.api.type, - org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.serializer, - org.opendaylight.yangtools.yang.data.api.schema.tree.spi, - org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser, - org.opendaylight.yangtools.sal.binding.yang.types, - org.opendaylight.yangtools.yang.data.impl.schema.transform.dom, - org.opendaylight.yangtools.yang.data.impl.util, - org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.packet.fields.rev140625.timerange, - org.opendaylight.yangtools.sal.binding.generator.api, - org.opendaylight.yangtools.sal.java.api.generator, - org.opendaylight.yangtools.yang.binding.annotations, - org.opendaylight.yangtools.sal.binding.generator.util, - org.opendaylight.yangtools.yang.model.repo.util, - org.opendaylight.yangtools.yang.model.api, - org.opendaylight.yangtools.yang.common, - org.opendaylight.yangtools.yang.wadl.generator, - org.opendaylight.yangtools.yang.parser.builder.api, - org.opendaylight.yangtools.yang.model.util, - org.opendaylight.yangtools.yang.parser.impl, - org.opendaylight.yangtools.yang.data.impl.schema, - org.opendaylight.yangtools.yang.data.api.codec, - org.opendaylight.yangtools.yang.unified.doc.generator, - org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.access.list, - org.opendaylight.yangtools.objcache, - org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.access.list.access.list.entries.actions, - org.opendaylight.yangtools.yang.data.util, - org.opendaylight.yangtools.yang.unified.doc.generator.maven, - org.opendaylight.yangtools.binding.generator.util.generated.type.builder, - org.opendaylight.yangtools.yang.model.repo.spi, - org.opendaylight.yangtools.yang.parser.repo, - org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715, - org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.access.list.access.list.entries.matches, - org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.valid, - com.romix.scala, - com.romix.scala.collection, - com.romix.scala.collection.concurrent, - org.opendaylight.yangtools.objcache.impl - </Export-Package> - </instructions> - </configuration> - </plugin> - <plugin> - <groupId>org.onosproject</groupId> - <artifactId>onos-maven-plugin</artifactId> - </plugin> - </plugins> - </build> - -</project> diff --git a/framework/src/onos/providers/netconf/flow/src/main/java/org/onosproject/provider/netconf/flow/impl/NetconfFlowRuleProvider.java b/framework/src/onos/providers/netconf/flow/src/main/java/org/onosproject/provider/netconf/flow/impl/NetconfFlowRuleProvider.java deleted file mode 100644 index b29d687e..00000000 --- a/framework/src/onos/providers/netconf/flow/src/main/java/org/onosproject/provider/netconf/flow/impl/NetconfFlowRuleProvider.java +++ /dev/null @@ -1,403 +0,0 @@ -/* - * 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.provider.netconf.flow.impl; - -import static com.google.common.base.Strings.isNullOrEmpty; -import static org.onlab.util.Tools.get; -import static org.slf4j.LoggerFactory.getLogger; - -import java.net.URI; -import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Dictionary; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.TimeUnit; - -import org.apache.felix.scr.annotations.Activate; -import org.apache.felix.scr.annotations.Component; -import org.apache.felix.scr.annotations.Deactivate; -import org.apache.felix.scr.annotations.Modified; -import org.apache.felix.scr.annotations.Reference; -import org.apache.felix.scr.annotations.ReferenceCardinality; -import org.jboss.netty.util.HashedWheelTimer; -import org.jboss.netty.util.Timeout; -import org.jboss.netty.util.TimerTask; -import org.onlab.util.Timer; -import org.onosproject.core.ApplicationId; -import org.onosproject.net.DeviceId; -import org.onosproject.net.flow.FlowEntry; -import org.onosproject.net.flow.FlowRule; -import org.onosproject.net.flow.FlowRuleBatchOperation; -import org.onosproject.net.flow.FlowRuleProvider; -import org.onosproject.net.flow.FlowRuleProviderRegistry; -import org.onosproject.net.flow.FlowRuleProviderService; -import org.onosproject.net.provider.AbstractProvider; -import org.onosproject.net.provider.ProviderId; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.AccessList; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.AccessListBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.access.list.AccessListEntries; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.access.list.AccessListEntriesBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.access.list.access.list.entries.ActionsBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.access.list.access.list.entries.Matches; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.access.list.access.list.entries.MatchesBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.access.list.access.list.entries.actions.packet.handling.DenyBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.access.list.access.list.entries.actions.packet.handling.PermitBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.access.list.access.list.entries.matches.ace.type.AceIp; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.access.list.access.list.entries.matches.ace.type.AceIpBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.access.list.access.list.entries.matches.ace.type.ace.ip.ace.ip.version.AceIpv4; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.access.list.access.list.entries.matches.ace.type.ace.ip.ace.ip.version.AceIpv4Builder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.packet.fields.rev140625.acl.transport.header.fields.DestinationPortRange; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.packet.fields.rev140625.acl.transport.header.fields.DestinationPortRangeBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.packet.fields.rev140625.acl.transport.header.fields.SourcePortRange; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.packet.fields.rev140625.acl.transport.header.fields.SourcePortRangeBuilder; -import org.osgi.service.component.ComponentContext; -import org.slf4j.Logger; - -/** - * Netconf provider to accept any flow and report them. - */ -@Component(immediate = true) -public class NetconfFlowRuleProvider extends AbstractProvider - implements FlowRuleProvider { - private final Logger log = getLogger(getClass()); - - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) - protected FlowRuleProviderRegistry providerRegistry; - - private ConcurrentMap<DeviceId, Set<FlowEntry>> flowTable = new ConcurrentHashMap<>(); - - private FlowRuleProviderService providerService; - - private XmlBuilder xmlBuilder; - - private AceIp aceIp; - private SourcePortRange srcPortRange; - private DestinationPortRange destPortRange; - private Matches matches; - private HashedWheelTimer timer = Timer.getTimer(); - private Timeout timeout; - private static final String ACL_NAME_KEY = "acl-name"; - private static final String ACL_LIST_ENTRIES_RULE_NAME_KEY = "access-list-entries.rule-name"; - private static final String ACL_LIST_SP_LOWER_KEY = "source-port-range.lower-port"; - private static final String ACL_LIST_SP_UPPER_KEY = "source-port-range.upper-port"; - private static final String ACL_LIST_DP_LOWER_KEY = "destination-port-range.lower-port"; - private static final String ACL_LIST_DP_UPPER_KEY = "destination-port-range.upper-port"; - private static final String ACL_LIST_DEST_IPV4_KEY = "matches.destination-ipv4-address"; - private static final String ACL_LIST_SRC_IPV4_KEY = "matches.source-ipv4-address"; - private static final String ACL_LIST_ACTIONS_KEY = "actions"; - - public NetconfFlowRuleProvider() { - super(new ProviderId("netconf", "org.onosproject.provider.netconf")); - } - - @Activate - public void activate(ComponentContext context) { - providerService = providerRegistry.register(this); - timeout = timer.newTimeout(new StatisticTask(), 5, TimeUnit.SECONDS); - applyRule(); - modified(context); - log.info("Started"); - } - - @Deactivate - public void deactivate() { - providerRegistry.unregister(this); - providerService = null; - timeout.cancel(); - log.info("Stopped"); - } - - @Modified - public void modified(ComponentContext context) { - if (xmlBuilder == null) { - xmlBuilder = new XmlBuilder(); - } - if (context == null) { - log.info("No configuration file"); - return; - } - Dictionary<?, ?> properties = context.getProperties(); - String deviceEntry = get(properties, "devConfigs"); - log.info("Settings: devConfigs={}", deviceEntry); - Enumeration<?> elements = properties.keys(); - Object nextElement = elements.nextElement(); - while (elements.hasMoreElements()) { - if (nextElement instanceof String) { - log.info("key::" + nextElement + ", value::" - + get(properties, (String) nextElement)); - } - nextElement = elements.nextElement(); - } - if (!isNullOrEmpty(deviceEntry)) { - Map<String, String> deviceMap = processDeviceEntry(deviceEntry); - AccessList accessList = buildAccessList(properties); - String xmlMsg = xmlBuilder.buildAclRequestXml(accessList); - log.info("The resultant xml from the builder\n" + xmlMsg); - NetconfOperation netconfOperation = new NetconfOperation(); - netconfOperation.sendXmlMessage(xmlMsg, deviceMap.get("username"), - deviceMap.get("password"), - deviceMap.get("hostIp"), Integer - .parseInt(deviceMap - .get("hostPort"))); - } - } - - /** - * @param properties - * @return accessList - */ - private AccessList buildAccessList(Dictionary<?, ?> properties) { - /** - * Populating Access List. - */ - AccessListBuilder abuilder = new AccessListBuilder(); - String aclName = get(properties, ACL_NAME_KEY); - if (aclName != null) { - abuilder.setAclName(aclName); - } - AccessList accessList = abuilder.build(); - abuilder.setAccessListEntries(getAccessListEntries(properties, matches)); - srcPortRange = getSourcePortRange(properties); - destPortRange = getDestinationPortRange(properties); - aceIp = getAceIp(properties, srcPortRange, destPortRange); - matches = getMatches(properties); - return accessList; - } - - /** - * @param properties - * @return matches - */ - private Matches getMatches(Dictionary<?, ?> properties) { - /** - * Building Matches for given ACL model. - */ - MatchesBuilder matchesBuilder = new MatchesBuilder(); - if (aceIp != null) { - matchesBuilder.setAceType(aceIp); - } - matches = matchesBuilder.build(); - return matches; - } - - /** - * @param properties - * @return srcPortRange - */ - private SourcePortRange getSourcePortRange(Dictionary<?, ?> properties) { - /** - * Building Source Port Range for given ACL model. - */ - String spRangeLowerStr = get(properties, ACL_LIST_SP_LOWER_KEY); - String spRangeUpperStr = get(properties, ACL_LIST_SP_UPPER_KEY); - SourcePortRangeBuilder srcPortRangeBuilder = new SourcePortRangeBuilder(); - if (spRangeLowerStr != null) { - int spRangeLower = Integer.parseInt(spRangeLowerStr); - srcPortRangeBuilder.setLowerPort(new PortNumber(spRangeLower)); - } - if (spRangeUpperStr != null) { - int spRangeUpper = Integer.parseInt(spRangeUpperStr); - srcPortRangeBuilder.setUpperPort(new PortNumber(spRangeUpper)); - } - srcPortRange = srcPortRangeBuilder.build(); - return srcPortRange; - } - - /** - * @param properties - * @return destPortRange - */ - private DestinationPortRange getDestinationPortRange(Dictionary<?, ?> properties) { - /** - * Building Destination Port Range for given ACL model. - */ - String dpRangeLowerStr = get(properties, ACL_LIST_DP_LOWER_KEY); - String dpRangeUpperStr = get(properties, ACL_LIST_DP_UPPER_KEY); - DestinationPortRangeBuilder destPortRangeBuilder = new DestinationPortRangeBuilder(); - if (dpRangeLowerStr != null) { - int dpRangeLower = Integer.parseInt(dpRangeLowerStr); - destPortRangeBuilder.setLowerPort(new PortNumber(dpRangeLower)); - } - if (dpRangeUpperStr != null) { - int dpRangeUpper = Integer.parseInt(dpRangeUpperStr); - destPortRangeBuilder.setUpperPort(new PortNumber(dpRangeUpper)); - } - destPortRange = destPortRangeBuilder.build(); - return destPortRange; - } - - /** - * @param properties - * @return accessListEntries - */ - private List<AccessListEntries> getAccessListEntries(Dictionary<?, ?> properties, - Matches matches) { - /** - * Build and Populate Access List Entries. - */ - AccessListEntriesBuilder acLListEntriesBuilder = new AccessListEntriesBuilder(); - String aclListEntriesRuleName = get(properties, - ACL_LIST_ENTRIES_RULE_NAME_KEY); - if (aclListEntriesRuleName != null) { - acLListEntriesBuilder.setRuleName(aclListEntriesRuleName); - } - acLListEntriesBuilder.setMatches(matches); - String aclActions = get(properties, ACL_LIST_ACTIONS_KEY); - if (aclActions != null) { - ActionsBuilder actionBuilder = new ActionsBuilder(); - if (aclActions.equalsIgnoreCase("deny")) { - DenyBuilder denyBuilder = new DenyBuilder(); - actionBuilder.setPacketHandling(denyBuilder.build()); - } else if (aclActions.equalsIgnoreCase("permit")) { - PermitBuilder permitBuilder = new PermitBuilder(); - actionBuilder.setPacketHandling(permitBuilder.build()); - } - acLListEntriesBuilder.setActions(actionBuilder.build()); - } - AccessListEntries aclListEntries = acLListEntriesBuilder.build(); - List<AccessListEntries> accessListEntries = new ArrayList<AccessListEntries>(); - accessListEntries.add(aclListEntries); - return accessListEntries; - } - - /** - * @param properties - * @return aceIp - */ - private AceIp getAceIp(Dictionary<?, ?> properties, - SourcePortRange srcPortRange, - DestinationPortRange destPortRange) { - /** - * Building Ace IPV4 Type - */ - String destIpv4 = get(properties, ACL_LIST_DEST_IPV4_KEY); - String srcIpv4 = get(properties, ACL_LIST_SRC_IPV4_KEY); - AceIpv4Builder aceIpv4Builder = new AceIpv4Builder(); - aceIp = null; - if (destIpv4 != null) { - Ipv4Prefix destinationIp = new Ipv4Prefix(destIpv4); - aceIpv4Builder.setDestinationIpv4Address(destinationIp); - } - if (srcIpv4 != null) { - Ipv4Prefix sourceIp = new Ipv4Prefix(srcIpv4); - aceIpv4Builder.setSourceIpv4Address(sourceIp); - } - if (destIpv4 != null || srcIpv4 != null) { - AceIpv4 aceIpv4 = aceIpv4Builder.build(); - AceIpBuilder aceIpBuilder = new AceIpBuilder(); - aceIpBuilder.setAceIpVersion(aceIpv4); - aceIpBuilder.setSourcePortRange(srcPortRange); - aceIpBuilder.setDestinationPortRange(destPortRange); - aceIp = aceIpBuilder.build(); - } - return aceIp; - } - - /** - * @param deviceEntry - * @return deviceMap - */ - private Map<String, String> processDeviceEntry(String deviceEntry) { - if (deviceEntry == null) { - log.info("No content for Device Entry, so cannot proceed further."); - return null; - } - - Map<String, String> deviceMap = new HashMap<String, String>(); - log.info("Trying to convert Device Entry String: " + deviceEntry - + " to a Netconf Device Object"); - try { - URI uri = new URI(deviceEntry); - String path = uri.getPath(); - String userInfo = path.substring(path.lastIndexOf('@')); - String hostInfo = path.substring(path.lastIndexOf('@') + 1); - String[] infoSplit = userInfo.split(":"); - String username = infoSplit[0]; - String password = infoSplit[1]; - infoSplit = hostInfo.split(":"); - String hostIp = infoSplit[0]; - String hostPort = infoSplit[1]; - if (isNullOrEmpty(username) || isNullOrEmpty(password) - || isNullOrEmpty(hostIp) || isNullOrEmpty(hostPort)) { - log.warn("Bad Configuration Data: both user and device" - + " information parts of Configuration " + deviceEntry - + " should be non-nullable"); - } else { - deviceMap.put("hostIp", hostIp); - deviceMap.put("hostPort", hostPort); - deviceMap.put("username", username); - deviceMap.put("password", password); - } - } catch (ArrayIndexOutOfBoundsException aie) { - log.error("Error while reading config infromation from the config file: " - + "The user, host and device state infomation should be " - + "in the order 'userInfo@hostInfo:deviceState'" - + deviceEntry, aie); - } catch (URISyntaxException urie) { - log.error("Error while parsing config information for the device entry: " - + "Illegal character in path " + deviceEntry, - urie); - } catch (Exception e) { - log.error("Error while parsing config information for the device entry: " - + deviceEntry, e); - } - return deviceMap; - } - - @Override - public void applyFlowRule(FlowRule... flowRules) { - } - - @Override - public void removeFlowRule(FlowRule... flowRules) { - } - - private void applyRule() { - // applyFlowRule(flowRules);//currentl - } - - @Override - public void removeRulesById(ApplicationId id, FlowRule... flowRules) { - log.info("removal by app id not supported in null provider"); - } - - @Override - public void executeBatch(FlowRuleBatchOperation batch) { - - } - - private class StatisticTask implements TimerTask { - - @Override - public void run(Timeout to) throws Exception { - for (DeviceId devId : flowTable.keySet()) { - providerService.pushFlowMetrics(devId, flowTable - .getOrDefault(devId, Collections.emptySet())); - } - timeout = timer.newTimeout(to.getTask(), 5, TimeUnit.SECONDS); - - } - } -} diff --git a/framework/src/onos/providers/netconf/flow/src/main/java/org/onosproject/provider/netconf/flow/impl/NetconfOperation.java b/framework/src/onos/providers/netconf/flow/src/main/java/org/onosproject/provider/netconf/flow/impl/NetconfOperation.java deleted file mode 100644 index 4e5a2752..00000000 --- a/framework/src/onos/providers/netconf/flow/src/main/java/org/onosproject/provider/netconf/flow/impl/NetconfOperation.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * 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.provider.netconf.flow.impl; - -import static org.onlab.util.Tools.delay; -import static org.slf4j.LoggerFactory.getLogger; - -import java.io.IOException; - -import org.slf4j.Logger; - -import com.tailf.jnc.Capabilities; -import com.tailf.jnc.JNCException; -import com.tailf.jnc.SSHConnection; -import com.tailf.jnc.SSHSession; - -/** - * This is to carry necessary information to connect and execute NETCONF - * operations. - */ -public class NetconfOperation { - private final Logger log = getLogger(NetconfOperation.class); - private static final int EVENTINTERVAL = 2000; - private static final int CONNECTION_CHECK_INTERVAL = 3; - private static final String INPUT_HELLO_XML_MSG = new StringBuilder( - "<?xml version=\"1.0\" encoding=\"UTF-8\"?>") - .append("<hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">") - .append("<capabilities><capability>urn:ietf:params:netconf:base:1.0</capability>") - .append("</capabilities></hello>").toString(); - - /** - * This will send a Xml message to the device. - * @param xmlMsg XML to send - * @param username user name - * @param password pass word - * @param deviceIp ip address of the device - * @param devicePort port on the device - */ - protected void sendXmlMessage(String xmlMsg, String username, - String password, String deviceIp, - Integer devicePort) { - SSHSession ssh = null; - try { - SSHConnection sshConnection = getConnection(username, password, - deviceIp, devicePort); - ssh = new SSHSession(sshConnection); - executeMessage(ssh, INPUT_HELLO_XML_MSG); - /* - * execute acl message - */ - executeMessage(ssh, xmlMsg); - - } catch (IOException e) { - log.error("Unable to send Hello Message to the device: ", e); - } catch (JNCException e) { - log.error("Authentication fail while sending Hello Message to the device: ", - e); - } catch (Exception e) { - log.error("Unable to send Hello Message to the device: ", e); - } finally { - log.debug("Closing the session after successful execution"); - if (ssh != null) { - ssh.close(); - } - } - } - - private void executeMessage(SSHSession ssh, String xmlMsg) - throws IOException, JNCException { - String helloRequestXML = xmlMsg.trim(); - - log.debug("Sending Hello"); - ssh.print(helloRequestXML); - ssh.flush(); - String xmlResponse = null; - int i = CONNECTION_CHECK_INTERVAL; - while (!ssh.ready() && i > 0) { - delay(EVENTINTERVAL); - i--; - } - - if (ssh.ready()) { - StringBuffer readOne = ssh.readOne(); - if (readOne == null) { - log.error("The Hello Contains No Capabilites"); - throw new JNCException( - JNCException.SESSION_ERROR, - "server does not support NETCONF base capability: " - + Capabilities.NETCONF_BASE_CAPABILITY); - } else { - xmlResponse = readOne.toString().trim(); - - log.debug("Reading Capabilities: " - + ssh.getSSHConnection().getGanymedConnection() - .getHostname()); - } - } - } - - /** - * To establish SSH Connection. - * - * @param username user name - * @param password pass word - * @param sshHost host - * @param sshPort port - * @return new SSH connection - * @throws IOException if connection fails - * @throws JNCException if connection causes an error - */ - public SSHConnection getConnection(String username, String password, - String sshHost, Integer sshPort) - throws IOException, JNCException { - SSHConnection sshConnection; - try { - sshConnection = new SSHConnection(sshHost, sshPort); - sshConnection.authenticateWithPassword(username, password); - } catch (IOException e) { - log.error("Unable to create a connection to the device: "); - throw e; - } catch (JNCException e) { - log.error("Failed to connect to the device: "); - throw e; - } - return sshConnection; - } - -} diff --git a/framework/src/onos/providers/netconf/flow/src/main/java/org/onosproject/provider/netconf/flow/impl/XmlBuilder.java b/framework/src/onos/providers/netconf/flow/src/main/java/org/onosproject/provider/netconf/flow/impl/XmlBuilder.java deleted file mode 100644 index 389f1669..00000000 --- a/framework/src/onos/providers/netconf/flow/src/main/java/org/onosproject/provider/netconf/flow/impl/XmlBuilder.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * 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.provider.netconf.flow.impl; - -import static org.slf4j.LoggerFactory.getLogger; - -import org.jdom2.Document; -import org.jdom2.Element; -import org.jdom2.Namespace; -import org.jdom2.output.Format; -import org.jdom2.output.XMLOutputter; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.AccessList; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.access.list.access.list.entries.matches.AceType; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.access.list.access.list.entries.matches.ace.type.AceEth; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.access.list.access.list.entries.matches.ace.type.AceIp; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.access.list.access.list.entries.matches.ace.type.ace.ip.AceIpVersion; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.access.list.access.list.entries.matches.ace.type.ace.ip.ace.ip.version.AceIpv4; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.access.list.access.list.entries.matches.ace.type.ace.ip.ace.ip.version.AceIpv6; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.packet.fields.rev140625.acl.transport.header.fields.DestinationPortRange; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.packet.fields.rev140625.acl.transport.header.fields.SourcePortRange; -import org.slf4j.Logger; - -/** - * Xml Builder to generate the xml according to given ACL model. - */ -public class XmlBuilder { - private final Logger log = getLogger(XmlBuilder.class); - - public String buildAclRequestXml(AccessList accessList) { - Document doc = new Document(); - Namespace namespaceRpc = Namespace - .getNamespace("urn:ietf:params:xml:ns:netconf:base:1.0"); - Namespace accessNamespaceRpc = Namespace - .getNamespace("urn:ietf:params:xml:ns:yang:ietf-acl"); - doc.setRootElement(new Element("rpc", namespaceRpc) - .setAttribute("message-id", "101")); - - /** - * Access list elements of given ACL model. - */ - Element access = new Element("access-list", accessNamespaceRpc); - access.addContent(new Element("acl-name", accessNamespaceRpc) - .setText(accessList.getAclName())); - // access.addContent(accessEntries); - - if (!accessList.getAccessListEntries().isEmpty() - && accessList.getAccessListEntries() != null) { - for (int accessEntryIntVlu = 0; accessEntryIntVlu < accessList - .getAccessListEntries().size(); accessEntryIntVlu++) { - access.addContent(getAccessEntries(accessEntryIntVlu, - accessList, - accessNamespaceRpc)); - } - } - - /** - * edit-config operation for given ACL model. - */ - Element editConfig = new Element("edit-config", namespaceRpc); - editConfig.addContent(new Element("target", namespaceRpc) - .addContent(new Element("running", namespaceRpc))); - editConfig.addContent(new Element("config", Namespace - .getNamespace("urn:ietf:params:xml:ns:netconf:base:1.0")) - .addContent(access)); - - doc.getRootElement().addContent(editConfig); - XMLOutputter xmlOutputter = new XMLOutputter(Format.getPrettyFormat()); - String outputString = xmlOutputter.outputString(doc); - - return outputString; - } - - /** - * access entries operation for given ACL model. - */ - private Element getAccessEntries(int accessEntryIntVlu, - AccessList accessList, - Namespace accessNamespaceRpc) { - - /** - * Port Number - */ - - int srcPortRangeLower = 0; - int srcPortRangeUpper = 0; - int destPortRangeLower = 0; - int destPortRangeUpper = 0; - - String sourceIpAdd = ""; - String destinationIpAdd = ""; - - /* - * checking accessList is null or not - */ - if (accessList != null) { - /* - * checking list entries are empty or null - */ - if (!accessList.getAccessListEntries().isEmpty() - && accessList.getAccessListEntries() != null) { - AceType aceType = accessList.getAccessListEntries() - .get(accessEntryIntVlu).getMatches().getAceType(); - - if (aceType instanceof AceIp) { - AceIp aceIp = (AceIp) aceType; - SourcePortRange sourcePortRange = aceIp - .getSourcePortRange(); - if (sourcePortRange != null) { - PortNumber lowerPort = sourcePortRange.getLowerPort(); - PortNumber upperPort = sourcePortRange.getUpperPort(); - - if (lowerPort != null) { - srcPortRangeLower = lowerPort.getValue(); - } - if (upperPort != null) { - srcPortRangeUpper = upperPort.getValue(); - } - } - DestinationPortRange destinationPortRange = aceIp - .getDestinationPortRange(); - - if (destinationPortRange != null) { - PortNumber lowerPort = destinationPortRange - .getLowerPort(); - if (lowerPort != null) { - destPortRangeLower = lowerPort.getValue(); - } - - PortNumber upperPort = destinationPortRange - .getUpperPort(); - if (upperPort != null) { - destPortRangeUpper = upperPort.getValue(); - } - - } - - AceIpVersion aceIpVersion = aceIp.getAceIpVersion(); - if (aceIpVersion instanceof AceIpv4) { - AceIpv4 obj = (AceIpv4) aceIpVersion; - destinationIpAdd = obj.getDestinationIpv4Address() - .getValue(); - sourceIpAdd = obj.getSourceIpv4Address().getValue(); - } else if (aceIpVersion instanceof AceIpv6) { - AceIpv6 obj = (AceIpv6) aceIpVersion; - destinationIpAdd = obj.getDestinationIpv6Address() - .getValue(); - sourceIpAdd = obj.getSourceIpv6Address().getValue(); - } - } else if (aceType instanceof AceEth) { - log.debug("Need to add execution loging for Ace Type Ethernet"); - } - } - } - - /** - * Matches elements to define IP address & Port range for given ACL - * model. - */ - Element matchesElement = new Element("matches", accessNamespaceRpc); - if (String.valueOf(srcPortRangeLower) != null - && !String.valueOf(srcPortRangeLower).isEmpty()) { - - matchesElement.addContent(new Element("source-port-range", - accessNamespaceRpc) - .addContent(new Element("lower-port", accessNamespaceRpc) - .setText(String.valueOf(srcPortRangeLower)))); - - matchesElement.addContent(new Element("source-port-range", - accessNamespaceRpc) - .addContent(new Element("upper-port", accessNamespaceRpc) - .setText(String.valueOf(srcPortRangeUpper)))); - - matchesElement.addContent(new Element("destination-port-range", - accessNamespaceRpc) - .addContent(new Element("lower-port", accessNamespaceRpc) - .setText(String.valueOf(destPortRangeLower)))); - - matchesElement.addContent(new Element("destination-port-range", - accessNamespaceRpc) - .addContent(new Element("upper-port", accessNamespaceRpc) - .setText(String.valueOf(destPortRangeUpper)))); - } - - if (destinationIpAdd != null && !destinationIpAdd.isEmpty()) { - matchesElement.addContent(new Element("destination-ipv4-address", - accessNamespaceRpc) - .setText(destinationIpAdd)); - } - if (sourceIpAdd != null && !sourceIpAdd.isEmpty()) { - matchesElement.addContent(new Element("source-ipv4-address", - accessNamespaceRpc) - .setText(sourceIpAdd)); - } - - /** - * Access entries elements for given ACL model. - */ - Element accessEntries = new Element("access-list-entries", - accessNamespaceRpc); - accessEntries.addContent(new Element("rule-name", accessNamespaceRpc) - .setText(accessList.getAccessListEntries() - .get(accessEntryIntVlu).getRuleName())); - accessEntries.addContent(matchesElement); - accessEntries.addContent(new Element("actions", accessNamespaceRpc) - .addContent(new Element("deny", accessNamespaceRpc))); - - return accessEntries; - } -} diff --git a/framework/src/onos/providers/netconf/pom.xml b/framework/src/onos/providers/netconf/pom.xml index f73940fe..8c4681df 100644 --- a/framework/src/onos/providers/netconf/pom.xml +++ b/framework/src/onos/providers/netconf/pom.xml @@ -34,7 +34,6 @@ <modules> <module>device</module> <module>app</module> - <module>flow</module> </modules> <dependencies> diff --git a/framework/src/onos/providers/null/src/main/java/org/onosproject/provider/nil/NullProviders.java b/framework/src/onos/providers/null/src/main/java/org/onosproject/provider/nil/NullProviders.java index c5688419..68c536b9 100644 --- a/framework/src/onos/providers/null/src/main/java/org/onosproject/provider/nil/NullProviders.java +++ b/framework/src/onos/providers/null/src/main/java/org/onosproject/provider/nil/NullProviders.java @@ -168,7 +168,7 @@ public class NullProviders { @Activate - public void activate(ComponentContext context) { + public void activate() { cfgService.registerProperties(getClass()); deviceProviderService = deviceProviderRegistry.register(deviceProvider); @@ -180,7 +180,7 @@ public class NullProviders { } @Deactivate - public void deactivate(ComponentContext context) { + public void deactivate() { cfgService.unregisterProperties(getClass(), false); tearDown(); 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 a7e334f4..4ceb425c 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 @@ -516,7 +516,7 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr PortNumber portNo = PortNumber.portNumber(port.getPortNo().getPortNumber()); boolean enabled = !port.getState().contains(OFPortState.LINK_DOWN) && !port.getConfig().contains(OFPortConfig.PORT_DOWN); - SparseAnnotations annotations = makePortNameAnnotation(port.getName()); + SparseAnnotations annotations = makePortAnnotation(port.getName(), port.getHwAddr().toString()); OFExpPortDescPropOpticalTransport firstProp = port.getProperties().get(0); OFPortOpticalTransportSignalType sigType = firstProp.getPortSignalType(); @@ -560,16 +560,19 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr /** * Creates an annotation for the port name if one is available. * - * @param port description of the port + * @param portName the port name + * @param portMac the port mac * @return annotation containing the port name if one is found, * null otherwise */ - private SparseAnnotations makePortNameAnnotation(String port) { + private SparseAnnotations makePortAnnotation(String portName, String portMac) { SparseAnnotations annotations = null; - String portName = Strings.emptyToNull(port); + String pName = Strings.emptyToNull(portName); + String pMac = Strings.emptyToNull(portMac); if (portName != null) { annotations = DefaultAnnotations.builder() - .set(AnnotationKeys.PORT_NAME, portName).build(); + .set(AnnotationKeys.PORT_NAME, pName) + .set(AnnotationKeys.PORT_MAC, pMac).build(); } return annotations; } @@ -586,7 +589,7 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr !port.getState().contains(OFPortState.LINK_DOWN) && !port.getConfig().contains(OFPortConfig.PORT_DOWN); Port.Type type = port.getCurr().contains(OFPortFeatures.PF_FIBER) ? FIBER : COPPER; - SparseAnnotations annotations = makePortNameAnnotation(port.getName()); + SparseAnnotations annotations = makePortAnnotation(port.getName(), port.getHwAddr().toString()); return new DefaultPortDescription(portNo, enabled, type, portSpeed(port), annotations); } @@ -607,7 +610,7 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr boolean enabled = !port.getState().contains(OFPortState.LINK_DOWN) && !port.getConfig().contains(OFPortConfig.PORT_DOWN); - SparseAnnotations annotations = makePortNameAnnotation(port.getName()); + SparseAnnotations annotations = makePortAnnotation(port.getName(), port.getHwAddr().toString()); if (port.getVersion() == OFVersion.OF_13 && ptype == PortDescPropertyType.OPTICAL_TRANSPORT) { @@ -649,7 +652,7 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr // FIXME when Calient OF agent reports port status boolean enabled = true; - SparseAnnotations annotations = makePortNameAnnotation(port.getName()); + SparseAnnotations annotations = makePortAnnotation(port.getName(), port.getHwAddr().toString()); // S160 data sheet // Wavelength range: 1260 - 1630 nm, grid is irrelevant for this type of switch @@ -664,7 +667,7 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr } else { PortNumber portNo = PortNumber.portNumber(port.getPortNo().getPortNumber()); Port.Type type = port.getCurr().contains(OFPortFeatures.PF_FIBER) ? FIBER : COPPER; - SparseAnnotations annotations = makePortNameAnnotation(port.getName()); + SparseAnnotations annotations = makePortAnnotation(port.getName(), port.getHwAddr().toString()); return new DefaultPortDescription(portNo, false, type, portSpeed(port), annotations); } 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 d4494f18..b12d8a60 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 @@ -27,6 +27,7 @@ import org.onlab.packet.VlanId; import org.onosproject.core.DefaultGroupId; import org.onosproject.net.DeviceId; import org.onosproject.net.Lambda; +import org.onosproject.net.OduSignalId; import org.onosproject.net.PortNumber; import org.onosproject.net.driver.DefaultDriverData; import org.onosproject.net.driver.DefaultDriverHandler; @@ -83,15 +84,21 @@ import org.projectfloodlight.openflow.types.U32; import org.projectfloodlight.openflow.types.U64; import org.projectfloodlight.openflow.types.U8; import org.projectfloodlight.openflow.types.VlanPcp; +import org.projectfloodlight.openflow.types.OduSignalID; import org.slf4j.Logger; import java.util.List; import static org.onosproject.net.flow.criteria.Criteria.matchLambda; import static org.onosproject.net.flow.criteria.Criteria.matchOchSignalType; +import static org.onosproject.net.flow.criteria.Criteria.matchOduSignalType; +import static org.onosproject.net.flow.criteria.Criteria.matchOduSignalId; +import static org.onosproject.net.flow.instructions.Instructions.modL0Lambda; +import static org.onosproject.net.flow.instructions.Instructions.modL1OduSignalId; import static org.onosproject.provider.of.flow.impl.OpenFlowValueMapper.lookupChannelSpacing; import static org.onosproject.provider.of.flow.impl.OpenFlowValueMapper.lookupGridType; import static org.onosproject.provider.of.flow.impl.OpenFlowValueMapper.lookupOchSignalType; +import static org.onosproject.provider.of.flow.impl.OpenFlowValueMapper.lookupOduSignalType; import static org.slf4j.LoggerFactory.getLogger; public class FlowEntryBuilder { @@ -454,6 +461,29 @@ public class FlowEntryBuilder { builder.extension(interpreter.mapAction(action), DeviceId.deviceId(Dpid.uri(dpid))); } break; + case EXP_ODU_SIG_ID: + @SuppressWarnings("unchecked") + OFOxm<OduSignalID> oduID = (OFOxm<OduSignalID>) oxm; + OduSignalID oduSignalID = oduID.getValue(); + OduSignalId oduSignalId = OduSignalId.oduSignalId(oduSignalID.getTpn(), + oduSignalID.getTslen(), + oduSignalID.getTsmap()); + builder.add(modL1OduSignalId(oduSignalId)); + break; + case EXP_OCH_SIG_ID: + try { + @SuppressWarnings("unchecked") + OFOxm<CircuitSignalID> ochId = (OFOxm<CircuitSignalID>) oxm; + CircuitSignalID circuitSignalID = ochId.getValue(); + builder.add(modL0Lambda(Lambda.ochSignal( + lookupGridType(circuitSignalID.getGridType()), + lookupChannelSpacing(circuitSignalID.getChannelSpacing()), + circuitSignalID.getChannelNumber(), circuitSignalID.getSpectralWidth()))); + } catch (NoMappingFoundException e) { + log.warn(e.getMessage()); + break; + } + break; case ARP_OP: case ARP_SHA: case ARP_SPA: @@ -501,6 +531,8 @@ public class FlowEntryBuilder { case OCH_SIGTYPE_BASIC: case SCTP_DST: case SCTP_SRC: + case EXP_ODU_SIGTYPE: + case EXP_OCH_SIGTYPE: default: log.warn("Set field type {} not yet implemented.", oxm.getMatchField().id); break; @@ -704,6 +736,41 @@ public class FlowEntryBuilder { U8 sigType = match.get(MatchField.OCH_SIGTYPE); builder.add(matchOchSignalType(lookupOchSignalType((byte) sigType.getValue()))); break; + case EXP_OCH_SIG_ID: + try { + CircuitSignalID expSigId = match.get(MatchField.EXP_OCH_SIG_ID); + builder.add(matchLambda(Lambda.ochSignal( + lookupGridType(expSigId.getGridType()), lookupChannelSpacing(expSigId.getChannelSpacing()), + expSigId.getChannelNumber(), expSigId.getSpectralWidth()))); + } catch (NoMappingFoundException e) { + log.warn(e.getMessage()); + break; + } + break; + case EXP_OCH_SIGTYPE: + try { + U8 expOchSigType = match.get(MatchField.EXP_OCH_SIGTYPE); + builder.add(matchOchSignalType(lookupOchSignalType((byte) expOchSigType.getValue()))); + } catch (NoMappingFoundException e) { + log.warn(e.getMessage()); + break; + } + break; + case EXP_ODU_SIG_ID: + OduSignalId oduSignalId = OduSignalId.oduSignalId(match.get(MatchField.EXP_ODU_SIG_ID).getTpn(), + match.get(MatchField.EXP_ODU_SIG_ID).getTslen(), + match.get(MatchField.EXP_ODU_SIG_ID).getTsmap()); + builder.add(matchOduSignalId(oduSignalId)); + break; + case EXP_ODU_SIGTYPE: + try { + U8 oduSigType = match.get(MatchField.EXP_ODU_SIGTYPE); + builder.add(matchOduSignalType(lookupOduSignalType((byte) oduSigType.getValue()))); + } catch (NoMappingFoundException e) { + log.warn(e.getMessage()); + break; + } + break; case TUNNEL_ID: long tunnelId = match.get(MatchField.TUNNEL_ID).getValue(); builder.matchTunnelId(tunnelId); diff --git a/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilder.java b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilder.java index 2a8d2010..dcd7b0fc 100644 --- a/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilder.java +++ b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilder.java @@ -20,8 +20,13 @@ import org.onlab.packet.Ip4Prefix; import org.onlab.packet.Ip6Address; import org.onlab.packet.Ip6Prefix; import org.onlab.packet.VlanId; +import org.onosproject.net.DeviceId; import org.onosproject.net.OchSignal; +import org.onosproject.net.driver.DefaultDriverData; +import org.onosproject.net.driver.DefaultDriverHandler; +import org.onosproject.net.driver.Driver; import org.onosproject.net.driver.DriverService; +import org.onosproject.net.OduSignalId; import org.onosproject.net.flow.FlowRule; import org.onosproject.net.flow.TrafficSelector; import org.onosproject.net.flow.criteria.ArpHaCriterion; @@ -30,6 +35,8 @@ import org.onosproject.net.flow.criteria.ArpPaCriterion; import org.onosproject.net.flow.criteria.Criterion; import org.onosproject.net.flow.criteria.EthCriterion; import org.onosproject.net.flow.criteria.EthTypeCriterion; +import org.onosproject.net.flow.criteria.ExtensionCriterion; +import org.onosproject.net.flow.criteria.ExtensionSelector; import org.onosproject.net.flow.criteria.IPCriterion; import org.onosproject.net.flow.criteria.IPDscpCriterion; import org.onosproject.net.flow.criteria.IPEcnCriterion; @@ -47,6 +54,8 @@ import org.onosproject.net.flow.criteria.MplsBosCriterion; import org.onosproject.net.flow.criteria.MplsCriterion; import org.onosproject.net.flow.criteria.OchSignalCriterion; import org.onosproject.net.flow.criteria.OchSignalTypeCriterion; +import org.onosproject.net.flow.criteria.OduSignalIdCriterion; +import org.onosproject.net.flow.criteria.OduSignalTypeCriterion; import org.onosproject.net.flow.criteria.PortCriterion; import org.onosproject.net.flow.criteria.SctpPortCriterion; import org.onosproject.net.flow.criteria.TcpPortCriterion; @@ -54,12 +63,14 @@ import org.onosproject.net.flow.criteria.TunnelIdCriterion; import org.onosproject.net.flow.criteria.UdpPortCriterion; import org.onosproject.net.flow.criteria.VlanIdCriterion; import org.onosproject.net.flow.criteria.VlanPcpCriterion; +import org.onosproject.openflow.controller.ExtensionSelectorInterpreter; import org.projectfloodlight.openflow.protocol.OFFactory; import org.projectfloodlight.openflow.protocol.OFFlowAdd; import org.projectfloodlight.openflow.protocol.OFFlowDelete; import org.projectfloodlight.openflow.protocol.OFFlowMod; import org.projectfloodlight.openflow.protocol.match.Match; import org.projectfloodlight.openflow.protocol.match.MatchField; +import org.projectfloodlight.openflow.protocol.oxm.OFOxm; import org.projectfloodlight.openflow.types.ArpOpcode; import org.projectfloodlight.openflow.types.CircuitSignalID; import org.projectfloodlight.openflow.types.EthType; @@ -84,6 +95,7 @@ import org.projectfloodlight.openflow.types.U64; import org.projectfloodlight.openflow.types.U8; import org.projectfloodlight.openflow.types.VlanPcp; import org.projectfloodlight.openflow.types.VlanVid; +import org.projectfloodlight.openflow.types.OduSignalID; import org.slf4j.Logger; import java.util.Optional; @@ -102,6 +114,7 @@ public abstract class FlowModBuilder { private final TrafficSelector selector; protected final Long xid; protected final Optional<DriverService> driverService; + protected final DeviceId deviceId; /** * Creates a new flow mod builder. @@ -142,6 +155,7 @@ public abstract class FlowModBuilder { this.selector = flowRule.selector(); this.xid = xid.orElse(0L); this.driverService = driverService; + this.deviceId = flowRule.deviceId(); } /** @@ -398,7 +412,7 @@ public abstract class FlowModBuilder { OchSignal signal = ochSignalCriterion.lambda(); byte gridType = OpenFlowValueMapper.lookupGridType(signal.gridType()); byte channelSpacing = OpenFlowValueMapper.lookupChannelSpacing(signal.channelSpacing()); - mBuilder.setExact(MatchField.OCH_SIGID, + mBuilder.setExact(MatchField.EXP_OCH_SIG_ID, new CircuitSignalID(gridType, channelSpacing, (short) signal.spacingMultiplier(), (short) signal.slotGranularity())); } catch (NoMappingFoundException e) { @@ -406,9 +420,30 @@ public abstract class FlowModBuilder { } break; case OCH_SIGTYPE: - OchSignalTypeCriterion sc = (OchSignalTypeCriterion) c; - byte signalType = OpenFlowValueMapper.lookupOchSignalType(sc.signalType()); - mBuilder.setExact(MatchField.OCH_SIGTYPE, U8.of(signalType)); + try { + OchSignalTypeCriterion sc = (OchSignalTypeCriterion) c; + byte signalType = OpenFlowValueMapper.lookupOchSignalType(sc.signalType()); + mBuilder.setExact(MatchField.EXP_OCH_SIGTYPE, U8.of(signalType)); + } catch (NoMappingFoundException e) { + log.warn(e.getMessage()); + } + break; + case ODU_SIGID: + OduSignalIdCriterion oduSignalIdCriterion = (OduSignalIdCriterion) c; + OduSignalId oduSignalId = oduSignalIdCriterion.oduSignalId(); + mBuilder.setExact(MatchField.EXP_ODU_SIG_ID, + new OduSignalID((short) oduSignalId.tributaryPortNumber(), + (short) oduSignalId.tributarySlotLength(), + oduSignalId.tributarySlotBitmap())); + break; + case ODU_SIGTYPE: + try { + OduSignalTypeCriterion oduSignalTypeCriterion = (OduSignalTypeCriterion) c; + byte oduSigType = OpenFlowValueMapper.lookupOduSignalType(oduSignalTypeCriterion.signalType()); + mBuilder.setExact(MatchField.EXP_ODU_SIGTYPE, U8.of(oduSigType)); + } catch (NoMappingFoundException e) { + log.warn(e.getMessage()); + } break; case TUNNEL_ID: TunnelIdCriterion tunnelId = (TunnelIdCriterion) c; @@ -446,8 +481,24 @@ public abstract class FlowModBuilder { mBuilder.setExact(MatchField.ARP_TPA, IPv4Address.of(arpPaCriterion.ip().toInt())); break; + case EXTENSION: + ExtensionCriterion extensionCriterion = (ExtensionCriterion) c; + OFOxm oxm = buildExtensionOxm(extensionCriterion.extensionSelector()); + if (oxm == null) { + log.warn("Unable to build extension selector"); + break; + } + + if (oxm.isMasked()) { + mBuilder.setMasked(oxm.getMatchField(), oxm.getValue(), oxm.getMask()); + } else { + mBuilder.setExact(oxm.getMatchField(), oxm.getValue()); + } + + break; case MPLS_TC: case PBB_ISID: + // TODO: need to implement PBB-ISID case when OpenFlowJ is ready default: log.warn("Match type {} not yet implemented.", c.type()); } @@ -473,4 +524,21 @@ public abstract class FlowModBuilder { return factory; } + private OFOxm buildExtensionOxm(ExtensionSelector extension) { + if (!driverService.isPresent()) { + log.error("No driver service present"); + return null; + } + Driver driver = driverService.get().getDriver(deviceId); + if (driver.hasBehaviour(ExtensionSelectorInterpreter.class)) { + DefaultDriverHandler handler = + new DefaultDriverHandler(new DefaultDriverData(driver, deviceId)); + ExtensionSelectorInterpreter interpreter = handler.behaviour(ExtensionSelectorInterpreter.class); + + return interpreter.mapSelector(factory(), extension); + } + + return null; + } + } diff --git a/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer10.java b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer10.java index bdea09da..d4ebb4fd 100644 --- a/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer10.java +++ b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer10.java @@ -181,6 +181,7 @@ public class FlowModBuilderVer10 extends FlowModBuilder { acts.add(queueBuilder.build()); break; case L0MODIFICATION: + case L1MODIFICATION: case GROUP: case TABLE: case METADATA: 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 90def432..a3182e72 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 @@ -18,8 +18,8 @@ package org.onosproject.provider.of.flow.impl; import com.google.common.collect.Lists; import org.onlab.packet.Ip4Address; import org.onlab.packet.Ip6Address; -import org.onosproject.net.DeviceId; import org.onosproject.net.OchSignal; +import org.onosproject.net.OduSignalId; import org.onosproject.net.PortNumber; import org.onosproject.net.driver.DefaultDriverData; import org.onosproject.net.driver.DefaultDriverHandler; @@ -36,6 +36,8 @@ 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; +import org.onosproject.net.flow.instructions.L1ModificationInstruction; +import org.onosproject.net.flow.instructions.L1ModificationInstruction.ModOduSignalIdInstruction; import org.onosproject.net.flow.instructions.L2ModificationInstruction; import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction; import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsBosInstruction; @@ -46,6 +48,9 @@ import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanPc import org.onosproject.net.flow.instructions.L2ModificationInstruction.PushHeaderInstructions; import org.onosproject.net.flow.instructions.L3ModificationInstruction; import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPInstruction; +import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModArpIPInstruction; +import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModArpEthInstruction; +import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModArpOpInstruction; import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPv6FlowLabelInstruction; import org.onosproject.net.flow.instructions.L4ModificationInstruction; import org.onosproject.net.flow.instructions.L4ModificationInstruction.ModTransportPortInstruction; @@ -62,6 +67,7 @@ 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; +import org.projectfloodlight.openflow.types.ArpOpcode; import org.projectfloodlight.openflow.types.CircuitSignalID; import org.projectfloodlight.openflow.types.EthType; import org.projectfloodlight.openflow.types.IPv4Address; @@ -73,6 +79,7 @@ import org.projectfloodlight.openflow.types.OFBufferId; import org.projectfloodlight.openflow.types.OFGroup; import org.projectfloodlight.openflow.types.OFPort; import org.projectfloodlight.openflow.types.OFVlanVidMatch; +import org.projectfloodlight.openflow.types.OduSignalID; import org.projectfloodlight.openflow.types.TableId; import org.projectfloodlight.openflow.types.TransportPort; import org.projectfloodlight.openflow.types.U32; @@ -95,7 +102,6 @@ public class FlowModBuilderVer13 extends FlowModBuilder { private static final int OFPCML_NO_BUFFER = 0xffff; private final TrafficTreatment treatment; - private final DeviceId deviceId; /** * Constructor for a flow mod builder for OpenFlow 1.3. @@ -110,7 +116,6 @@ public class FlowModBuilderVer13 extends FlowModBuilder { super(flowRule, factory, xid, driverService); this.treatment = flowRule.treatment(); - this.deviceId = flowRule.deviceId(); } @Override @@ -233,6 +238,9 @@ public class FlowModBuilderVer13 extends FlowModBuilder { case L0MODIFICATION: actions.add(buildL0Modification(i)); break; + case L1MODIFICATION: + actions.add(buildL1Modification(i)); + break; case L2MODIFICATION: actions.add(buildL2Modification(i)); break; @@ -302,20 +310,31 @@ public class FlowModBuilderVer13 extends FlowModBuilder { private OFAction buildL0Modification(Instruction i) { L0ModificationInstruction l0m = (L0ModificationInstruction) i; + OFOxm<?> oxm = null; switch (l0m.subtype()) { case LAMBDA: return buildModLambdaInstruction((ModLambdaInstruction) i); case OCH: try { - return buildModOchSignalInstruction((ModOchSignalInstruction) i); + ModOchSignalInstruction modOchSignalInstruction = (ModOchSignalInstruction) l0m; + OchSignal signal = modOchSignalInstruction.lambda(); + byte gridType = OpenFlowValueMapper.lookupGridType(signal.gridType()); + byte channelSpacing = OpenFlowValueMapper.lookupChannelSpacing(signal.channelSpacing()); + oxm = factory().oxms().expOchSigId( + new CircuitSignalID(gridType, channelSpacing, + (short) signal.spacingMultiplier(), (short) signal.slotGranularity())); } catch (NoMappingFoundException e) { log.warn(e.getMessage()); break; } + break; default: log.warn("Unimplemented action type {}.", l0m.subtype()); break; } + if (oxm != null) { + return factory().actions().buildSetField().setField(oxm).build(); + } return null; } @@ -335,6 +354,31 @@ public class FlowModBuilderVer13 extends FlowModBuilder { )); } + private OFAction buildL1Modification(Instruction i) { + L1ModificationInstruction l1m = (L1ModificationInstruction) i; + OFOxm<?> oxm = null; + switch (l1m.subtype()) { + case ODU_SIGID: + ModOduSignalIdInstruction modOduSignalIdInstruction = (ModOduSignalIdInstruction) l1m; + OduSignalId oduSignalId = modOduSignalIdInstruction.oduSignalId(); + + OduSignalID oduSignalID = new OduSignalID((short) oduSignalId.tributaryPortNumber(), + (short) oduSignalId.tributarySlotLength(), + oduSignalId.tributarySlotBitmap()); + + oxm = factory().oxms().expOduSigId(oduSignalID); + break; + default: + log.warn("Unimplemented action type {}.", l1m.subtype()); + break; + } + + if (oxm != null) { + return factory().actions().buildSetField().setField(oxm).build(); + } + return null; + } + private OFAction buildL2Modification(Instruction i) { L2ModificationInstruction l2m = (L2ModificationInstruction) i; ModEtherInstruction eth; @@ -433,6 +477,19 @@ public class FlowModBuilderVer13 extends FlowModBuilder { int flowLabel = flowLabelInstruction.flowLabel(); oxm = factory().oxms().ipv6Flabel(IPv6FlowLabel.of(flowLabel)); break; + case ARP_SPA: + ModArpIPInstruction aip = (ModArpIPInstruction) i; + ip4 = aip.ip().getIp4Address(); + oxm = factory().oxms().arpSpa(IPv4Address.of(ip4.toInt())); + break; + case ARP_SHA: + ModArpEthInstruction ei = (ModArpEthInstruction) i; + oxm = factory().oxms().arpSha(MacAddress.of(ei.mac().toLong())); + break; + case ARP_OP: + ModArpOpInstruction oi = (ModArpOpInstruction) i; + oxm = factory().oxms().arpOp(ArpOpcode.of((int) oi.op())); + break; case DEC_TTL: return factory().actions().decNwTtl(); case TTL_IN: diff --git a/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/NewAdaptiveFlowStatsCollector.java b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/NewAdaptiveFlowStatsCollector.java index d5186fa9..aa8df947 100644 --- a/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/NewAdaptiveFlowStatsCollector.java +++ b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/NewAdaptiveFlowStatsCollector.java @@ -1,882 +1,882 @@ -/*
- * 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.provider.of.flow.impl;
-
-import com.google.common.base.Objects;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-import org.onosproject.net.flow.DefaultTypedFlowEntry;
-import org.onosproject.net.flow.FlowEntry;
-import org.onosproject.net.flow.FlowId;
-import org.onosproject.net.flow.FlowRule;
-import org.onosproject.net.flow.StoredFlowEntry;
-import org.onosproject.net.flow.TypedStoredFlowEntry;
-import org.onosproject.net.flow.instructions.Instruction;
-import org.onosproject.net.flow.instructions.Instructions;
-import org.onosproject.openflow.controller.OpenFlowSwitch;
-import org.onosproject.openflow.controller.RoleState;
-import org.projectfloodlight.openflow.protocol.OFFlowStatsRequest;
-import org.projectfloodlight.openflow.protocol.match.Match;
-import org.projectfloodlight.openflow.types.OFPort;
-import org.projectfloodlight.openflow.types.TableId;
-import org.slf4j.Logger;
-
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.TimeUnit;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static org.onlab.util.Tools.groupedThreads;
-import static org.onosproject.net.flow.TypedStoredFlowEntry.FlowLiveType;
-import static org.slf4j.LoggerFactory.getLogger;
-
-/**
- * Efficiently and adaptively collects flow statistics for the specified switch.
- */
-public class NewAdaptiveFlowStatsCollector {
-
- private final Logger log = getLogger(getClass());
-
- private final OpenFlowSwitch sw;
-
- private ScheduledExecutorService adaptiveFlowStatsScheduler =
- Executors.newScheduledThreadPool(4, groupedThreads("onos/flow", "device-stats-collector-%d"));
- private ScheduledFuture<?> calAndShortFlowsThread;
- private ScheduledFuture<?> midFlowsThread;
- private ScheduledFuture<?> longFlowsThread;
-
- // Task that calculates all flowEntries' FlowLiveType and collects stats IMMEDIATE flows every calAndPollInterval
- private CalAndShortFlowsTask calAndShortFlowsTask;
- // Task that collects stats MID flows every 2*calAndPollInterval
- private MidFlowsTask midFlowsTask;
- // Task that collects stats LONG flows every 3*calAndPollInterval
- private LongFlowsTask longFlowsTask;
-
- private static final int CAL_AND_POLL_TIMES = 1; // must be always 0
- private static final int MID_POLL_TIMES = 2; // variable greater or equal than 1
- private static final int LONG_POLL_TIMES = 3; // variable greater or equal than MID_POLL_TIMES
- //TODO: make ENTIRE_POLL_TIMES configurable with enable or disable
- // must be variable greater or equal than common multiple of MID_POLL_TIMES and LONG_POLL_TIMES
- private static final int ENTIRE_POLL_TIMES = 6;
-
- private static final int DEFAULT_CAL_AND_POLL_FREQUENCY = 5;
- private static final int MIN_CAL_AND_POLL_FREQUENCY = 2;
- private static final int MAX_CAL_AND_POLL_FREQUENCY = 60;
-
- private int calAndPollInterval; // CAL_AND_POLL_TIMES * DEFAULT_CAL_AND_POLL_FREQUENCY;
- private int midPollInterval; // MID_POLL_TIMES * DEFAULT_CAL_AND_POLL_FREQUENCY;
- private int longPollInterval; // LONG_POLL_TIMES * DEFAULT_CAL_AND_POLL_FREQUENCY;
- // only used for checking condition at each task if it collects entire flows from a given switch or not
- private int entirePollInterval; // ENTIRE_POLL_TIMES * DEFAULT_CAL_AND_POLL_FREQUENCY;
-
- // Number of call count of each Task,
- // for undoing collection except only entire flows collecting task in CalAndShortFlowsTask
- private int callCountCalAndShortFlowsTask = 0; // increased CAL_AND_POLL_TIMES whenever Task is called
- private int callCountMidFlowsTask = 0; // increased MID_POLL_TIMES whenever Task is called
- private int callCountLongFlowsTask = 0; // increased LONG_POLL_TIMES whenever Task is called
-
- private InternalDeviceFlowTable deviceFlowTable = new InternalDeviceFlowTable();
-
- private boolean isFirstTimeStart = true;
-
- public static final long NO_FLOW_MISSING_XID = (-1);
- private long flowMissingXid = NO_FLOW_MISSING_XID;
-
- /**
- * Creates a new adaptive collector for the given switch and default cal_and_poll frequency.
- *
- * @param sw switch to pull
- * @param pollInterval cal and immediate poll frequency in seconds
- */
- NewAdaptiveFlowStatsCollector(OpenFlowSwitch sw, int pollInterval) {
- this.sw = sw;
-
- initMemberVars(pollInterval);
- }
-
- // check calAndPollInterval validity and set all pollInterval values and finally initialize each task call count
- private void initMemberVars(int pollInterval) {
- if (pollInterval < MIN_CAL_AND_POLL_FREQUENCY) {
- this.calAndPollInterval = MIN_CAL_AND_POLL_FREQUENCY;
- } else if (pollInterval >= MAX_CAL_AND_POLL_FREQUENCY) {
- this.calAndPollInterval = MAX_CAL_AND_POLL_FREQUENCY;
- } else {
- this.calAndPollInterval = pollInterval;
- }
-
- calAndPollInterval = CAL_AND_POLL_TIMES * calAndPollInterval;
- midPollInterval = MID_POLL_TIMES * calAndPollInterval;
- longPollInterval = LONG_POLL_TIMES * calAndPollInterval;
- entirePollInterval = ENTIRE_POLL_TIMES * calAndPollInterval;
-
- callCountCalAndShortFlowsTask = 0;
- callCountMidFlowsTask = 0;
- callCountLongFlowsTask = 0;
-
- flowMissingXid = NO_FLOW_MISSING_XID;
- }
-
- /**
- * Adjusts adaptive poll frequency.
- *
- * @param pollInterval poll frequency in seconds
- */
- synchronized void adjustCalAndPollInterval(int pollInterval) {
- initMemberVars(pollInterval);
-
- if (calAndShortFlowsThread != null) {
- calAndShortFlowsThread.cancel(false);
- }
- if (midFlowsThread != null) {
- midFlowsThread.cancel(false);
- }
- if (longFlowsThread != null) {
- longFlowsThread.cancel(false);
- }
-
- calAndShortFlowsTask = new CalAndShortFlowsTask();
- calAndShortFlowsThread = adaptiveFlowStatsScheduler.scheduleWithFixedDelay(
- calAndShortFlowsTask,
- 0,
- calAndPollInterval,
- TimeUnit.SECONDS);
-
- midFlowsTask = new MidFlowsTask();
- midFlowsThread = adaptiveFlowStatsScheduler.scheduleWithFixedDelay(
- midFlowsTask,
- 0,
- midPollInterval,
- TimeUnit.SECONDS);
-
- longFlowsTask = new LongFlowsTask();
- longFlowsThread = adaptiveFlowStatsScheduler.scheduleWithFixedDelay(
- longFlowsTask,
- 0,
- longPollInterval,
- TimeUnit.SECONDS);
-
- log.debug("calAndPollInterval=" + calAndPollInterval + "is adjusted");
- }
-
- private class CalAndShortFlowsTask implements Runnable {
- @Override
- public void run() {
- if (sw.getRole() == RoleState.MASTER) {
- log.trace("CalAndShortFlowsTask Collecting AdaptiveStats for {}", sw.getStringId());
-
- if (isFirstTimeStart) {
- // isFirstTimeStart, get entire flow stats from a given switch sw
- log.trace("CalAndShortFlowsTask Collecting Entire AdaptiveStats at first time start for {}",
- sw.getStringId());
- ofFlowStatsRequestAllSend();
-
- callCountCalAndShortFlowsTask += CAL_AND_POLL_TIMES;
- isFirstTimeStart = false;
- } else if (callCountCalAndShortFlowsTask == ENTIRE_POLL_TIMES) {
- // entire_poll_times, get entire flow stats from a given switch sw
- log.trace("CalAndShortFlowsTask Collecting Entire AdaptiveStats for {}", sw.getStringId());
- ofFlowStatsRequestAllSend();
-
- callCountCalAndShortFlowsTask = CAL_AND_POLL_TIMES;
- //TODO: check flows deleted in switch, but exist in controller flow table, then remove them
- //
- } else {
- calAndShortFlowsTaskInternal();
- callCountCalAndShortFlowsTask += CAL_AND_POLL_TIMES;
- }
- }
- }
- }
-
- // send openflow flow stats request message with getting all flow entries to a given switch sw
- private void ofFlowStatsRequestAllSend() {
- OFFlowStatsRequest request = sw.factory().buildFlowStatsRequest()
- .setMatch(sw.factory().matchWildcardAll())
- .setTableId(TableId.ALL)
- .setOutPort(OFPort.NO_MASK)
- .build();
-
- synchronized (this) {
- // set the request xid to check the reply in OpenFlowRuleProvider
- // After processing the reply of this request message,
- // this must be set to NO_FLOW_MISSING_XID(-1) by provider
- setFlowMissingXid(request.getXid());
- log.debug("ofFlowStatsRequestAllSend,Request={},for {}", request.toString(), sw.getStringId());
-
- sw.sendMsg(request);
- }
- }
-
- // send openflow flow stats request message with getting the specific flow entry(fe) to a given switch sw
- private void ofFlowStatsRequestFlowSend(FlowEntry fe) {
- // set find match
- Match match = FlowModBuilder.builder(fe, sw.factory(), Optional.empty(),
- Optional.empty()).buildMatch();
- // set find tableId
- TableId tableId = TableId.of(fe.tableId());
- // set output port
- Instruction ins = fe.treatment().allInstructions().stream()
- .filter(i -> (i.type() == Instruction.Type.OUTPUT))
- .findFirst()
- .orElse(null);
- OFPort ofPort = OFPort.NO_MASK;
- if (ins != null) {
- Instructions.OutputInstruction out = (Instructions.OutputInstruction) ins;
- ofPort = OFPort.of((int) ((out.port().toLong())));
- }
-
- OFFlowStatsRequest request = sw.factory().buildFlowStatsRequest()
- .setMatch(match)
- .setTableId(tableId)
- .setOutPort(ofPort)
- .build();
-
- synchronized (this) {
- if (getFlowMissingXid() != NO_FLOW_MISSING_XID) {
- log.debug("ofFlowStatsRequestFlowSend: previous FlowStatsRequestAll does not be processed yet,"
- + " set no flow missing xid anyway, for {}",
- sw.getStringId());
- setFlowMissingXid(NO_FLOW_MISSING_XID);
- }
-
- sw.sendMsg(request);
- }
- }
-
- private void calAndShortFlowsTaskInternal() {
- deviceFlowTable.checkAndMoveLiveFlowAll();
-
- deviceFlowTable.getShortFlows().forEach(fe -> {
- ofFlowStatsRequestFlowSend(fe);
- });
- }
-
- private class MidFlowsTask implements Runnable {
- @Override
- public void run() {
- if (sw.getRole() == RoleState.MASTER) {
- log.trace("MidFlowsTask Collecting AdaptiveStats for {}", sw.getStringId());
-
- // skip collecting because CalAndShortFlowsTask collects entire flow stats from a given switch sw
- if (callCountMidFlowsTask == ENTIRE_POLL_TIMES) {
- callCountMidFlowsTask = MID_POLL_TIMES;
- } else {
- midFlowsTaskInternal();
- callCountMidFlowsTask += MID_POLL_TIMES;
- }
- }
- }
- }
-
- private void midFlowsTaskInternal() {
- deviceFlowTable.getMidFlows().forEach(fe -> {
- ofFlowStatsRequestFlowSend(fe);
- });
- }
-
- private class LongFlowsTask implements Runnable {
- @Override
- public void run() {
- if (sw.getRole() == RoleState.MASTER) {
- log.trace("LongFlowsTask Collecting AdaptiveStats for {}", sw.getStringId());
-
- // skip collecting because CalAndShortFlowsTask collects entire flow stats from a given switch sw
- if (callCountLongFlowsTask == ENTIRE_POLL_TIMES) {
- callCountLongFlowsTask = LONG_POLL_TIMES;
- } else {
- longFlowsTaskInternal();
- callCountLongFlowsTask += LONG_POLL_TIMES;
- }
- }
- }
- }
-
- private void longFlowsTaskInternal() {
- deviceFlowTable.getLongFlows().forEach(fe -> {
- ofFlowStatsRequestFlowSend(fe);
- });
- }
-
- /**
- * start adaptive flow statistic collection.
- *
- */
- public synchronized void start() {
- log.debug("Starting AdaptiveStats collection thread for {}", sw.getStringId());
- callCountCalAndShortFlowsTask = 0;
- callCountMidFlowsTask = 0;
- callCountLongFlowsTask = 0;
-
- isFirstTimeStart = true;
-
- // Initially start polling quickly. Then drop down to configured value
- calAndShortFlowsTask = new CalAndShortFlowsTask();
- calAndShortFlowsThread = adaptiveFlowStatsScheduler.scheduleWithFixedDelay(
- calAndShortFlowsTask,
- 1,
- calAndPollInterval,
- TimeUnit.SECONDS);
-
- midFlowsTask = new MidFlowsTask();
- midFlowsThread = adaptiveFlowStatsScheduler.scheduleWithFixedDelay(
- midFlowsTask,
- 1,
- midPollInterval,
- TimeUnit.SECONDS);
-
- longFlowsTask = new LongFlowsTask();
- longFlowsThread = adaptiveFlowStatsScheduler.scheduleWithFixedDelay(
- longFlowsTask,
- 1,
- longPollInterval,
- TimeUnit.SECONDS);
-
- log.info("Started");
- }
-
- /**
- * stop adaptive flow statistic collection.
- *
- */
- public synchronized void stop() {
- log.debug("Stopping AdaptiveStats collection thread for {}", sw.getStringId());
- if (calAndShortFlowsThread != null) {
- calAndShortFlowsThread.cancel(true);
- }
- if (midFlowsThread != null) {
- midFlowsThread.cancel(true);
- }
- if (longFlowsThread != null) {
- longFlowsThread.cancel(true);
- }
-
- adaptiveFlowStatsScheduler.shutdownNow();
-
- isFirstTimeStart = false;
-
- log.info("Stopped");
- }
-
- /**
- * add typed flow entry from flow rule into the internal flow table.
- *
- * @param flowRules the flow rules
- *
- */
- public synchronized void addWithFlowRule(FlowRule... flowRules) {
- for (FlowRule fr : flowRules) {
- // First remove old entry unconditionally, if exist
- deviceFlowTable.remove(fr);
-
- // add new flow entry, we suppose IMMEDIATE_FLOW
- TypedStoredFlowEntry newFlowEntry = new DefaultTypedFlowEntry(fr,
- FlowLiveType.IMMEDIATE_FLOW);
- deviceFlowTable.addWithCalAndSetFlowLiveType(newFlowEntry);
- }
- }
-
- /**
- * add or update typed flow entry from flow entry into the internal flow table.
- *
- * @param flowEntries the flow entries
- *
- */
- public synchronized void addOrUpdateFlows(FlowEntry... flowEntries) {
- for (FlowEntry fe : flowEntries) {
- // check if this new rule is an update to an existing entry
- TypedStoredFlowEntry stored = deviceFlowTable.getFlowEntry(fe);
-
- if (stored != null) {
- // duplicated flow entry is collected!, just skip
- if (fe.bytes() == stored.bytes() && fe.packets() == stored.packets()
- && fe.life() == stored.life()) {
- log.debug("addOrUpdateFlows:, FlowId=" + Long.toHexString(fe.id().value())
- + ",is DUPLICATED stats collection, just skip."
- + " AdaptiveStats collection thread for {}",
- sw.getStringId());
-
- stored.setLastSeen();
- continue;
- } else if (fe.life() < stored.life()) {
- // Invalid updates the stats values, i.e., bytes, packets, durations ...
- log.debug("addOrUpdateFlows():" +
- " Invalid Flow Update! The new life is SMALLER than the previous one, jus skip." +
- " new flowId=" + Long.toHexString(fe.id().value()) +
- ", old flowId=" + Long.toHexString(stored.id().value()) +
- ", new bytes=" + fe.bytes() + ", old bytes=" + stored.bytes() +
- ", new life=" + fe.life() + ", old life=" + stored.life() +
- ", new lastSeen=" + fe.lastSeen() + ", old lastSeen=" + stored.lastSeen());
- // go next
- stored.setLastSeen();
- continue;
- }
-
- // update now
- stored.setLife(fe.life());
- stored.setPackets(fe.packets());
- stored.setBytes(fe.bytes());
- stored.setLastSeen();
- if (stored.state() == FlowEntry.FlowEntryState.PENDING_ADD) {
- // flow is really RULE_ADDED
- stored.setState(FlowEntry.FlowEntryState.ADDED);
- }
- // flow is RULE_UPDATED, skip adding and just updating flow live table
- //deviceFlowTable.calAndSetFlowLiveType(stored);
- continue;
- }
-
- // add new flow entry, we suppose IMMEDIATE_FLOW
- TypedStoredFlowEntry newFlowEntry = new DefaultTypedFlowEntry(fe,
- FlowLiveType.IMMEDIATE_FLOW);
- deviceFlowTable.addWithCalAndSetFlowLiveType(newFlowEntry);
- }
- }
-
- /**
- * remove typed flow entry from the internal flow table.
- *
- * @param flowRules the flow entries
- *
- */
- public synchronized void removeFlows(FlowRule... flowRules) {
- for (FlowRule rule : flowRules) {
- deviceFlowTable.remove(rule);
- }
- }
-
- // same as removeFlows() function
- /**
- * remove typed flow entry from the internal flow table.
- *
- * @param flowRules the flow entries
- *
- */
- public void flowRemoved(FlowRule... flowRules) {
- removeFlows(flowRules);
- }
-
- // same as addOrUpdateFlows() function
- /**
- * add or update typed flow entry from flow entry into the internal flow table.
- *
- * @param flowEntries the flow entry list
- *
- */
- public void pushFlowMetrics(List<FlowEntry> flowEntries) {
- flowEntries.forEach(fe -> {
- addOrUpdateFlows(fe);
- });
- }
-
- /**
- * returns flowMissingXid that indicates the execution of flowMissing process or not(NO_FLOW_MISSING_XID(-1)).
- *
- * @return xid of missing flow
- */
- public long getFlowMissingXid() {
- return flowMissingXid;
- }
-
- /**
- * set flowMissingXid, namely OFFlowStatsRequest match any ALL message Id.
- *
- * @param flowMissingXid the OFFlowStatsRequest message Id
- *
- */
- public void setFlowMissingXid(long flowMissingXid) {
- this.flowMissingXid = flowMissingXid;
- }
-
- private class InternalDeviceFlowTable {
-
- private final Map<FlowId, Set<TypedStoredFlowEntry>>
- flowEntries = Maps.newConcurrentMap();
-
- private final Set<StoredFlowEntry> shortFlows = new HashSet<>();
- private final Set<StoredFlowEntry> midFlows = new HashSet<>();
- private final Set<StoredFlowEntry> longFlows = new HashSet<>();
-
- // Assumed latency adjustment(default=500 millisecond) between FlowStatsRequest and Reply
- private final long latencyFlowStatsRequestAndReplyMillis = 500;
-
-
- // Statistics for table operation
- private long addCount = 0, addWithSetFlowLiveTypeCount = 0;
- private long removeCount = 0;
-
- /**
- * Resets all count values with zero.
- *
- */
- public void resetAllCount() {
- addCount = 0;
- addWithSetFlowLiveTypeCount = 0;
- removeCount = 0;
- }
-
- // get set of flow entries for the given flowId
- private Set<TypedStoredFlowEntry> getFlowEntriesInternal(FlowId flowId) {
- return flowEntries.computeIfAbsent(flowId, id -> Sets.newCopyOnWriteArraySet());
- }
-
- // get flow entry for the given flow rule
- private TypedStoredFlowEntry getFlowEntryInternal(FlowRule rule) {
- Set<TypedStoredFlowEntry> flowEntries = getFlowEntriesInternal(rule.id());
- return flowEntries.stream()
- .filter(entry -> Objects.equal(entry, rule))
- .findAny()
- .orElse(null);
- }
-
- // get the flow entries for all flows in flow table
- private Set<TypedStoredFlowEntry> getFlowEntriesInternal() {
- Set<TypedStoredFlowEntry> result = Sets.newHashSet();
-
- flowEntries.values().forEach(result::addAll);
- return result;
- }
-
- /**
- * Gets the number of flow entry in flow table.
- *
- * @return the number of flow entry.
- *
- */
- public long getFlowCount() {
- return flowEntries.values().stream().mapToLong(Set::size).sum();
- }
-
- /**
- * Gets the number of flow entry in flow table.
- *
- * @param rule the flow rule
- * @return the typed flow entry.
- *
- */
- public TypedStoredFlowEntry getFlowEntry(FlowRule rule) {
- checkNotNull(rule);
-
- return getFlowEntryInternal(rule);
- }
-
- /**
- * Gets the all typed flow entries in flow table.
- *
- * @return the set of typed flow entry.
- *
- */
- public Set<TypedStoredFlowEntry> getFlowEntries() {
- return getFlowEntriesInternal();
- }
-
- /**
- * Gets the short typed flow entries in flow table.
- *
- * @return the set of typed flow entry.
- *
- */
- public Set<StoredFlowEntry> getShortFlows() {
- return ImmutableSet.copyOf(shortFlows); //Sets.newHashSet(shortFlows);
- }
-
- /**
- * Gets the mid typed flow entries in flow table.
- *
- * @return the set of typed flow entry.
- *
- */
- public Set<StoredFlowEntry> getMidFlows() {
- return ImmutableSet.copyOf(midFlows); //Sets.newHashSet(midFlows);
- }
-
- /**
- * Gets the long typed flow entries in flow table.
- *
- * @return the set of typed flow entry.
- *
- */
- public Set<StoredFlowEntry> getLongFlows() {
- return ImmutableSet.copyOf(longFlows); //Sets.newHashSet(longFlows);
- }
-
- /**
- * Add typed flow entry into table only.
- *
- * @param rule the flow rule
- *
- */
- public synchronized void add(TypedStoredFlowEntry rule) {
- checkNotNull(rule);
-
- //rule have to be new DefaultTypedFlowEntry
- boolean result = getFlowEntriesInternal(rule.id()).add(rule);
-
- if (result) {
- addCount++;
- }
- }
-
- /**
- * Calculates and set the flow live type at the first time,
- * and then add it into a corresponding typed flow table.
- *
- * @param rule the flow rule
- *
- */
- public void calAndSetFlowLiveType(TypedStoredFlowEntry rule) {
- checkNotNull(rule);
-
- calAndSetFlowLiveTypeInternal(rule);
- }
-
- /**
- * Add the typed flow entry into table, and calculates and set the flow live type,
- * and then add it into a corresponding typed flow table.
- *
- * @param rule the flow rule
- *
- */
- public synchronized void addWithCalAndSetFlowLiveType(TypedStoredFlowEntry rule) {
- checkNotNull(rule);
-
- //rule have to be new DefaultTypedFlowEntry
- boolean result = getFlowEntriesInternal(rule.id()).add(rule);
- if (result) {
- calAndSetFlowLiveTypeInternal(rule);
- addWithSetFlowLiveTypeCount++;
- } else {
- log.debug("addWithCalAndSetFlowLiveType, FlowId=" + Long.toHexString(rule.id().value())
- + " ADD Failed, cause it may already exists in table !!!,"
- + " AdaptiveStats collection thread for {}",
- sw.getStringId());
- }
- }
-
- // In real, calculates and set the flow live type at the first time,
- // and then add it into a corresponding typed flow table
- private void calAndSetFlowLiveTypeInternal(TypedStoredFlowEntry rule) {
- long life = rule.life();
- FlowLiveType prevFlowLiveType = rule.flowLiveType();
-
- if (life >= longPollInterval) {
- rule.setFlowLiveType(FlowLiveType.LONG_FLOW);
- longFlows.add(rule);
- } else if (life >= midPollInterval) {
- rule.setFlowLiveType(FlowLiveType.MID_FLOW);
- midFlows.add(rule);
- } else if (life >= calAndPollInterval) {
- rule.setFlowLiveType(FlowLiveType.SHORT_FLOW);
- shortFlows.add(rule);
- } else if (life >= 0) {
- rule.setFlowLiveType(FlowLiveType.IMMEDIATE_FLOW);
- } else { // life < 0
- rule.setFlowLiveType(FlowLiveType.UNKNOWN_FLOW);
- }
-
- if (rule.flowLiveType() != prevFlowLiveType) {
- switch (prevFlowLiveType) {
- // delete it from previous flow table
- case SHORT_FLOW:
- shortFlows.remove(rule);
- break;
- case MID_FLOW:
- midFlows.remove(rule);
- break;
- case LONG_FLOW:
- longFlows.remove(rule);
- break;
- default:
- break;
- }
- }
- }
-
-
- // check the flow live type based on current time, then set and add it into corresponding table
- private boolean checkAndMoveLiveFlowInternal(TypedStoredFlowEntry fe, long cTime) {
- long curTime = (cTime > 0 ? cTime : System.currentTimeMillis());
- // For latency adjustment(default=500 millisecond) between FlowStatsRequest and Reply
- long fromLastSeen = ((curTime - fe.lastSeen() + latencyFlowStatsRequestAndReplyMillis) / 1000);
- // fe.life() unit is SECOND!
- long liveTime = fe.life() + fromLastSeen;
-
-
- switch (fe.flowLiveType()) {
- case IMMEDIATE_FLOW:
- if (liveTime >= longPollInterval) {
- fe.setFlowLiveType(FlowLiveType.LONG_FLOW);
- longFlows.add(fe);
- } else if (liveTime >= midPollInterval) {
- fe.setFlowLiveType(FlowLiveType.MID_FLOW);
- midFlows.add(fe);
- } else if (liveTime >= calAndPollInterval) {
- fe.setFlowLiveType(FlowLiveType.SHORT_FLOW);
- shortFlows.add(fe);
- }
- break;
- case SHORT_FLOW:
- if (liveTime >= longPollInterval) {
- fe.setFlowLiveType(FlowLiveType.LONG_FLOW);
- shortFlows.remove(fe);
- longFlows.add(fe);
- } else if (liveTime >= midPollInterval) {
- fe.setFlowLiveType(FlowLiveType.MID_FLOW);
- shortFlows.remove(fe);
- midFlows.add(fe);
- }
- break;
- case MID_FLOW:
- if (liveTime >= longPollInterval) {
- fe.setFlowLiveType(FlowLiveType.LONG_FLOW);
- midFlows.remove(fe);
- longFlows.add(fe);
- }
- break;
- case LONG_FLOW:
- if (fromLastSeen > entirePollInterval) {
- log.trace("checkAndMoveLiveFlowInternal, flow is already removed at switch.");
- return false;
- }
- break;
- case UNKNOWN_FLOW: // Unknown flow is an internal error flow type, just fall through
- default :
- // Error Unknown Live Type
- log.error("checkAndMoveLiveFlowInternal, Unknown Live Type error!"
- + "AdaptiveStats collection thread for {}",
- sw.getStringId());
- return false;
- }
-
- log.debug("checkAndMoveLiveFlowInternal, FlowId=" + Long.toHexString(fe.id().value())
- + ", state=" + fe.state()
- + ", After liveType=" + fe.flowLiveType()
- + ", liveTime=" + liveTime
- + ", life=" + fe.life()
- + ", bytes=" + fe.bytes()
- + ", packets=" + fe.packets()
- + ", fromLastSeen=" + fromLastSeen
- + ", priority=" + fe.priority()
- + ", selector=" + fe.selector().criteria()
- + ", treatment=" + fe.treatment()
- + " AdaptiveStats collection thread for {}",
- sw.getStringId());
-
- return true;
- }
-
- /**
- * Check and move live type for all type flow entries in table at every calAndPollInterval time.
- *
- */
- public void checkAndMoveLiveFlowAll() {
- Set<TypedStoredFlowEntry> typedFlowEntries = getFlowEntriesInternal();
-
- long calCurTime = System.currentTimeMillis();
- typedFlowEntries.forEach(fe -> {
- if (!checkAndMoveLiveFlowInternal(fe, calCurTime)) {
- remove(fe);
- }
- });
-
- // print table counts for debug
- if (log.isDebugEnabled()) {
- synchronized (this) {
- long totalFlowCount = getFlowCount();
- long shortFlowCount = shortFlows.size();
- long midFlowCount = midFlows.size();
- long longFlowCount = longFlows.size();
- long immediateFlowCount = totalFlowCount - shortFlowCount - midFlowCount - longFlowCount;
- long calTotalCount = addCount + addWithSetFlowLiveTypeCount - removeCount;
-
- log.debug("--------------------------------------------------------------------------- for {}",
- sw.getStringId());
- log.debug("checkAndMoveLiveFlowAll, Total Flow_Count=" + totalFlowCount
- + ", add - remove_Count=" + calTotalCount
- + ", IMMEDIATE_FLOW_Count=" + immediateFlowCount
- + ", SHORT_FLOW_Count=" + shortFlowCount
- + ", MID_FLOW_Count=" + midFlowCount
- + ", LONG_FLOW_Count=" + longFlowCount
- + ", add_Count=" + addCount
- + ", addWithSetFlowLiveType_Count=" + addWithSetFlowLiveTypeCount
- + ", remove_Count=" + removeCount
- + " AdaptiveStats collection thread for {}", sw.getStringId());
- log.debug("--------------------------------------------------------------------------- for {}",
- sw.getStringId());
- if (totalFlowCount != calTotalCount) {
- log.error("checkAndMoveLiveFlowAll, Real total flow count and "
- + "calculated total flow count do NOT match, something is wrong internally "
- + "or check counter value bound is over!");
- }
- if (immediateFlowCount < 0) {
- log.error("checkAndMoveLiveFlowAll, IMMEDIATE_FLOW count is negative, "
- + "something is wrong internally "
- + "or check counter value bound is over!");
- }
- }
- }
- log.trace("checkAndMoveLiveFlowAll, AdaptiveStats for {}", sw.getStringId());
- }
-
- /**
- * Remove the typed flow entry from table.
- *
- * @param rule the flow rule
- *
- */
- public synchronized void remove(FlowRule rule) {
- checkNotNull(rule);
-
- TypedStoredFlowEntry removeStore = getFlowEntryInternal(rule);
- if (removeStore != null) {
- removeLiveFlowsInternal((TypedStoredFlowEntry) removeStore);
- boolean result = getFlowEntriesInternal(rule.id()).remove(removeStore);
-
- if (result) {
- removeCount++;
- }
- }
- }
-
- // Remove the typed flow entry from corresponding table
- private void removeLiveFlowsInternal(TypedStoredFlowEntry fe) {
- switch (fe.flowLiveType()) {
- case IMMEDIATE_FLOW:
- // do nothing
- break;
- case SHORT_FLOW:
- shortFlows.remove(fe);
- break;
- case MID_FLOW:
- midFlows.remove(fe);
- break;
- case LONG_FLOW:
- longFlows.remove(fe);
- break;
- default: // error in Flow Live Type
- log.error("removeLiveFlowsInternal, Unknown Live Type error!");
- break;
- }
- }
- }
-}
+/* + * 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.provider.of.flow.impl; + +import com.google.common.base.Objects; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import org.onosproject.net.flow.DefaultTypedFlowEntry; +import org.onosproject.net.flow.FlowEntry; +import org.onosproject.net.flow.FlowId; +import org.onosproject.net.flow.FlowRule; +import org.onosproject.net.flow.StoredFlowEntry; +import org.onosproject.net.flow.TypedStoredFlowEntry; +import org.onosproject.net.flow.instructions.Instruction; +import org.onosproject.net.flow.instructions.Instructions; +import org.onosproject.openflow.controller.OpenFlowSwitch; +import org.onosproject.openflow.controller.RoleState; +import org.projectfloodlight.openflow.protocol.OFFlowStatsRequest; +import org.projectfloodlight.openflow.protocol.match.Match; +import org.projectfloodlight.openflow.types.OFPort; +import org.projectfloodlight.openflow.types.TableId; +import org.slf4j.Logger; + +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.onlab.util.Tools.groupedThreads; +import static org.onosproject.net.flow.TypedStoredFlowEntry.FlowLiveType; +import static org.slf4j.LoggerFactory.getLogger; + +/** + * Efficiently and adaptively collects flow statistics for the specified switch. + */ +public class NewAdaptiveFlowStatsCollector { + + private final Logger log = getLogger(getClass()); + + private final OpenFlowSwitch sw; + + private ScheduledExecutorService adaptiveFlowStatsScheduler = + Executors.newScheduledThreadPool(4, groupedThreads("onos/flow", "device-stats-collector-%d")); + private ScheduledFuture<?> calAndShortFlowsThread; + private ScheduledFuture<?> midFlowsThread; + private ScheduledFuture<?> longFlowsThread; + + // Task that calculates all flowEntries' FlowLiveType and collects stats IMMEDIATE flows every calAndPollInterval + private CalAndShortFlowsTask calAndShortFlowsTask; + // Task that collects stats MID flows every 2*calAndPollInterval + private MidFlowsTask midFlowsTask; + // Task that collects stats LONG flows every 3*calAndPollInterval + private LongFlowsTask longFlowsTask; + + private static final int CAL_AND_POLL_TIMES = 1; // must be always 0 + private static final int MID_POLL_TIMES = 2; // variable greater or equal than 1 + private static final int LONG_POLL_TIMES = 3; // variable greater or equal than MID_POLL_TIMES + //TODO: make ENTIRE_POLL_TIMES configurable with enable or disable + // must be variable greater or equal than common multiple of MID_POLL_TIMES and LONG_POLL_TIMES + private static final int ENTIRE_POLL_TIMES = 6; + + private static final int DEFAULT_CAL_AND_POLL_FREQUENCY = 5; + private static final int MIN_CAL_AND_POLL_FREQUENCY = 2; + private static final int MAX_CAL_AND_POLL_FREQUENCY = 60; + + private int calAndPollInterval; // CAL_AND_POLL_TIMES * DEFAULT_CAL_AND_POLL_FREQUENCY; + private int midPollInterval; // MID_POLL_TIMES * DEFAULT_CAL_AND_POLL_FREQUENCY; + private int longPollInterval; // LONG_POLL_TIMES * DEFAULT_CAL_AND_POLL_FREQUENCY; + // only used for checking condition at each task if it collects entire flows from a given switch or not + private int entirePollInterval; // ENTIRE_POLL_TIMES * DEFAULT_CAL_AND_POLL_FREQUENCY; + + // Number of call count of each Task, + // for undoing collection except only entire flows collecting task in CalAndShortFlowsTask + private int callCountCalAndShortFlowsTask = 0; // increased CAL_AND_POLL_TIMES whenever Task is called + private int callCountMidFlowsTask = 0; // increased MID_POLL_TIMES whenever Task is called + private int callCountLongFlowsTask = 0; // increased LONG_POLL_TIMES whenever Task is called + + private InternalDeviceFlowTable deviceFlowTable = new InternalDeviceFlowTable(); + + private boolean isFirstTimeStart = true; + + public static final long NO_FLOW_MISSING_XID = (-1); + private long flowMissingXid = NO_FLOW_MISSING_XID; + + /** + * Creates a new adaptive collector for the given switch and default cal_and_poll frequency. + * + * @param sw switch to pull + * @param pollInterval cal and immediate poll frequency in seconds + */ + NewAdaptiveFlowStatsCollector(OpenFlowSwitch sw, int pollInterval) { + this.sw = sw; + + initMemberVars(pollInterval); + } + + // check calAndPollInterval validity and set all pollInterval values and finally initialize each task call count + private void initMemberVars(int pollInterval) { + if (pollInterval < MIN_CAL_AND_POLL_FREQUENCY) { + this.calAndPollInterval = MIN_CAL_AND_POLL_FREQUENCY; + } else if (pollInterval >= MAX_CAL_AND_POLL_FREQUENCY) { + this.calAndPollInterval = MAX_CAL_AND_POLL_FREQUENCY; + } else { + this.calAndPollInterval = pollInterval; + } + + calAndPollInterval = CAL_AND_POLL_TIMES * calAndPollInterval; + midPollInterval = MID_POLL_TIMES * calAndPollInterval; + longPollInterval = LONG_POLL_TIMES * calAndPollInterval; + entirePollInterval = ENTIRE_POLL_TIMES * calAndPollInterval; + + callCountCalAndShortFlowsTask = 0; + callCountMidFlowsTask = 0; + callCountLongFlowsTask = 0; + + flowMissingXid = NO_FLOW_MISSING_XID; + } + + /** + * Adjusts adaptive poll frequency. + * + * @param pollInterval poll frequency in seconds + */ + synchronized void adjustCalAndPollInterval(int pollInterval) { + initMemberVars(pollInterval); + + if (calAndShortFlowsThread != null) { + calAndShortFlowsThread.cancel(false); + } + if (midFlowsThread != null) { + midFlowsThread.cancel(false); + } + if (longFlowsThread != null) { + longFlowsThread.cancel(false); + } + + calAndShortFlowsTask = new CalAndShortFlowsTask(); + calAndShortFlowsThread = adaptiveFlowStatsScheduler.scheduleWithFixedDelay( + calAndShortFlowsTask, + 0, + calAndPollInterval, + TimeUnit.SECONDS); + + midFlowsTask = new MidFlowsTask(); + midFlowsThread = adaptiveFlowStatsScheduler.scheduleWithFixedDelay( + midFlowsTask, + 0, + midPollInterval, + TimeUnit.SECONDS); + + longFlowsTask = new LongFlowsTask(); + longFlowsThread = adaptiveFlowStatsScheduler.scheduleWithFixedDelay( + longFlowsTask, + 0, + longPollInterval, + TimeUnit.SECONDS); + + log.debug("calAndPollInterval=" + calAndPollInterval + "is adjusted"); + } + + private class CalAndShortFlowsTask implements Runnable { + @Override + public void run() { + if (sw.getRole() == RoleState.MASTER) { + log.trace("CalAndShortFlowsTask Collecting AdaptiveStats for {}", sw.getStringId()); + + if (isFirstTimeStart) { + // isFirstTimeStart, get entire flow stats from a given switch sw + log.trace("CalAndShortFlowsTask Collecting Entire AdaptiveStats at first time start for {}", + sw.getStringId()); + ofFlowStatsRequestAllSend(); + + callCountCalAndShortFlowsTask += CAL_AND_POLL_TIMES; + isFirstTimeStart = false; + } else if (callCountCalAndShortFlowsTask == ENTIRE_POLL_TIMES) { + // entire_poll_times, get entire flow stats from a given switch sw + log.trace("CalAndShortFlowsTask Collecting Entire AdaptiveStats for {}", sw.getStringId()); + ofFlowStatsRequestAllSend(); + + callCountCalAndShortFlowsTask = CAL_AND_POLL_TIMES; + //TODO: check flows deleted in switch, but exist in controller flow table, then remove them + // + } else { + calAndShortFlowsTaskInternal(); + callCountCalAndShortFlowsTask += CAL_AND_POLL_TIMES; + } + } + } + } + + // send openflow flow stats request message with getting all flow entries to a given switch sw + private void ofFlowStatsRequestAllSend() { + OFFlowStatsRequest request = sw.factory().buildFlowStatsRequest() + .setMatch(sw.factory().matchWildcardAll()) + .setTableId(TableId.ALL) + .setOutPort(OFPort.NO_MASK) + .build(); + + synchronized (this) { + // set the request xid to check the reply in OpenFlowRuleProvider + // After processing the reply of this request message, + // this must be set to NO_FLOW_MISSING_XID(-1) by provider + setFlowMissingXid(request.getXid()); + log.debug("ofFlowStatsRequestAllSend,Request={},for {}", request.toString(), sw.getStringId()); + + sw.sendMsg(request); + } + } + + // send openflow flow stats request message with getting the specific flow entry(fe) to a given switch sw + private void ofFlowStatsRequestFlowSend(FlowEntry fe) { + // set find match + Match match = FlowModBuilder.builder(fe, sw.factory(), Optional.empty(), + Optional.empty()).buildMatch(); + // set find tableId + TableId tableId = TableId.of(fe.tableId()); + // set output port + Instruction ins = fe.treatment().allInstructions().stream() + .filter(i -> (i.type() == Instruction.Type.OUTPUT)) + .findFirst() + .orElse(null); + OFPort ofPort = OFPort.NO_MASK; + if (ins != null) { + Instructions.OutputInstruction out = (Instructions.OutputInstruction) ins; + ofPort = OFPort.of((int) ((out.port().toLong()))); + } + + OFFlowStatsRequest request = sw.factory().buildFlowStatsRequest() + .setMatch(match) + .setTableId(tableId) + .setOutPort(ofPort) + .build(); + + synchronized (this) { + if (getFlowMissingXid() != NO_FLOW_MISSING_XID) { + log.debug("ofFlowStatsRequestFlowSend: previous FlowStatsRequestAll does not be processed yet," + + " set no flow missing xid anyway, for {}", + sw.getStringId()); + setFlowMissingXid(NO_FLOW_MISSING_XID); + } + + sw.sendMsg(request); + } + } + + private void calAndShortFlowsTaskInternal() { + deviceFlowTable.checkAndMoveLiveFlowAll(); + + deviceFlowTable.getShortFlows().forEach(fe -> { + ofFlowStatsRequestFlowSend(fe); + }); + } + + private class MidFlowsTask implements Runnable { + @Override + public void run() { + if (sw.getRole() == RoleState.MASTER) { + log.trace("MidFlowsTask Collecting AdaptiveStats for {}", sw.getStringId()); + + // skip collecting because CalAndShortFlowsTask collects entire flow stats from a given switch sw + if (callCountMidFlowsTask == ENTIRE_POLL_TIMES) { + callCountMidFlowsTask = MID_POLL_TIMES; + } else { + midFlowsTaskInternal(); + callCountMidFlowsTask += MID_POLL_TIMES; + } + } + } + } + + private void midFlowsTaskInternal() { + deviceFlowTable.getMidFlows().forEach(fe -> { + ofFlowStatsRequestFlowSend(fe); + }); + } + + private class LongFlowsTask implements Runnable { + @Override + public void run() { + if (sw.getRole() == RoleState.MASTER) { + log.trace("LongFlowsTask Collecting AdaptiveStats for {}", sw.getStringId()); + + // skip collecting because CalAndShortFlowsTask collects entire flow stats from a given switch sw + if (callCountLongFlowsTask == ENTIRE_POLL_TIMES) { + callCountLongFlowsTask = LONG_POLL_TIMES; + } else { + longFlowsTaskInternal(); + callCountLongFlowsTask += LONG_POLL_TIMES; + } + } + } + } + + private void longFlowsTaskInternal() { + deviceFlowTable.getLongFlows().forEach(fe -> { + ofFlowStatsRequestFlowSend(fe); + }); + } + + /** + * start adaptive flow statistic collection. + * + */ + public synchronized void start() { + log.debug("Starting AdaptiveStats collection thread for {}", sw.getStringId()); + callCountCalAndShortFlowsTask = 0; + callCountMidFlowsTask = 0; + callCountLongFlowsTask = 0; + + isFirstTimeStart = true; + + // Initially start polling quickly. Then drop down to configured value + calAndShortFlowsTask = new CalAndShortFlowsTask(); + calAndShortFlowsThread = adaptiveFlowStatsScheduler.scheduleWithFixedDelay( + calAndShortFlowsTask, + 1, + calAndPollInterval, + TimeUnit.SECONDS); + + midFlowsTask = new MidFlowsTask(); + midFlowsThread = adaptiveFlowStatsScheduler.scheduleWithFixedDelay( + midFlowsTask, + 1, + midPollInterval, + TimeUnit.SECONDS); + + longFlowsTask = new LongFlowsTask(); + longFlowsThread = adaptiveFlowStatsScheduler.scheduleWithFixedDelay( + longFlowsTask, + 1, + longPollInterval, + TimeUnit.SECONDS); + + log.info("Started"); + } + + /** + * stop adaptive flow statistic collection. + * + */ + public synchronized void stop() { + log.debug("Stopping AdaptiveStats collection thread for {}", sw.getStringId()); + if (calAndShortFlowsThread != null) { + calAndShortFlowsThread.cancel(true); + } + if (midFlowsThread != null) { + midFlowsThread.cancel(true); + } + if (longFlowsThread != null) { + longFlowsThread.cancel(true); + } + + adaptiveFlowStatsScheduler.shutdownNow(); + + isFirstTimeStart = false; + + log.info("Stopped"); + } + + /** + * add typed flow entry from flow rule into the internal flow table. + * + * @param flowRules the flow rules + * + */ + public synchronized void addWithFlowRule(FlowRule... flowRules) { + for (FlowRule fr : flowRules) { + // First remove old entry unconditionally, if exist + deviceFlowTable.remove(fr); + + // add new flow entry, we suppose IMMEDIATE_FLOW + TypedStoredFlowEntry newFlowEntry = new DefaultTypedFlowEntry(fr, + FlowLiveType.IMMEDIATE_FLOW); + deviceFlowTable.addWithCalAndSetFlowLiveType(newFlowEntry); + } + } + + /** + * add or update typed flow entry from flow entry into the internal flow table. + * + * @param flowEntries the flow entries + * + */ + public synchronized void addOrUpdateFlows(FlowEntry... flowEntries) { + for (FlowEntry fe : flowEntries) { + // check if this new rule is an update to an existing entry + TypedStoredFlowEntry stored = deviceFlowTable.getFlowEntry(fe); + + if (stored != null) { + // duplicated flow entry is collected!, just skip + if (fe.bytes() == stored.bytes() && fe.packets() == stored.packets() + && fe.life() == stored.life()) { + log.debug("addOrUpdateFlows:, FlowId=" + Long.toHexString(fe.id().value()) + + ",is DUPLICATED stats collection, just skip." + + " AdaptiveStats collection thread for {}", + sw.getStringId()); + + stored.setLastSeen(); + continue; + } else if (fe.life() < stored.life()) { + // Invalid updates the stats values, i.e., bytes, packets, durations ... + log.debug("addOrUpdateFlows():" + + " Invalid Flow Update! The new life is SMALLER than the previous one, jus skip." + + " new flowId=" + Long.toHexString(fe.id().value()) + + ", old flowId=" + Long.toHexString(stored.id().value()) + + ", new bytes=" + fe.bytes() + ", old bytes=" + stored.bytes() + + ", new life=" + fe.life() + ", old life=" + stored.life() + + ", new lastSeen=" + fe.lastSeen() + ", old lastSeen=" + stored.lastSeen()); + // go next + stored.setLastSeen(); + continue; + } + + // update now + stored.setLife(fe.life()); + stored.setPackets(fe.packets()); + stored.setBytes(fe.bytes()); + stored.setLastSeen(); + if (stored.state() == FlowEntry.FlowEntryState.PENDING_ADD) { + // flow is really RULE_ADDED + stored.setState(FlowEntry.FlowEntryState.ADDED); + } + // flow is RULE_UPDATED, skip adding and just updating flow live table + //deviceFlowTable.calAndSetFlowLiveType(stored); + continue; + } + + // add new flow entry, we suppose IMMEDIATE_FLOW + TypedStoredFlowEntry newFlowEntry = new DefaultTypedFlowEntry(fe, + FlowLiveType.IMMEDIATE_FLOW); + deviceFlowTable.addWithCalAndSetFlowLiveType(newFlowEntry); + } + } + + /** + * remove typed flow entry from the internal flow table. + * + * @param flowRules the flow entries + * + */ + public synchronized void removeFlows(FlowRule... flowRules) { + for (FlowRule rule : flowRules) { + deviceFlowTable.remove(rule); + } + } + + // same as removeFlows() function + /** + * remove typed flow entry from the internal flow table. + * + * @param flowRules the flow entries + * + */ + public void flowRemoved(FlowRule... flowRules) { + removeFlows(flowRules); + } + + // same as addOrUpdateFlows() function + /** + * add or update typed flow entry from flow entry into the internal flow table. + * + * @param flowEntries the flow entry list + * + */ + public void pushFlowMetrics(List<FlowEntry> flowEntries) { + flowEntries.forEach(fe -> { + addOrUpdateFlows(fe); + }); + } + + /** + * returns flowMissingXid that indicates the execution of flowMissing process or not(NO_FLOW_MISSING_XID(-1)). + * + * @return xid of missing flow + */ + public long getFlowMissingXid() { + return flowMissingXid; + } + + /** + * set flowMissingXid, namely OFFlowStatsRequest match any ALL message Id. + * + * @param flowMissingXid the OFFlowStatsRequest message Id + * + */ + public void setFlowMissingXid(long flowMissingXid) { + this.flowMissingXid = flowMissingXid; + } + + private class InternalDeviceFlowTable { + + private final Map<FlowId, Set<TypedStoredFlowEntry>> + flowEntries = Maps.newConcurrentMap(); + + private final Set<StoredFlowEntry> shortFlows = new HashSet<>(); + private final Set<StoredFlowEntry> midFlows = new HashSet<>(); + private final Set<StoredFlowEntry> longFlows = new HashSet<>(); + + // Assumed latency adjustment(default=500 millisecond) between FlowStatsRequest and Reply + private final long latencyFlowStatsRequestAndReplyMillis = 500; + + + // Statistics for table operation + private long addCount = 0, addWithSetFlowLiveTypeCount = 0; + private long removeCount = 0; + + /** + * Resets all count values with zero. + * + */ + public void resetAllCount() { + addCount = 0; + addWithSetFlowLiveTypeCount = 0; + removeCount = 0; + } + + // get set of flow entries for the given flowId + private Set<TypedStoredFlowEntry> getFlowEntriesInternal(FlowId flowId) { + return flowEntries.computeIfAbsent(flowId, id -> Sets.newCopyOnWriteArraySet()); + } + + // get flow entry for the given flow rule + private TypedStoredFlowEntry getFlowEntryInternal(FlowRule rule) { + Set<TypedStoredFlowEntry> flowEntries = getFlowEntriesInternal(rule.id()); + return flowEntries.stream() + .filter(entry -> Objects.equal(entry, rule)) + .findAny() + .orElse(null); + } + + // get the flow entries for all flows in flow table + private Set<TypedStoredFlowEntry> getFlowEntriesInternal() { + Set<TypedStoredFlowEntry> result = Sets.newHashSet(); + + flowEntries.values().forEach(result::addAll); + return result; + } + + /** + * Gets the number of flow entry in flow table. + * + * @return the number of flow entry. + * + */ + public long getFlowCount() { + return flowEntries.values().stream().mapToLong(Set::size).sum(); + } + + /** + * Gets the number of flow entry in flow table. + * + * @param rule the flow rule + * @return the typed flow entry. + * + */ + public TypedStoredFlowEntry getFlowEntry(FlowRule rule) { + checkNotNull(rule); + + return getFlowEntryInternal(rule); + } + + /** + * Gets the all typed flow entries in flow table. + * + * @return the set of typed flow entry. + * + */ + public Set<TypedStoredFlowEntry> getFlowEntries() { + return getFlowEntriesInternal(); + } + + /** + * Gets the short typed flow entries in flow table. + * + * @return the set of typed flow entry. + * + */ + public Set<StoredFlowEntry> getShortFlows() { + return ImmutableSet.copyOf(shortFlows); //Sets.newHashSet(shortFlows); + } + + /** + * Gets the mid typed flow entries in flow table. + * + * @return the set of typed flow entry. + * + */ + public Set<StoredFlowEntry> getMidFlows() { + return ImmutableSet.copyOf(midFlows); //Sets.newHashSet(midFlows); + } + + /** + * Gets the long typed flow entries in flow table. + * + * @return the set of typed flow entry. + * + */ + public Set<StoredFlowEntry> getLongFlows() { + return ImmutableSet.copyOf(longFlows); //Sets.newHashSet(longFlows); + } + + /** + * Add typed flow entry into table only. + * + * @param rule the flow rule + * + */ + public synchronized void add(TypedStoredFlowEntry rule) { + checkNotNull(rule); + + //rule have to be new DefaultTypedFlowEntry + boolean result = getFlowEntriesInternal(rule.id()).add(rule); + + if (result) { + addCount++; + } + } + + /** + * Calculates and set the flow live type at the first time, + * and then add it into a corresponding typed flow table. + * + * @param rule the flow rule + * + */ + public void calAndSetFlowLiveType(TypedStoredFlowEntry rule) { + checkNotNull(rule); + + calAndSetFlowLiveTypeInternal(rule); + } + + /** + * Add the typed flow entry into table, and calculates and set the flow live type, + * and then add it into a corresponding typed flow table. + * + * @param rule the flow rule + * + */ + public synchronized void addWithCalAndSetFlowLiveType(TypedStoredFlowEntry rule) { + checkNotNull(rule); + + //rule have to be new DefaultTypedFlowEntry + boolean result = getFlowEntriesInternal(rule.id()).add(rule); + if (result) { + calAndSetFlowLiveTypeInternal(rule); + addWithSetFlowLiveTypeCount++; + } else { + log.debug("addWithCalAndSetFlowLiveType, FlowId=" + Long.toHexString(rule.id().value()) + + " ADD Failed, cause it may already exists in table !!!," + + " AdaptiveStats collection thread for {}", + sw.getStringId()); + } + } + + // In real, calculates and set the flow live type at the first time, + // and then add it into a corresponding typed flow table + private void calAndSetFlowLiveTypeInternal(TypedStoredFlowEntry rule) { + long life = rule.life(); + FlowLiveType prevFlowLiveType = rule.flowLiveType(); + + if (life >= longPollInterval) { + rule.setFlowLiveType(FlowLiveType.LONG_FLOW); + longFlows.add(rule); + } else if (life >= midPollInterval) { + rule.setFlowLiveType(FlowLiveType.MID_FLOW); + midFlows.add(rule); + } else if (life >= calAndPollInterval) { + rule.setFlowLiveType(FlowLiveType.SHORT_FLOW); + shortFlows.add(rule); + } else if (life >= 0) { + rule.setFlowLiveType(FlowLiveType.IMMEDIATE_FLOW); + } else { // life < 0 + rule.setFlowLiveType(FlowLiveType.UNKNOWN_FLOW); + } + + if (rule.flowLiveType() != prevFlowLiveType) { + switch (prevFlowLiveType) { + // delete it from previous flow table + case SHORT_FLOW: + shortFlows.remove(rule); + break; + case MID_FLOW: + midFlows.remove(rule); + break; + case LONG_FLOW: + longFlows.remove(rule); + break; + default: + break; + } + } + } + + + // check the flow live type based on current time, then set and add it into corresponding table + private boolean checkAndMoveLiveFlowInternal(TypedStoredFlowEntry fe, long cTime) { + long curTime = (cTime > 0 ? cTime : System.currentTimeMillis()); + // For latency adjustment(default=500 millisecond) between FlowStatsRequest and Reply + long fromLastSeen = ((curTime - fe.lastSeen() + latencyFlowStatsRequestAndReplyMillis) / 1000); + // fe.life() unit is SECOND! + long liveTime = fe.life() + fromLastSeen; + + + switch (fe.flowLiveType()) { + case IMMEDIATE_FLOW: + if (liveTime >= longPollInterval) { + fe.setFlowLiveType(FlowLiveType.LONG_FLOW); + longFlows.add(fe); + } else if (liveTime >= midPollInterval) { + fe.setFlowLiveType(FlowLiveType.MID_FLOW); + midFlows.add(fe); + } else if (liveTime >= calAndPollInterval) { + fe.setFlowLiveType(FlowLiveType.SHORT_FLOW); + shortFlows.add(fe); + } + break; + case SHORT_FLOW: + if (liveTime >= longPollInterval) { + fe.setFlowLiveType(FlowLiveType.LONG_FLOW); + shortFlows.remove(fe); + longFlows.add(fe); + } else if (liveTime >= midPollInterval) { + fe.setFlowLiveType(FlowLiveType.MID_FLOW); + shortFlows.remove(fe); + midFlows.add(fe); + } + break; + case MID_FLOW: + if (liveTime >= longPollInterval) { + fe.setFlowLiveType(FlowLiveType.LONG_FLOW); + midFlows.remove(fe); + longFlows.add(fe); + } + break; + case LONG_FLOW: + if (fromLastSeen > entirePollInterval) { + log.trace("checkAndMoveLiveFlowInternal, flow is already removed at switch."); + return false; + } + break; + case UNKNOWN_FLOW: // Unknown flow is an internal error flow type, just fall through + default : + // Error Unknown Live Type + log.error("checkAndMoveLiveFlowInternal, Unknown Live Type error!" + + "AdaptiveStats collection thread for {}", + sw.getStringId()); + return false; + } + + log.debug("checkAndMoveLiveFlowInternal, FlowId=" + Long.toHexString(fe.id().value()) + + ", state=" + fe.state() + + ", After liveType=" + fe.flowLiveType() + + ", liveTime=" + liveTime + + ", life=" + fe.life() + + ", bytes=" + fe.bytes() + + ", packets=" + fe.packets() + + ", fromLastSeen=" + fromLastSeen + + ", priority=" + fe.priority() + + ", selector=" + fe.selector().criteria() + + ", treatment=" + fe.treatment() + + " AdaptiveStats collection thread for {}", + sw.getStringId()); + + return true; + } + + /** + * Check and move live type for all type flow entries in table at every calAndPollInterval time. + * + */ + public void checkAndMoveLiveFlowAll() { + Set<TypedStoredFlowEntry> typedFlowEntries = getFlowEntriesInternal(); + + long calCurTime = System.currentTimeMillis(); + typedFlowEntries.forEach(fe -> { + if (!checkAndMoveLiveFlowInternal(fe, calCurTime)) { + remove(fe); + } + }); + + // print table counts for debug + if (log.isDebugEnabled()) { + synchronized (this) { + long totalFlowCount = getFlowCount(); + long shortFlowCount = shortFlows.size(); + long midFlowCount = midFlows.size(); + long longFlowCount = longFlows.size(); + long immediateFlowCount = totalFlowCount - shortFlowCount - midFlowCount - longFlowCount; + long calTotalCount = addCount + addWithSetFlowLiveTypeCount - removeCount; + + log.debug("--------------------------------------------------------------------------- for {}", + sw.getStringId()); + log.debug("checkAndMoveLiveFlowAll, Total Flow_Count=" + totalFlowCount + + ", add - remove_Count=" + calTotalCount + + ", IMMEDIATE_FLOW_Count=" + immediateFlowCount + + ", SHORT_FLOW_Count=" + shortFlowCount + + ", MID_FLOW_Count=" + midFlowCount + + ", LONG_FLOW_Count=" + longFlowCount + + ", add_Count=" + addCount + + ", addWithSetFlowLiveType_Count=" + addWithSetFlowLiveTypeCount + + ", remove_Count=" + removeCount + + " AdaptiveStats collection thread for {}", sw.getStringId()); + log.debug("--------------------------------------------------------------------------- for {}", + sw.getStringId()); + if (totalFlowCount != calTotalCount) { + log.error("checkAndMoveLiveFlowAll, Real total flow count and " + + "calculated total flow count do NOT match, something is wrong internally " + + "or check counter value bound is over!"); + } + if (immediateFlowCount < 0) { + log.error("checkAndMoveLiveFlowAll, IMMEDIATE_FLOW count is negative, " + + "something is wrong internally " + + "or check counter value bound is over!"); + } + } + } + log.trace("checkAndMoveLiveFlowAll, AdaptiveStats for {}", sw.getStringId()); + } + + /** + * Remove the typed flow entry from table. + * + * @param rule the flow rule + * + */ + public synchronized void remove(FlowRule rule) { + checkNotNull(rule); + + TypedStoredFlowEntry removeStore = getFlowEntryInternal(rule); + if (removeStore != null) { + removeLiveFlowsInternal((TypedStoredFlowEntry) removeStore); + boolean result = getFlowEntriesInternal(rule.id()).remove(removeStore); + + if (result) { + removeCount++; + } + } + } + + // Remove the typed flow entry from corresponding table + private void removeLiveFlowsInternal(TypedStoredFlowEntry fe) { + switch (fe.flowLiveType()) { + case IMMEDIATE_FLOW: + // do nothing + break; + case SHORT_FLOW: + shortFlows.remove(fe); + break; + case MID_FLOW: + midFlows.remove(fe); + break; + case LONG_FLOW: + longFlows.remove(fe); + break; + default: // error in Flow Live Type + log.error("removeLiveFlowsInternal, Unknown Live Type error!"); + break; + } + } + } +} diff --git a/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowValueMapper.java b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowValueMapper.java index 2f0831c6..556f76f5 100644 --- a/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowValueMapper.java +++ b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowValueMapper.java @@ -20,6 +20,7 @@ import com.google.common.collect.EnumHashBiMap; import org.onosproject.net.ChannelSpacing; import org.onosproject.net.GridType; import org.onosproject.net.OchSignalType; +import org.onosproject.net.OduSignalType; /** * Collection of helper methods to convert protocol agnostic models to values used in OpenFlow spec. @@ -54,6 +55,17 @@ final class OpenFlowValueMapper { OCH_SIGNAL_TYPES.put(OchSignalType.FLEX_GRID, (byte) 2); // OFPOCHT_FLEX_GRID of enum ofp_och_signal_type } + private static final BiMap<OduSignalType, Byte> ODU_SIGNAL_TYPES = EnumHashBiMap.create(OduSignalType.class); + static { + // See ONF "Optical Transport Protocol Extensions Version 1.0" for the following values + ODU_SIGNAL_TYPES.put(OduSignalType.ODU1, (byte) 1); // OFPODUT_ODU1 of enum ofp_odu_signal_type + ODU_SIGNAL_TYPES.put(OduSignalType.ODU2, (byte) 2); // OFPODUT_ODU2 of enum ofp_odu_signal_type + ODU_SIGNAL_TYPES.put(OduSignalType.ODU3, (byte) 3); // OFPODUT_ODU3 of enum ofp_odu_signal_type + ODU_SIGNAL_TYPES.put(OduSignalType.ODU4, (byte) 4); // OFPODUT_ODU4 of enum ofp_odu_signal_type + ODU_SIGNAL_TYPES.put(OduSignalType.ODU0, (byte) 10); // OFPODUT_ODU0 of enum ofp_odu_signal_type + ODU_SIGNAL_TYPES.put(OduSignalType.ODU2e, (byte) 11); // OFPODUT_ODU2E of enum ofp_odu_signal_type + } + /** * Looks up the specified input value to the corresponding value with the specified map. * @@ -149,4 +161,30 @@ final class OpenFlowValueMapper { static OchSignalType lookupOchSignalType(byte signalType) { return lookup(OCH_SIGNAL_TYPES.inverse(), signalType, OchSignalType.class); } + + /** + * Looks up the corresponding byte value for ODU signal type defined in + * ONF "Optical Transport Protocol Extensions Version 1.0" + * from the specified {@link OchSignalType} instance. + * + * @param signalType ODU (Optical channel Data Unit) signal type + * @return byte value corresponding to the specified ODU signal type + * @throws NoMappingFoundException if the specified ODU signal type is not found + */ + static byte lookupOduSignalType(OduSignalType signalType) { + return lookup(ODU_SIGNAL_TYPES, signalType, Byte.class); + } + + /** + * Looks up the the corresponding {@link OchSignalType} instance + * from the specified byte value for ODU signal type defined in + * ONF "Optical Transport Protocol Extensions Version 1.0". + * + * @param signalType byte value as ODU (Optical channel Data Unit) signal type defined the spec + * @return the corresponding OchSignalType instance + * @throws NoMappingFoundException if the specified ODU signal type is not found + */ + static OduSignalType lookupOduSignalType(byte signalType) { + return lookup(ODU_SIGNAL_TYPES.inverse(), signalType, OduSignalType.class); + } } 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 e69fd6b9..6c646d0d 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 @@ -128,7 +128,8 @@ public class OpenFlowGroupProvider extends AbstractProvider implements GroupProv public void deactivate() { providerRegistry.unregister(this); providerService = null; - + collectors.values().forEach(GroupStatsCollector::stop); + collectors.clear(); log.info("Stopped"); } diff --git a/framework/src/onos/providers/openflow/meter/src/main/java/org/onosproject/provider/of/meter/impl/OpenFlowMeterProvider.java b/framework/src/onos/providers/openflow/meter/src/main/java/org/onosproject/provider/of/meter/impl/OpenFlowMeterProvider.java index f5a777be..e4113790 100644 --- a/framework/src/onos/providers/openflow/meter/src/main/java/org/onosproject/provider/of/meter/impl/OpenFlowMeterProvider.java +++ b/framework/src/onos/providers/openflow/meter/src/main/java/org/onosproject/provider/of/meter/impl/OpenFlowMeterProvider.java @@ -132,6 +132,8 @@ public class OpenFlowMeterProvider extends AbstractProvider implements MeterProv @Deactivate public void deactivate() { providerRegistry.unregister(this); + collectors.values().forEach(MeterStatsCollector::stop); + collectors.clear(); controller.removeEventListener(listener); controller.removeListener(listener); providerService = null; diff --git a/framework/src/onos/providers/pom.xml b/framework/src/onos/providers/pom.xml index 32890b92..5665d324 100644 --- a/framework/src/onos/providers/pom.xml +++ b/framework/src/onos/providers/pom.xml @@ -35,11 +35,13 @@ <module>openflow</module> <module>lldp</module> <module>host</module> + <module>netcfghost</module> <module>netconf</module> <module>null</module> <module>pcep</module> <module>ovsdb</module> <module>bgp</module> + <module>snmp</module> </modules> <dependencies> diff --git a/framework/src/onos/providers/snmp/alarm/pom.xml b/framework/src/onos/providers/snmp/alarm/pom.xml new file mode 100644 index 00000000..f0a292e9 --- /dev/null +++ b/framework/src/onos/providers/snmp/alarm/pom.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ 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. + --> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.onosproject</groupId> + <artifactId>onos-snmp-providers</artifactId> + <version>1.4.0-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + + <artifactId>onos-snmp-provider-alarm</artifactId> + <packaging>bundle</packaging> + + <description>ONOS SNMP protocol alarm provider</description> + +</project>
\ No newline at end of file diff --git a/framework/src/onos/providers/snmp/alarm/src/main/java/org/onosproject/provider/snmp/alarm/impl/SNMPAlarmProvider.java b/framework/src/onos/providers/snmp/alarm/src/main/java/org/onosproject/provider/snmp/alarm/impl/SNMPAlarmProvider.java new file mode 100644 index 00000000..dc82a2cf --- /dev/null +++ b/framework/src/onos/providers/snmp/alarm/src/main/java/org/onosproject/provider/snmp/alarm/impl/SNMPAlarmProvider.java @@ -0,0 +1,57 @@ +/* + * Copyright 2014-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.provider.snmp.alarm.impl; + +import org.apache.felix.scr.annotations.Component; +import org.onosproject.net.DeviceId; +import org.onosproject.incubator.net.faultmanagement.alarm.AlarmProvider; +import org.onosproject.net.provider.AbstractProvider; +import org.onosproject.net.provider.ProviderId; +import org.slf4j.Logger; + +import static org.slf4j.LoggerFactory.getLogger; + +/** + * Provider which uses an SNMP controller to detect network device alarms. The class leverages functionality from + * + * @see <a href="https://github.com/btisystems/snmp-core">https://github.com/btisystems/snmp-core</a> + * @see <a href="https://github.com/btisystems/mibbler">https://github.com/btisystems/mibbler</a> + */ +@Component(immediate = true) +public class SNMPAlarmProvider extends AbstractProvider implements AlarmProvider { + + private static final Logger LOG = getLogger(SNMPAlarmProvider.class); + + /** + * Creates a SNMP alarm provider, dummy class provided as template, tbd later. + */ + public SNMPAlarmProvider() { + super(new ProviderId("snmp", "org.onosproject.provider.alarm")); + } + + @Override + public void triggerProbe(final DeviceId deviceId) { + + // TODO in shout term should this just be synchronous and return result? + LOG.info("Run a SNMP discovery for device at {} when done invoke on AlarmProviderService", deviceId); + + // TODO Look up AlarmProviderService + // TODO Decide threading + // TODO Decide shouldn't it be generic not alarm-specific ? Its user responsible for passing in OID list ? + // Same for its callack AlarmProviderService ? + } + +} diff --git a/framework/src/onos/providers/netconf/flow/src/main/java/org/onosproject/provider/netconf/flow/impl/package-info.java b/framework/src/onos/providers/snmp/alarm/src/main/java/org/onosproject/provider/snmp/alarm/impl/package-info.java index b095fc9a..2c138cbb 100644 --- a/framework/src/onos/providers/netconf/flow/src/main/java/org/onosproject/provider/netconf/flow/impl/package-info.java +++ b/framework/src/onos/providers/snmp/alarm/src/main/java/org/onosproject/provider/snmp/alarm/impl/package-info.java @@ -15,7 +15,6 @@ */ /** - * Provider that will accept any flow rules. + * Provider that uses SNMP as a means of discovering alarms on devices. */ -package org.onosproject.provider.netconf.flow.impl; - +package org.onosproject.provider.snmp.alarm.impl; diff --git a/framework/src/onos/providers/snmp/pom.xml b/framework/src/onos/providers/snmp/pom.xml new file mode 100644 index 00000000..21031d98 --- /dev/null +++ b/framework/src/onos/providers/snmp/pom.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ 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. + --> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.onosproject</groupId> + <artifactId>onos-providers</artifactId> + <version>1.4.0-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + + <artifactId>onos-snmp-providers</artifactId> + <packaging>pom</packaging> + + <description>ONOS SNMP Protocol Adapters</description> + + <modules> + <module>alarm</module> + </modules> + +</project>
\ No newline at end of file |