Showing
39 changed files
with
1283 additions
and
426 deletions
| ... | @@ -18,18 +18,20 @@ | ... | @@ -18,18 +18,20 @@ |
| 18 | 18 | ||
| 19 | <dependencies> | 19 | <dependencies> |
| 20 | <dependency> | 20 | <dependency> |
| 21 | - <groupId>org.codehaus.jackson</groupId> | 21 | + <groupId>org.codehaus.jackson</groupId> |
| 22 | - <artifactId>jackson-core-asl</artifactId> | 22 | + <artifactId>jackson-core-asl</artifactId> |
| 23 | </dependency> | 23 | </dependency> |
| 24 | <dependency> | 24 | <dependency> |
| 25 | - <groupId>org.codehaus.jackson</groupId> | 25 | + <groupId>org.codehaus.jackson</groupId> |
| 26 | - <artifactId>jackson-mapper-asl</artifactId> | 26 | + <artifactId>jackson-mapper-asl</artifactId> |
| 27 | </dependency> | 27 | </dependency> |
| 28 | <dependency> | 28 | <dependency> |
| 29 | <groupId>com.fasterxml.jackson.core</groupId> | 29 | <groupId>com.fasterxml.jackson.core</groupId> |
| 30 | <artifactId>jackson-annotations</artifactId> | 30 | <artifactId>jackson-annotations</artifactId> |
| 31 | - <version>2.4.2</version> | 31 | + </dependency> |
| 32 | - <scope>provided</scope> | 32 | + <dependency> |
| 33 | + <groupId>org.onlab.onos</groupId> | ||
| 34 | + <artifactId>onlab-misc</artifactId> | ||
| 33 | </dependency> | 35 | </dependency> |
| 34 | </dependencies> | 36 | </dependencies> |
| 35 | 37 | ... | ... |
| ... | @@ -41,5 +41,17 @@ | ... | @@ -41,5 +41,17 @@ |
| 41 | <groupId>org.apache.karaf.shell</groupId> | 41 | <groupId>org.apache.karaf.shell</groupId> |
| 42 | <artifactId>org.apache.karaf.shell.console</artifactId> | 42 | <artifactId>org.apache.karaf.shell.console</artifactId> |
| 43 | </dependency> | 43 | </dependency> |
| 44 | + <dependency> | ||
| 45 | + <groupId>org.onlab.onos</groupId> | ||
| 46 | + <artifactId>onlab-misc</artifactId> | ||
| 47 | + </dependency> | ||
| 48 | + <dependency> | ||
| 49 | + <groupId>com.google.guava</groupId> | ||
| 50 | + <artifactId>guava</artifactId> | ||
| 51 | + </dependency> | ||
| 52 | + <dependency> | ||
| 53 | + <groupId>org.osgi</groupId> | ||
| 54 | + <artifactId>org.osgi.core</artifactId> | ||
| 55 | + </dependency> | ||
| 44 | </dependencies> | 56 | </dependencies> |
| 45 | </project> | 57 | </project> | ... | ... |
| ... | @@ -4,8 +4,6 @@ import java.io.IOException; | ... | @@ -4,8 +4,6 @@ import java.io.IOException; |
| 4 | 4 | ||
| 5 | import org.onlab.netty.Message; | 5 | import org.onlab.netty.Message; |
| 6 | import org.onlab.netty.MessageHandler; | 6 | import org.onlab.netty.MessageHandler; |
| 7 | -import org.slf4j.Logger; | ||
| 8 | -import org.slf4j.LoggerFactory; | ||
| 9 | 7 | ||
| 10 | 8 | ||
| 11 | /** | 9 | /** |
| ... | @@ -13,11 +11,8 @@ import org.slf4j.LoggerFactory; | ... | @@ -13,11 +11,8 @@ import org.slf4j.LoggerFactory; |
| 13 | */ | 11 | */ |
| 14 | public class NettyEchoHandler implements MessageHandler { | 12 | public class NettyEchoHandler implements MessageHandler { |
| 15 | 13 | ||
| 16 | - private final Logger log = LoggerFactory.getLogger(getClass()); | ||
| 17 | - | ||
| 18 | @Override | 14 | @Override |
| 19 | public void handle(Message message) throws IOException { | 15 | public void handle(Message message) throws IOException { |
| 20 | - //log.info("Received message. Echoing it back to the sender."); | ||
| 21 | message.respond(message.payload()); | 16 | message.respond(message.payload()); |
| 22 | } | 17 | } |
| 23 | } | 18 | } | ... | ... |
| ... | @@ -8,12 +8,12 @@ import org.slf4j.LoggerFactory; | ... | @@ -8,12 +8,12 @@ import org.slf4j.LoggerFactory; |
| 8 | /** | 8 | /** |
| 9 | * A MessageHandler that simply logs the information. | 9 | * A MessageHandler that simply logs the information. |
| 10 | */ | 10 | */ |
| 11 | -public class NettyLoggingHandler implements MessageHandler { | 11 | +public class NettyNothingHandler implements MessageHandler { |
| 12 | 12 | ||
| 13 | private final Logger log = LoggerFactory.getLogger(getClass()); | 13 | private final Logger log = LoggerFactory.getLogger(getClass()); |
| 14 | 14 | ||
| 15 | @Override | 15 | @Override |
| 16 | public void handle(Message message) { | 16 | public void handle(Message message) { |
| 17 | - //log.info("Received message. Payload has {} bytes", message.payload().length); | 17 | + // Do nothing |
| 18 | } | 18 | } |
| 19 | } | 19 | } | ... | ... |
| 1 | package org.onlab.onos.foo; | 1 | package org.onlab.onos.foo; |
| 2 | 2 | ||
| 3 | +import static java.lang.Thread.sleep; | ||
| 4 | + | ||
| 3 | import java.io.IOException; | 5 | import java.io.IOException; |
| 4 | import java.util.concurrent.ExecutionException; | 6 | import java.util.concurrent.ExecutionException; |
| 7 | +import java.util.concurrent.TimeUnit; | ||
| 5 | import java.util.concurrent.TimeoutException; | 8 | import java.util.concurrent.TimeoutException; |
| 6 | 9 | ||
| 7 | import org.onlab.metrics.MetricsComponent; | 10 | import org.onlab.metrics.MetricsComponent; |
| ... | @@ -15,14 +18,29 @@ import org.slf4j.LoggerFactory; | ... | @@ -15,14 +18,29 @@ import org.slf4j.LoggerFactory; |
| 15 | 18 | ||
| 16 | import com.codahale.metrics.Timer; | 19 | import com.codahale.metrics.Timer; |
| 17 | 20 | ||
| 21 | +/** | ||
| 22 | + * The Simple netty client test. | ||
| 23 | + */ | ||
| 18 | // FIXME: Should be move out to test or app | 24 | // FIXME: Should be move out to test or app |
| 19 | public final class SimpleNettyClient { | 25 | public final class SimpleNettyClient { |
| 20 | 26 | ||
| 21 | private static Logger log = LoggerFactory.getLogger(SimpleNettyClient.class); | 27 | private static Logger log = LoggerFactory.getLogger(SimpleNettyClient.class); |
| 22 | 28 | ||
| 29 | + static NettyMessagingService messaging; | ||
| 30 | + static MetricsManager metrics; | ||
| 31 | + | ||
| 23 | private SimpleNettyClient() { | 32 | private SimpleNettyClient() { |
| 24 | } | 33 | } |
| 25 | 34 | ||
| 35 | + /** | ||
| 36 | + * The entry point of application. | ||
| 37 | + * | ||
| 38 | + * @param args the input arguments | ||
| 39 | + * @throws IOException the iO exception | ||
| 40 | + * @throws InterruptedException the interrupted exception | ||
| 41 | + * @throws ExecutionException the execution exception | ||
| 42 | + * @throws TimeoutException the timeout exception | ||
| 43 | + */ | ||
| 26 | public static void main(String[] args) | 44 | public static void main(String[] args) |
| 27 | throws IOException, InterruptedException, ExecutionException, | 45 | throws IOException, InterruptedException, ExecutionException, |
| 28 | TimeoutException { | 46 | TimeoutException { |
| ... | @@ -34,13 +52,20 @@ private static Logger log = LoggerFactory.getLogger(SimpleNettyClient.class); | ... | @@ -34,13 +52,20 @@ private static Logger log = LoggerFactory.getLogger(SimpleNettyClient.class); |
| 34 | 52 | ||
| 35 | System.exit(0); | 53 | System.exit(0); |
| 36 | } | 54 | } |
| 55 | + | ||
| 56 | + /** | ||
| 57 | + * Start standalone. | ||
| 58 | + * | ||
| 59 | + * @param args the args | ||
| 60 | + * @throws Exception the exception | ||
| 61 | + */ | ||
| 37 | public static void startStandalone(String[] args) throws Exception { | 62 | public static void startStandalone(String[] args) throws Exception { |
| 38 | String host = args.length > 0 ? args[0] : "localhost"; | 63 | String host = args.length > 0 ? args[0] : "localhost"; |
| 39 | int port = args.length > 1 ? Integer.parseInt(args[1]) : 8081; | 64 | int port = args.length > 1 ? Integer.parseInt(args[1]) : 8081; |
| 40 | int warmup = args.length > 2 ? Integer.parseInt(args[2]) : 1000; | 65 | int warmup = args.length > 2 ? Integer.parseInt(args[2]) : 1000; |
| 41 | int iterations = args.length > 3 ? Integer.parseInt(args[3]) : 50 * 100000; | 66 | int iterations = args.length > 3 ? Integer.parseInt(args[3]) : 50 * 100000; |
| 42 | - NettyMessagingService messaging = new TestNettyMessagingService(9081); | 67 | + messaging = new TestNettyMessagingService(9081); |
| 43 | - MetricsManager metrics = new MetricsManager(); | 68 | + metrics = new MetricsManager(); |
| 44 | Endpoint endpoint = new Endpoint(host, port); | 69 | Endpoint endpoint = new Endpoint(host, port); |
| 45 | messaging.activate(); | 70 | messaging.activate(); |
| 46 | metrics.activate(); | 71 | metrics.activate(); |
| ... | @@ -53,30 +78,61 @@ private static Logger log = LoggerFactory.getLogger(SimpleNettyClient.class); | ... | @@ -53,30 +78,61 @@ private static Logger log = LoggerFactory.getLogger(SimpleNettyClient.class); |
| 53 | Response response = messaging | 78 | Response response = messaging |
| 54 | .sendAndReceive(endpoint, "echo", | 79 | .sendAndReceive(endpoint, "echo", |
| 55 | "Hello World".getBytes()); | 80 | "Hello World".getBytes()); |
| 81 | + response.get(100000, TimeUnit.MILLISECONDS); | ||
| 82 | + } | ||
| 83 | + | ||
| 84 | + log.info("measuring round-trip send & receive"); | ||
| 85 | + Timer sendAndReceiveTimer = metrics.createTimer(component, feature, "SendAndReceive"); | ||
| 86 | + int timeouts = 0; | ||
| 87 | + | ||
| 88 | + for (int i = 0; i < iterations; i++) { | ||
| 89 | + Response response; | ||
| 90 | + Timer.Context context = sendAndReceiveTimer.time(); | ||
| 91 | + try { | ||
| 92 | + response = messaging | ||
| 93 | + .sendAndReceive(endpoint, "echo", | ||
| 94 | + "Hello World".getBytes()); | ||
| 95 | + response.get(10000, TimeUnit.MILLISECONDS); | ||
| 96 | + } catch (TimeoutException e) { | ||
| 97 | + timeouts++; | ||
| 98 | + log.info("timeout:" + timeouts + " at iteration:" + i); | ||
| 99 | + } finally { | ||
| 100 | + context.stop(); | ||
| 101 | + } | ||
| 102 | + // System.out.println("Got back:" + new String(response.get(2, TimeUnit.SECONDS))); | ||
| 56 | } | 103 | } |
| 57 | 104 | ||
| 105 | + sleep(1000); | ||
| 58 | log.info("measuring async sender"); | 106 | log.info("measuring async sender"); |
| 59 | Timer sendAsyncTimer = metrics.createTimer(component, feature, "AsyncSender"); | 107 | Timer sendAsyncTimer = metrics.createTimer(component, feature, "AsyncSender"); |
| 60 | 108 | ||
| 61 | for (int i = 0; i < iterations; i++) { | 109 | for (int i = 0; i < iterations; i++) { |
| 62 | - Timer.Context context = sendAsyncTimer.time(); | 110 | + Timer.Context context = sendAsyncTimer.time(); |
| 63 | - messaging.sendAsync(endpoint, "simple", "Hello World".getBytes()); | 111 | + messaging.sendAsync(endpoint, "simple", "Hello World".getBytes()); |
| 64 | - context.stop(); | 112 | + context.stop(); |
| 65 | } | 113 | } |
| 114 | + sleep(1000); | ||
| 115 | + } | ||
| 66 | 116 | ||
| 67 | - Timer sendAndReceiveTimer = metrics.createTimer(component, feature, "SendAndReceive"); | 117 | + public static void stop() { |
| 68 | - for (int i = 0; i < iterations; i++) { | 118 | + try { |
| 69 | - Timer.Context context = sendAndReceiveTimer.time(); | 119 | + messaging.deactivate(); |
| 70 | - Response response = messaging | 120 | + metrics.deactivate(); |
| 71 | - .sendAndReceive(endpoint, "echo", | 121 | + } catch (Exception e) { |
| 72 | - "Hello World".getBytes()); | 122 | + log.info("Unable to stop client %s", e); |
| 73 | - // System.out.println("Got back:" + new String(response.get(2, TimeUnit.SECONDS))); | ||
| 74 | - context.stop(); | ||
| 75 | } | 123 | } |
| 76 | - metrics.deactivate(); | ||
| 77 | } | 124 | } |
| 78 | 125 | ||
| 126 | + /** | ||
| 127 | + * The type Test netty messaging service. | ||
| 128 | + */ | ||
| 79 | public static class TestNettyMessagingService extends NettyMessagingService { | 129 | public static class TestNettyMessagingService extends NettyMessagingService { |
| 130 | + /** | ||
| 131 | + * Instantiates a new Test netty messaging service. | ||
| 132 | + * | ||
| 133 | + * @param port the port | ||
| 134 | + * @throws Exception the exception | ||
| 135 | + */ | ||
| 80 | public TestNettyMessagingService(int port) throws Exception { | 136 | public TestNettyMessagingService(int port) throws Exception { |
| 81 | super(port); | 137 | super(port); |
| 82 | } | 138 | } | ... | ... |
| 1 | package org.onlab.onos.foo; | 1 | package org.onlab.onos.foo; |
| 2 | 2 | ||
| 3 | import static org.onlab.onos.foo.SimpleNettyClient.startStandalone; | 3 | import static org.onlab.onos.foo.SimpleNettyClient.startStandalone; |
| 4 | +import static org.onlab.onos.foo.SimpleNettyClient.stop; | ||
| 4 | 5 | ||
| 5 | import org.apache.karaf.shell.commands.Argument; | 6 | import org.apache.karaf.shell.commands.Argument; |
| 6 | import org.apache.karaf.shell.commands.Command; | 7 | import org.apache.karaf.shell.commands.Command; |
| ... | @@ -10,7 +11,7 @@ import org.onlab.onos.cli.AbstractShellCommand; | ... | @@ -10,7 +11,7 @@ import org.onlab.onos.cli.AbstractShellCommand; |
| 10 | * Test Netty client performance. | 11 | * Test Netty client performance. |
| 11 | */ | 12 | */ |
| 12 | @Command(scope = "onos", name = "simple-netty-client", | 13 | @Command(scope = "onos", name = "simple-netty-client", |
| 13 | - description = "Starts the simple Netty client") | 14 | + description = "Starts simple Netty client") |
| 14 | public class SimpleNettyClientCommand extends AbstractShellCommand { | 15 | public class SimpleNettyClientCommand extends AbstractShellCommand { |
| 15 | 16 | ||
| 16 | //FIXME: replace these arguments with proper ones needed for the test. | 17 | //FIXME: replace these arguments with proper ones needed for the test. |
| ... | @@ -28,7 +29,7 @@ public class SimpleNettyClientCommand extends AbstractShellCommand { | ... | @@ -28,7 +29,7 @@ public class SimpleNettyClientCommand extends AbstractShellCommand { |
| 28 | 29 | ||
| 29 | @Argument(index = 3, name = "messageCount", description = "Message count", | 30 | @Argument(index = 3, name = "messageCount", description = "Message count", |
| 30 | required = false, multiValued = false) | 31 | required = false, multiValued = false) |
| 31 | - String messageCount = "100000"; | 32 | + String messageCount = "1000000"; |
| 32 | 33 | ||
| 33 | @Override | 34 | @Override |
| 34 | protected void execute() { | 35 | protected void execute() { |
| ... | @@ -37,5 +38,6 @@ public class SimpleNettyClientCommand extends AbstractShellCommand { | ... | @@ -37,5 +38,6 @@ public class SimpleNettyClientCommand extends AbstractShellCommand { |
| 37 | } catch (Exception e) { | 38 | } catch (Exception e) { |
| 38 | error("Unable to start client %s", e); | 39 | error("Unable to start client %s", e); |
| 39 | } | 40 | } |
| 41 | + stop(); | ||
| 40 | } | 42 | } |
| 41 | } | 43 | } | ... | ... |
| ... | @@ -12,16 +12,30 @@ import org.slf4j.LoggerFactory; | ... | @@ -12,16 +12,30 @@ import org.slf4j.LoggerFactory; |
| 12 | 12 | ||
| 13 | private SimpleNettyServer() {} | 13 | private SimpleNettyServer() {} |
| 14 | 14 | ||
| 15 | - public static void main(String... args) throws Exception { | 15 | + /** |
| 16 | + * The entry point of application. | ||
| 17 | + * | ||
| 18 | + * @param args the input arguments | ||
| 19 | + * @throws Exception the exception | ||
| 20 | + */ | ||
| 21 | + public static void main(String... args) throws Exception { | ||
| 16 | startStandalone(args); | 22 | startStandalone(args); |
| 17 | System.exit(0); | 23 | System.exit(0); |
| 18 | } | 24 | } |
| 19 | 25 | ||
| 20 | - public static void startStandalone(String[] args) throws Exception { | 26 | + /** |
| 21 | - NettyMessagingService server = new NettyMessagingService(8081); | 27 | + * Start standalone server. |
| 28 | + * | ||
| 29 | + * @param args the args | ||
| 30 | + * @throws Exception the exception | ||
| 31 | + */ | ||
| 32 | + public static void startStandalone(String[] args) throws Exception { | ||
| 33 | + int port = args.length > 0 ? Integer.parseInt(args[0]) : 8081; | ||
| 34 | + NettyMessagingService server = new NettyMessagingService(port); | ||
| 22 | server.activate(); | 35 | server.activate(); |
| 23 | - server.registerHandler("simple", new NettyLoggingHandler()); | 36 | + server.registerHandler("simple", new NettyNothingHandler()); |
| 24 | server.registerHandler("echo", new NettyEchoHandler()); | 37 | server.registerHandler("echo", new NettyEchoHandler()); |
| 38 | + log.info("Netty Server server on port " + port); | ||
| 25 | } | 39 | } |
| 26 | } | 40 | } |
| 27 | 41 | ... | ... |
| ... | @@ -10,26 +10,18 @@ import org.onlab.onos.cli.AbstractShellCommand; | ... | @@ -10,26 +10,18 @@ import org.onlab.onos.cli.AbstractShellCommand; |
| 10 | * Starts the Simple Netty server. | 10 | * Starts the Simple Netty server. |
| 11 | */ | 11 | */ |
| 12 | @Command(scope = "onos", name = "simple-netty-server", | 12 | @Command(scope = "onos", name = "simple-netty-server", |
| 13 | - description = "Starts the simple netty server") | 13 | + description = "Starts simple Netty server") |
| 14 | public class SimpleNettyServerCommand extends AbstractShellCommand { | 14 | public class SimpleNettyServerCommand extends AbstractShellCommand { |
| 15 | 15 | ||
| 16 | //FIXME: Replace these with parameters for | 16 | //FIXME: Replace these with parameters for |
| 17 | - @Argument(index = 0, name = "serverIp", description = "Server IP address", | 17 | + @Argument(index = 0, name = "port", description = "listen port", |
| 18 | required = false, multiValued = false) | 18 | required = false, multiValued = false) |
| 19 | - String serverIp = "127.0.0.1"; | 19 | + String port = "8081"; |
| 20 | - | ||
| 21 | - @Argument(index = 1, name = "workers", description = "IO workers", | ||
| 22 | - required = false, multiValued = false) | ||
| 23 | - String workers = "6"; | ||
| 24 | - | ||
| 25 | - @Argument(index = 2, name = "messageLength", description = "Message length (bytes)", | ||
| 26 | - required = false, multiValued = false) | ||
| 27 | - String messageLength = "128"; | ||
| 28 | 20 | ||
| 29 | @Override | 21 | @Override |
| 30 | protected void execute() { | 22 | protected void execute() { |
| 31 | try { | 23 | try { |
| 32 | - startStandalone(new String[]{serverIp, workers, messageLength}); | 24 | + startStandalone(new String[]{port}); |
| 33 | } catch (Exception e) { | 25 | } catch (Exception e) { |
| 34 | error("Unable to start server %s", e); | 26 | error("Unable to start server %s", e); |
| 35 | } | 27 | } | ... | ... |
| ... | @@ -16,4 +16,14 @@ | ... | @@ -16,4 +16,14 @@ |
| 16 | 16 | ||
| 17 | <description>ONOS simple Mobility app</description> | 17 | <description>ONOS simple Mobility app</description> |
| 18 | 18 | ||
| 19 | + <dependencies> | ||
| 20 | + <dependency> | ||
| 21 | + <groupId>com.google.guava</groupId> | ||
| 22 | + <artifactId>guava</artifactId> | ||
| 23 | + </dependency> | ||
| 24 | + <dependency> | ||
| 25 | + <groupId>org.onlab.onos</groupId> | ||
| 26 | + <artifactId>onlab-misc</artifactId> | ||
| 27 | + </dependency> | ||
| 28 | + </dependencies> | ||
| 19 | </project> | 29 | </project> | ... | ... |
| ... | @@ -23,7 +23,8 @@ | ... | @@ -23,7 +23,8 @@ |
| 23 | <module>foo</module> | 23 | <module>foo</module> |
| 24 | <module>mobility</module> | 24 | <module>mobility</module> |
| 25 | <module>proxyarp</module> | 25 | <module>proxyarp</module> |
| 26 | - <module>config</module> | 26 | + <module>config</module> |
| 27 | + <module>sdnip</module> | ||
| 27 | </modules> | 28 | </modules> |
| 28 | 29 | ||
| 29 | <properties> | 30 | <properties> | ... | ... |
apps/sdnip/pom.xml
0 → 100644
| 1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | +<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
| 3 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
| 4 | + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> | ||
| 5 | + <modelVersion>4.0.0</modelVersion> | ||
| 6 | + | ||
| 7 | + <parent> | ||
| 8 | + <groupId>org.onlab.onos</groupId> | ||
| 9 | + <artifactId>onos-apps</artifactId> | ||
| 10 | + <version>1.0.0-SNAPSHOT</version> | ||
| 11 | + <relativePath>../pom.xml</relativePath> | ||
| 12 | + </parent> | ||
| 13 | + | ||
| 14 | + <artifactId>onos-app-sdnip</artifactId> | ||
| 15 | + <packaging>bundle</packaging> | ||
| 16 | + | ||
| 17 | + <description>SDN-IP peering application</description> | ||
| 18 | + | ||
| 19 | + <dependencies> | ||
| 20 | + <dependency> | ||
| 21 | + <groupId>org.codehaus.jackson</groupId> | ||
| 22 | + <artifactId>jackson-core-asl</artifactId> | ||
| 23 | + </dependency> | ||
| 24 | + <dependency> | ||
| 25 | + <groupId>org.codehaus.jackson</groupId> | ||
| 26 | + <artifactId>jackson-mapper-asl</artifactId> | ||
| 27 | + </dependency> | ||
| 28 | + <dependency> | ||
| 29 | + <groupId>com.fasterxml.jackson.core</groupId> | ||
| 30 | + <artifactId>jackson-annotations</artifactId> | ||
| 31 | + <version>2.4.2</version> | ||
| 32 | + <scope>provided</scope> | ||
| 33 | + </dependency> | ||
| 34 | + </dependencies> | ||
| 35 | + | ||
| 36 | +</project> |
| 1 | +package org.onlab.onos.sdnip; | ||
| 2 | + | ||
| 3 | +import static org.slf4j.LoggerFactory.getLogger; | ||
| 4 | + | ||
| 5 | +import org.apache.felix.scr.annotations.Activate; | ||
| 6 | +import org.apache.felix.scr.annotations.Component; | ||
| 7 | +import org.apache.felix.scr.annotations.Deactivate; | ||
| 8 | +import org.slf4j.Logger; | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * Placeholder SDN-IP component. | ||
| 12 | + */ | ||
| 13 | +@Component(immediate = true) | ||
| 14 | +public class SdnIp { | ||
| 15 | + | ||
| 16 | + private final Logger log = getLogger(getClass()); | ||
| 17 | + | ||
| 18 | + @Activate | ||
| 19 | + protected void activate() { | ||
| 20 | + log.debug("SDN-IP started"); | ||
| 21 | + } | ||
| 22 | + | ||
| 23 | + @Deactivate | ||
| 24 | + protected void deactivate() { | ||
| 25 | + log.info("Stopped"); | ||
| 26 | + } | ||
| 27 | +} |
| 1 | -package org.onlab.onos.store.common.impl; | 1 | +package org.onlab.onos.cluster; |
| 2 | - | ||
| 3 | -import org.onlab.onos.cluster.ControllerNode; | ||
| 4 | -import org.onlab.onos.cluster.NodeId; | ||
| 5 | 2 | ||
| 6 | import com.google.common.base.Function; | 3 | import com.google.common.base.Function; |
| 7 | 4 | ||
| ... | @@ -18,6 +15,11 @@ public final class ControllerNodeToNodeId | ... | @@ -18,6 +15,11 @@ public final class ControllerNodeToNodeId |
| 18 | return input.id(); | 15 | return input.id(); |
| 19 | } | 16 | } |
| 20 | 17 | ||
| 18 | + /** | ||
| 19 | + * Returns a Function to convert ControllerNode to NodeId. | ||
| 20 | + * | ||
| 21 | + * @return ControllerNodeToNodeId instance. | ||
| 22 | + */ | ||
| 21 | public static ControllerNodeToNodeId toNodeId() { | 23 | public static ControllerNodeToNodeId toNodeId() { |
| 22 | return INSTANCE; | 24 | return INSTANCE; |
| 23 | } | 25 | } | ... | ... |
| 1 | +package org.onlab.onos.cluster; | ||
| 2 | + | ||
| 3 | +import static org.junit.Assert.*; | ||
| 4 | +import static org.onlab.onos.cluster.ControllerNodeToNodeId.toNodeId; | ||
| 5 | + | ||
| 6 | +import java.util.Arrays; | ||
| 7 | +import java.util.List; | ||
| 8 | + | ||
| 9 | +import org.junit.Test; | ||
| 10 | +import org.onlab.packet.IpPrefix; | ||
| 11 | + | ||
| 12 | +import com.google.common.collect.FluentIterable; | ||
| 13 | + | ||
| 14 | + | ||
| 15 | +public class ControllerNodeToNodeIdTest { | ||
| 16 | + | ||
| 17 | + private static final NodeId NID1 = new NodeId("foo"); | ||
| 18 | + private static final NodeId NID2 = new NodeId("bar"); | ||
| 19 | + private static final NodeId NID3 = new NodeId("buz"); | ||
| 20 | + | ||
| 21 | + private static final IpPrefix IP1 = IpPrefix.valueOf("127.0.0.1"); | ||
| 22 | + private static final IpPrefix IP2 = IpPrefix.valueOf("127.0.0.2"); | ||
| 23 | + private static final IpPrefix IP3 = IpPrefix.valueOf("127.0.0.3"); | ||
| 24 | + | ||
| 25 | + private static final ControllerNode CN1 = new DefaultControllerNode(NID1, IP1); | ||
| 26 | + private static final ControllerNode CN2 = new DefaultControllerNode(NID2, IP2); | ||
| 27 | + private static final ControllerNode CN3 = new DefaultControllerNode(NID3, IP3); | ||
| 28 | + | ||
| 29 | + | ||
| 30 | + @Test | ||
| 31 | + public final void testToNodeId() { | ||
| 32 | + | ||
| 33 | + final Iterable<ControllerNode> nodes = Arrays.asList(CN1, CN2, CN3); | ||
| 34 | + final List<NodeId> nodeIds = Arrays.asList(NID1, NID2, NID3); | ||
| 35 | + | ||
| 36 | + assertEquals(nodeIds, | ||
| 37 | + FluentIterable.from(nodes) | ||
| 38 | + .transform(toNodeId()) | ||
| 39 | + .toList()); | ||
| 40 | + } | ||
| 41 | + | ||
| 42 | +} |
| ... | @@ -9,6 +9,7 @@ import static org.onlab.onos.event.TestEvent.Type.FOO; | ... | @@ -9,6 +9,7 @@ import static org.onlab.onos.event.TestEvent.Type.FOO; |
| 9 | import java.util.List; | 9 | import java.util.List; |
| 10 | import java.util.Timer; | 10 | import java.util.Timer; |
| 11 | 11 | ||
| 12 | +import org.junit.Ignore; | ||
| 12 | import org.junit.Test; | 13 | import org.junit.Test; |
| 13 | 14 | ||
| 14 | /** | 15 | /** |
| ... | @@ -41,6 +42,7 @@ public class AbstractEventAccumulatorTest { | ... | @@ -41,6 +42,7 @@ public class AbstractEventAccumulatorTest { |
| 41 | assertEquals("incorrect batch", "abcde", accumulator.batch); | 42 | assertEquals("incorrect batch", "abcde", accumulator.batch); |
| 42 | } | 43 | } |
| 43 | 44 | ||
| 45 | + @Ignore("FIXME: timing sensitive test failing randomly.") | ||
| 44 | @Test | 46 | @Test |
| 45 | public void timeTrigger() { | 47 | public void timeTrigger() { |
| 46 | TestAccumulator accumulator = new TestAccumulator(); | 48 | TestAccumulator accumulator = new TestAccumulator(); | ... | ... |
| ... | @@ -54,8 +54,13 @@ | ... | @@ -54,8 +54,13 @@ |
| 54 | <artifactId>org.apache.felix.scr.annotations</artifactId> | 54 | <artifactId>org.apache.felix.scr.annotations</artifactId> |
| 55 | </dependency> | 55 | </dependency> |
| 56 | <dependency> | 56 | <dependency> |
| 57 | - <groupId>de.javakaffee</groupId> | 57 | + <groupId>com.google.guava</groupId> |
| 58 | - <artifactId>kryo-serializers</artifactId> | 58 | + <artifactId>guava-testlib</artifactId> |
| 59 | + <scope>test</scope> | ||
| 60 | + </dependency> | ||
| 61 | + <dependency> | ||
| 62 | + <groupId>org.apache.commons</groupId> | ||
| 63 | + <artifactId>commons-lang3</artifactId> | ||
| 59 | </dependency> | 64 | </dependency> |
| 60 | </dependencies> | 65 | </dependencies> |
| 61 | 66 | ... | ... |
| ... | @@ -65,6 +65,7 @@ import java.util.concurrent.TimeUnit; | ... | @@ -65,6 +65,7 @@ import java.util.concurrent.TimeUnit; |
| 65 | 65 | ||
| 66 | import static com.google.common.base.Preconditions.checkArgument; | 66 | import static com.google.common.base.Preconditions.checkArgument; |
| 67 | import static com.google.common.base.Predicates.notNull; | 67 | import static com.google.common.base.Predicates.notNull; |
| 68 | +import static org.onlab.onos.cluster.ControllerNodeToNodeId.toNodeId; | ||
| 68 | import static org.onlab.onos.net.device.DeviceEvent.Type.*; | 69 | import static org.onlab.onos.net.device.DeviceEvent.Type.*; |
| 69 | import static org.slf4j.LoggerFactory.getLogger; | 70 | import static org.slf4j.LoggerFactory.getLogger; |
| 70 | import static org.apache.commons.lang3.concurrent.ConcurrentUtils.createIfAbsentUnchecked; | 71 | import static org.apache.commons.lang3.concurrent.ConcurrentUtils.createIfAbsentUnchecked; |
| ... | @@ -73,7 +74,6 @@ import static com.google.common.base.Verify.verify; | ... | @@ -73,7 +74,6 @@ import static com.google.common.base.Verify.verify; |
| 73 | import static org.onlab.util.Tools.namedThreads; | 74 | import static org.onlab.util.Tools.namedThreads; |
| 74 | import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor; | 75 | import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor; |
| 75 | import static org.onlab.onos.store.device.impl.GossipDeviceStoreMessageSubjects.DEVICE_ADVERTISE; | 76 | import static org.onlab.onos.store.device.impl.GossipDeviceStoreMessageSubjects.DEVICE_ADVERTISE; |
| 76 | -import static org.onlab.onos.store.common.impl.ControllerNodeToNodeId.toNodeId; | ||
| 77 | 77 | ||
| 78 | // TODO: give me a better name | 78 | // TODO: give me a better name |
| 79 | /** | 79 | /** | ... | ... |
| 1 | +package org.onlab.onos.store.link.impl; | ||
| 2 | + | ||
| 3 | +import com.google.common.base.Function; | ||
| 4 | +import com.google.common.base.Predicate; | ||
| 5 | +import com.google.common.collect.FluentIterable; | ||
| 6 | +import com.google.common.collect.HashMultimap; | ||
| 7 | +import com.google.common.collect.ImmutableList; | ||
| 8 | +import com.google.common.collect.Maps; | ||
| 9 | +import com.google.common.collect.SetMultimap; | ||
| 10 | + | ||
| 11 | +import org.apache.commons.lang3.RandomUtils; | ||
| 12 | +import org.apache.commons.lang3.concurrent.ConcurrentUtils; | ||
| 13 | +import org.apache.felix.scr.annotations.Activate; | ||
| 14 | +import org.apache.felix.scr.annotations.Component; | ||
| 15 | +import org.apache.felix.scr.annotations.Deactivate; | ||
| 16 | +import org.apache.felix.scr.annotations.Reference; | ||
| 17 | +import org.apache.felix.scr.annotations.ReferenceCardinality; | ||
| 18 | +import org.apache.felix.scr.annotations.Service; | ||
| 19 | +import org.onlab.onos.cluster.ClusterService; | ||
| 20 | +import org.onlab.onos.cluster.ControllerNode; | ||
| 21 | +import org.onlab.onos.cluster.NodeId; | ||
| 22 | +import org.onlab.onos.net.AnnotationsUtil; | ||
| 23 | +import org.onlab.onos.net.ConnectPoint; | ||
| 24 | +import org.onlab.onos.net.DefaultAnnotations; | ||
| 25 | +import org.onlab.onos.net.DefaultLink; | ||
| 26 | +import org.onlab.onos.net.DeviceId; | ||
| 27 | +import org.onlab.onos.net.Link; | ||
| 28 | +import org.onlab.onos.net.SparseAnnotations; | ||
| 29 | +import org.onlab.onos.net.Link.Type; | ||
| 30 | +import org.onlab.onos.net.LinkKey; | ||
| 31 | +import org.onlab.onos.net.Provided; | ||
| 32 | +import org.onlab.onos.net.link.DefaultLinkDescription; | ||
| 33 | +import org.onlab.onos.net.link.LinkDescription; | ||
| 34 | +import org.onlab.onos.net.link.LinkEvent; | ||
| 35 | +import org.onlab.onos.net.link.LinkStore; | ||
| 36 | +import org.onlab.onos.net.link.LinkStoreDelegate; | ||
| 37 | +import org.onlab.onos.net.provider.ProviderId; | ||
| 38 | +import org.onlab.onos.store.AbstractStore; | ||
| 39 | +import org.onlab.onos.store.ClockService; | ||
| 40 | +import org.onlab.onos.store.Timestamp; | ||
| 41 | +import org.onlab.onos.store.cluster.messaging.ClusterCommunicationService; | ||
| 42 | +import org.onlab.onos.store.cluster.messaging.ClusterMessage; | ||
| 43 | +import org.onlab.onos.store.cluster.messaging.ClusterMessageHandler; | ||
| 44 | +import org.onlab.onos.store.cluster.messaging.MessageSubject; | ||
| 45 | +import org.onlab.onos.store.common.impl.Timestamped; | ||
| 46 | +import org.onlab.onos.store.serializers.DistributedStoreSerializers; | ||
| 47 | +import org.onlab.onos.store.serializers.KryoSerializer; | ||
| 48 | +import org.onlab.util.KryoPool; | ||
| 49 | +import org.onlab.util.NewConcurrentHashMap; | ||
| 50 | +import org.slf4j.Logger; | ||
| 51 | + | ||
| 52 | +import java.io.IOException; | ||
| 53 | +import java.util.Collections; | ||
| 54 | +import java.util.HashMap; | ||
| 55 | +import java.util.HashSet; | ||
| 56 | +import java.util.Map; | ||
| 57 | +import java.util.Set; | ||
| 58 | +import java.util.Map.Entry; | ||
| 59 | +import java.util.concurrent.ConcurrentHashMap; | ||
| 60 | +import java.util.concurrent.ConcurrentMap; | ||
| 61 | +import java.util.concurrent.ScheduledExecutorService; | ||
| 62 | +import java.util.concurrent.TimeUnit; | ||
| 63 | + | ||
| 64 | +import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor; | ||
| 65 | +import static org.onlab.onos.cluster.ControllerNodeToNodeId.toNodeId; | ||
| 66 | +import static org.onlab.onos.net.DefaultAnnotations.union; | ||
| 67 | +import static org.onlab.onos.net.DefaultAnnotations.merge; | ||
| 68 | +import static org.onlab.onos.net.Link.Type.DIRECT; | ||
| 69 | +import static org.onlab.onos.net.Link.Type.INDIRECT; | ||
| 70 | +import static org.onlab.onos.net.link.LinkEvent.Type.*; | ||
| 71 | +import static org.onlab.util.Tools.namedThreads; | ||
| 72 | +import static org.slf4j.LoggerFactory.getLogger; | ||
| 73 | +import static com.google.common.collect.Multimaps.synchronizedSetMultimap; | ||
| 74 | +import static com.google.common.base.Predicates.notNull; | ||
| 75 | + | ||
| 76 | +/** | ||
| 77 | + * Manages inventory of infrastructure links in distributed data store | ||
| 78 | + * that uses optimistic replication and gossip based techniques. | ||
| 79 | + */ | ||
| 80 | +@Component(immediate = true) | ||
| 81 | +@Service | ||
| 82 | +public class GossipLinkStore | ||
| 83 | + extends AbstractStore<LinkEvent, LinkStoreDelegate> | ||
| 84 | + implements LinkStore { | ||
| 85 | + | ||
| 86 | + private final Logger log = getLogger(getClass()); | ||
| 87 | + | ||
| 88 | + // Link inventory | ||
| 89 | + private final ConcurrentMap<LinkKey, ConcurrentMap<ProviderId, Timestamped<LinkDescription>>> linkDescs = | ||
| 90 | + new ConcurrentHashMap<>(); | ||
| 91 | + | ||
| 92 | + // Link instance cache | ||
| 93 | + private final ConcurrentMap<LinkKey, Link> links = new ConcurrentHashMap<>(); | ||
| 94 | + | ||
| 95 | + // Egress and ingress link sets | ||
| 96 | + private final SetMultimap<DeviceId, LinkKey> srcLinks = createSynchronizedHashMultiMap(); | ||
| 97 | + private final SetMultimap<DeviceId, LinkKey> dstLinks = createSynchronizedHashMultiMap(); | ||
| 98 | + | ||
| 99 | + // Remove links | ||
| 100 | + private final Map<LinkKey, Timestamp> removedLinks = Maps.newHashMap(); | ||
| 101 | + | ||
| 102 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
| 103 | + protected ClockService clockService; | ||
| 104 | + | ||
| 105 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
| 106 | + protected ClusterCommunicationService clusterCommunicator; | ||
| 107 | + | ||
| 108 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
| 109 | + protected ClusterService clusterService; | ||
| 110 | + | ||
| 111 | + private static final KryoSerializer SERIALIZER = new KryoSerializer() { | ||
| 112 | + @Override | ||
| 113 | + protected void setupKryoPool() { | ||
| 114 | + serializerPool = KryoPool.newBuilder() | ||
| 115 | + .register(DistributedStoreSerializers.COMMON) | ||
| 116 | + .register(InternalLinkEvent.class) | ||
| 117 | + .register(InternalLinkRemovedEvent.class) | ||
| 118 | + .register(LinkAntiEntropyAdvertisement.class) | ||
| 119 | + .register(LinkFragmentId.class) | ||
| 120 | + .build() | ||
| 121 | + .populate(1); | ||
| 122 | + } | ||
| 123 | + }; | ||
| 124 | + | ||
| 125 | + private ScheduledExecutorService executor; | ||
| 126 | + | ||
| 127 | + @Activate | ||
| 128 | + public void activate() { | ||
| 129 | + | ||
| 130 | + clusterCommunicator.addSubscriber( | ||
| 131 | + GossipLinkStoreMessageSubjects.LINK_UPDATE, | ||
| 132 | + new InternalLinkEventListener()); | ||
| 133 | + clusterCommunicator.addSubscriber( | ||
| 134 | + GossipLinkStoreMessageSubjects.LINK_REMOVED, | ||
| 135 | + new InternalLinkRemovedEventListener()); | ||
| 136 | + clusterCommunicator.addSubscriber( | ||
| 137 | + GossipLinkStoreMessageSubjects.LINK_ANTI_ENTROPY_ADVERTISEMENT, | ||
| 138 | + new InternalLinkAntiEntropyAdvertisementListener()); | ||
| 139 | + | ||
| 140 | + executor = | ||
| 141 | + newSingleThreadScheduledExecutor(namedThreads("link-anti-entropy-%d")); | ||
| 142 | + | ||
| 143 | + // TODO: Make these configurable | ||
| 144 | + long initialDelaySec = 5; | ||
| 145 | + long periodSec = 5; | ||
| 146 | + // start anti-entropy thread | ||
| 147 | + executor.scheduleAtFixedRate(new SendAdvertisementTask(), | ||
| 148 | + initialDelaySec, periodSec, TimeUnit.SECONDS); | ||
| 149 | + | ||
| 150 | + log.info("Started"); | ||
| 151 | + } | ||
| 152 | + | ||
| 153 | + @Deactivate | ||
| 154 | + public void deactivate() { | ||
| 155 | + linkDescs.clear(); | ||
| 156 | + links.clear(); | ||
| 157 | + srcLinks.clear(); | ||
| 158 | + dstLinks.clear(); | ||
| 159 | + log.info("Stopped"); | ||
| 160 | + } | ||
| 161 | + | ||
| 162 | + @Override | ||
| 163 | + public int getLinkCount() { | ||
| 164 | + return links.size(); | ||
| 165 | + } | ||
| 166 | + | ||
| 167 | + @Override | ||
| 168 | + public Iterable<Link> getLinks() { | ||
| 169 | + return Collections.unmodifiableCollection(links.values()); | ||
| 170 | + } | ||
| 171 | + | ||
| 172 | + @Override | ||
| 173 | + public Set<Link> getDeviceEgressLinks(DeviceId deviceId) { | ||
| 174 | + // lock for iteration | ||
| 175 | + synchronized (srcLinks) { | ||
| 176 | + return FluentIterable.from(srcLinks.get(deviceId)) | ||
| 177 | + .transform(lookupLink()) | ||
| 178 | + .filter(notNull()) | ||
| 179 | + .toSet(); | ||
| 180 | + } | ||
| 181 | + } | ||
| 182 | + | ||
| 183 | + @Override | ||
| 184 | + public Set<Link> getDeviceIngressLinks(DeviceId deviceId) { | ||
| 185 | + // lock for iteration | ||
| 186 | + synchronized (dstLinks) { | ||
| 187 | + return FluentIterable.from(dstLinks.get(deviceId)) | ||
| 188 | + .transform(lookupLink()) | ||
| 189 | + .filter(notNull()) | ||
| 190 | + .toSet(); | ||
| 191 | + } | ||
| 192 | + } | ||
| 193 | + | ||
| 194 | + @Override | ||
| 195 | + public Link getLink(ConnectPoint src, ConnectPoint dst) { | ||
| 196 | + return links.get(new LinkKey(src, dst)); | ||
| 197 | + } | ||
| 198 | + | ||
| 199 | + @Override | ||
| 200 | + public Set<Link> getEgressLinks(ConnectPoint src) { | ||
| 201 | + Set<Link> egress = new HashSet<>(); | ||
| 202 | + for (LinkKey linkKey : srcLinks.get(src.deviceId())) { | ||
| 203 | + if (linkKey.src().equals(src)) { | ||
| 204 | + egress.add(links.get(linkKey)); | ||
| 205 | + } | ||
| 206 | + } | ||
| 207 | + return egress; | ||
| 208 | + } | ||
| 209 | + | ||
| 210 | + @Override | ||
| 211 | + public Set<Link> getIngressLinks(ConnectPoint dst) { | ||
| 212 | + Set<Link> ingress = new HashSet<>(); | ||
| 213 | + for (LinkKey linkKey : dstLinks.get(dst.deviceId())) { | ||
| 214 | + if (linkKey.dst().equals(dst)) { | ||
| 215 | + ingress.add(links.get(linkKey)); | ||
| 216 | + } | ||
| 217 | + } | ||
| 218 | + return ingress; | ||
| 219 | + } | ||
| 220 | + | ||
| 221 | + @Override | ||
| 222 | + public LinkEvent createOrUpdateLink(ProviderId providerId, | ||
| 223 | + LinkDescription linkDescription) { | ||
| 224 | + | ||
| 225 | + DeviceId dstDeviceId = linkDescription.dst().deviceId(); | ||
| 226 | + Timestamp newTimestamp = clockService.getTimestamp(dstDeviceId); | ||
| 227 | + | ||
| 228 | + final Timestamped<LinkDescription> deltaDesc = new Timestamped<>(linkDescription, newTimestamp); | ||
| 229 | + | ||
| 230 | + LinkEvent event = createOrUpdateLinkInternal(providerId, deltaDesc); | ||
| 231 | + | ||
| 232 | + if (event != null) { | ||
| 233 | + log.info("Notifying peers of a link update topology event from providerId: " | ||
| 234 | + + "{} between src: {} and dst: {}", | ||
| 235 | + providerId, linkDescription.src(), linkDescription.dst()); | ||
| 236 | + try { | ||
| 237 | + notifyPeers(new InternalLinkEvent(providerId, deltaDesc)); | ||
| 238 | + } catch (IOException e) { | ||
| 239 | + log.info("Failed to notify peers of a link update topology event from providerId: " | ||
| 240 | + + "{} between src: {} and dst: {}", | ||
| 241 | + providerId, linkDescription.src(), linkDescription.dst()); | ||
| 242 | + } | ||
| 243 | + } | ||
| 244 | + return event; | ||
| 245 | + } | ||
| 246 | + | ||
| 247 | + private LinkEvent createOrUpdateLinkInternal( | ||
| 248 | + ProviderId providerId, | ||
| 249 | + Timestamped<LinkDescription> linkDescription) { | ||
| 250 | + | ||
| 251 | + LinkKey key = new LinkKey(linkDescription.value().src(), linkDescription.value().dst()); | ||
| 252 | + ConcurrentMap<ProviderId, Timestamped<LinkDescription>> descs = getLinkDescriptions(key); | ||
| 253 | + | ||
| 254 | + synchronized (descs) { | ||
| 255 | + // if the link was previously removed, we should proceed if and | ||
| 256 | + // only if this request is more recent. | ||
| 257 | + Timestamp linkRemovedTimestamp = removedLinks.get(key); | ||
| 258 | + if (linkRemovedTimestamp != null) { | ||
| 259 | + if (linkDescription.isNewer(linkRemovedTimestamp)) { | ||
| 260 | + removedLinks.remove(key); | ||
| 261 | + } else { | ||
| 262 | + return null; | ||
| 263 | + } | ||
| 264 | + } | ||
| 265 | + | ||
| 266 | + final Link oldLink = links.get(key); | ||
| 267 | + // update description | ||
| 268 | + createOrUpdateLinkDescription(descs, providerId, linkDescription); | ||
| 269 | + final Link newLink = composeLink(descs); | ||
| 270 | + if (oldLink == null) { | ||
| 271 | + return createLink(key, newLink); | ||
| 272 | + } | ||
| 273 | + return updateLink(key, oldLink, newLink); | ||
| 274 | + } | ||
| 275 | + } | ||
| 276 | + | ||
| 277 | + // Guarded by linkDescs value (=locking each Link) | ||
| 278 | + private Timestamped<LinkDescription> createOrUpdateLinkDescription( | ||
| 279 | + ConcurrentMap<ProviderId, Timestamped<LinkDescription>> existingLinkDescriptions, | ||
| 280 | + ProviderId providerId, | ||
| 281 | + Timestamped<LinkDescription> linkDescription) { | ||
| 282 | + | ||
| 283 | + // merge existing attributes and merge | ||
| 284 | + Timestamped<LinkDescription> existingLinkDescription = existingLinkDescriptions.get(providerId); | ||
| 285 | + if (existingLinkDescription != null && existingLinkDescription.isNewer(linkDescription)) { | ||
| 286 | + return null; | ||
| 287 | + } | ||
| 288 | + Timestamped<LinkDescription> newLinkDescription = linkDescription; | ||
| 289 | + if (existingLinkDescription != null) { | ||
| 290 | + SparseAnnotations merged = union(existingLinkDescription.value().annotations(), | ||
| 291 | + linkDescription.value().annotations()); | ||
| 292 | + newLinkDescription = new Timestamped<LinkDescription>( | ||
| 293 | + new DefaultLinkDescription( | ||
| 294 | + linkDescription.value().src(), | ||
| 295 | + linkDescription.value().dst(), | ||
| 296 | + linkDescription.value().type(), merged), | ||
| 297 | + linkDescription.timestamp()); | ||
| 298 | + } | ||
| 299 | + return existingLinkDescriptions.put(providerId, newLinkDescription); | ||
| 300 | + } | ||
| 301 | + | ||
| 302 | + // Creates and stores the link and returns the appropriate event. | ||
| 303 | + // Guarded by linkDescs value (=locking each Link) | ||
| 304 | + private LinkEvent createLink(LinkKey key, Link newLink) { | ||
| 305 | + | ||
| 306 | + if (newLink.providerId().isAncillary()) { | ||
| 307 | + // TODO: revisit ancillary only Link handling | ||
| 308 | + | ||
| 309 | + // currently treating ancillary only as down (not visible outside) | ||
| 310 | + return null; | ||
| 311 | + } | ||
| 312 | + | ||
| 313 | + links.put(key, newLink); | ||
| 314 | + srcLinks.put(newLink.src().deviceId(), key); | ||
| 315 | + dstLinks.put(newLink.dst().deviceId(), key); | ||
| 316 | + return new LinkEvent(LINK_ADDED, newLink); | ||
| 317 | + } | ||
| 318 | + | ||
| 319 | + // Updates, if necessary the specified link and returns the appropriate event. | ||
| 320 | + // Guarded by linkDescs value (=locking each Link) | ||
| 321 | + private LinkEvent updateLink(LinkKey key, Link oldLink, Link newLink) { | ||
| 322 | + | ||
| 323 | + if (newLink.providerId().isAncillary()) { | ||
| 324 | + // TODO: revisit ancillary only Link handling | ||
| 325 | + | ||
| 326 | + // currently treating ancillary only as down (not visible outside) | ||
| 327 | + return null; | ||
| 328 | + } | ||
| 329 | + | ||
| 330 | + if ((oldLink.type() == INDIRECT && newLink.type() == DIRECT) || | ||
| 331 | + !AnnotationsUtil.isEqual(oldLink.annotations(), newLink.annotations())) { | ||
| 332 | + | ||
| 333 | + links.put(key, newLink); | ||
| 334 | + // strictly speaking following can be ommitted | ||
| 335 | + srcLinks.put(oldLink.src().deviceId(), key); | ||
| 336 | + dstLinks.put(oldLink.dst().deviceId(), key); | ||
| 337 | + return new LinkEvent(LINK_UPDATED, newLink); | ||
| 338 | + } | ||
| 339 | + return null; | ||
| 340 | + } | ||
| 341 | + | ||
| 342 | + @Override | ||
| 343 | + public LinkEvent removeLink(ConnectPoint src, ConnectPoint dst) { | ||
| 344 | + final LinkKey key = new LinkKey(src, dst); | ||
| 345 | + | ||
| 346 | + DeviceId dstDeviceId = dst.deviceId(); | ||
| 347 | + Timestamp timestamp = clockService.getTimestamp(dstDeviceId); | ||
| 348 | + | ||
| 349 | + LinkEvent event = removeLinkInternal(key, timestamp); | ||
| 350 | + | ||
| 351 | + if (event != null) { | ||
| 352 | + log.info("Notifying peers of a link removed topology event for a link " | ||
| 353 | + + "between src: {} and dst: {}", src, dst); | ||
| 354 | + try { | ||
| 355 | + notifyPeers(new InternalLinkRemovedEvent(key, timestamp)); | ||
| 356 | + } catch (IOException e) { | ||
| 357 | + log.error("Failed to notify peers of a link removed topology event for a link " | ||
| 358 | + + "between src: {} and dst: {}", src, dst); | ||
| 359 | + } | ||
| 360 | + } | ||
| 361 | + return event; | ||
| 362 | + } | ||
| 363 | + | ||
| 364 | + private LinkEvent removeLinkInternal(LinkKey key, Timestamp timestamp) { | ||
| 365 | + ConcurrentMap<ProviderId, Timestamped<LinkDescription>> linkDescriptions = | ||
| 366 | + getLinkDescriptions(key); | ||
| 367 | + synchronized (linkDescriptions) { | ||
| 368 | + // accept removal request if given timestamp is newer than | ||
| 369 | + // the latest Timestamp from Primary provider | ||
| 370 | + ProviderId primaryProviderId = pickPrimaryProviderId(linkDescriptions); | ||
| 371 | + if (linkDescriptions.get(primaryProviderId).isNewer(timestamp)) { | ||
| 372 | + return null; | ||
| 373 | + } | ||
| 374 | + removedLinks.put(key, timestamp); | ||
| 375 | + Link link = links.remove(key); | ||
| 376 | + linkDescriptions.clear(); | ||
| 377 | + if (link != null) { | ||
| 378 | + srcLinks.remove(link.src().deviceId(), key); | ||
| 379 | + dstLinks.remove(link.dst().deviceId(), key); | ||
| 380 | + return new LinkEvent(LINK_REMOVED, link); | ||
| 381 | + } | ||
| 382 | + return null; | ||
| 383 | + } | ||
| 384 | + } | ||
| 385 | + | ||
| 386 | + private static <K, V> SetMultimap<K, V> createSynchronizedHashMultiMap() { | ||
| 387 | + return synchronizedSetMultimap(HashMultimap.<K, V>create()); | ||
| 388 | + } | ||
| 389 | + | ||
| 390 | + /** | ||
| 391 | + * @return primary ProviderID, or randomly chosen one if none exists | ||
| 392 | + */ | ||
| 393 | + private ProviderId pickPrimaryProviderId( | ||
| 394 | + ConcurrentMap<ProviderId, Timestamped<LinkDescription>> providerDescs) { | ||
| 395 | + | ||
| 396 | + ProviderId fallBackPrimary = null; | ||
| 397 | + for (Entry<ProviderId, Timestamped<LinkDescription>> e : providerDescs.entrySet()) { | ||
| 398 | + if (!e.getKey().isAncillary()) { | ||
| 399 | + return e.getKey(); | ||
| 400 | + } else if (fallBackPrimary == null) { | ||
| 401 | + // pick randomly as a fallback in case there is no primary | ||
| 402 | + fallBackPrimary = e.getKey(); | ||
| 403 | + } | ||
| 404 | + } | ||
| 405 | + return fallBackPrimary; | ||
| 406 | + } | ||
| 407 | + | ||
| 408 | + private Link composeLink(ConcurrentMap<ProviderId, Timestamped<LinkDescription>> linkDescriptions) { | ||
| 409 | + ProviderId primaryProviderId = pickPrimaryProviderId(linkDescriptions); | ||
| 410 | + Timestamped<LinkDescription> base = linkDescriptions.get(primaryProviderId); | ||
| 411 | + | ||
| 412 | + ConnectPoint src = base.value().src(); | ||
| 413 | + ConnectPoint dst = base.value().dst(); | ||
| 414 | + Type type = base.value().type(); | ||
| 415 | + DefaultAnnotations annotations = DefaultAnnotations.builder().build(); | ||
| 416 | + annotations = merge(annotations, base.value().annotations()); | ||
| 417 | + | ||
| 418 | + for (Entry<ProviderId, Timestamped<LinkDescription>> e : linkDescriptions.entrySet()) { | ||
| 419 | + if (primaryProviderId.equals(e.getKey())) { | ||
| 420 | + continue; | ||
| 421 | + } | ||
| 422 | + | ||
| 423 | + // TODO: should keep track of Description timestamp | ||
| 424 | + // and only merge conflicting keys when timestamp is newer | ||
| 425 | + // Currently assuming there will never be a key conflict between | ||
| 426 | + // providers | ||
| 427 | + | ||
| 428 | + // annotation merging. not so efficient, should revisit later | ||
| 429 | + annotations = merge(annotations, e.getValue().value().annotations()); | ||
| 430 | + } | ||
| 431 | + | ||
| 432 | + return new DefaultLink(primaryProviderId , src, dst, type, annotations); | ||
| 433 | + } | ||
| 434 | + | ||
| 435 | + private ConcurrentMap<ProviderId, Timestamped<LinkDescription>> getLinkDescriptions(LinkKey key) { | ||
| 436 | + return ConcurrentUtils.createIfAbsentUnchecked(linkDescs, key, | ||
| 437 | + NewConcurrentHashMap.<ProviderId, Timestamped<LinkDescription>>ifNeeded()); | ||
| 438 | + } | ||
| 439 | + | ||
| 440 | + private Timestamped<LinkDescription> getLinkDescription(LinkKey key, ProviderId providerId) { | ||
| 441 | + return getLinkDescriptions(key).get(providerId); | ||
| 442 | + } | ||
| 443 | + | ||
| 444 | + private final Function<LinkKey, Link> lookupLink = new LookupLink(); | ||
| 445 | + private Function<LinkKey, Link> lookupLink() { | ||
| 446 | + return lookupLink; | ||
| 447 | + } | ||
| 448 | + | ||
| 449 | + private final class LookupLink implements Function<LinkKey, Link> { | ||
| 450 | + @Override | ||
| 451 | + public Link apply(LinkKey input) { | ||
| 452 | + return links.get(input); | ||
| 453 | + } | ||
| 454 | + } | ||
| 455 | + | ||
| 456 | + private static final Predicate<Provided> IS_PRIMARY = new IsPrimary(); | ||
| 457 | + private static final Predicate<Provided> isPrimary() { | ||
| 458 | + return IS_PRIMARY; | ||
| 459 | + } | ||
| 460 | + | ||
| 461 | + private static final class IsPrimary implements Predicate<Provided> { | ||
| 462 | + | ||
| 463 | + @Override | ||
| 464 | + public boolean apply(Provided input) { | ||
| 465 | + return !input.providerId().isAncillary(); | ||
| 466 | + } | ||
| 467 | + } | ||
| 468 | + | ||
| 469 | + private void notifyDelegateIfNotNull(LinkEvent event) { | ||
| 470 | + if (event != null) { | ||
| 471 | + notifyDelegate(event); | ||
| 472 | + } | ||
| 473 | + } | ||
| 474 | + | ||
| 475 | + // TODO: should we be throwing exception? | ||
| 476 | + private void broadcastMessage(MessageSubject subject, Object event) throws IOException { | ||
| 477 | + ClusterMessage message = new ClusterMessage( | ||
| 478 | + clusterService.getLocalNode().id(), | ||
| 479 | + subject, | ||
| 480 | + SERIALIZER.encode(event)); | ||
| 481 | + clusterCommunicator.broadcast(message); | ||
| 482 | + } | ||
| 483 | + | ||
| 484 | + // TODO: should we be throwing exception? | ||
| 485 | + private void unicastMessage(NodeId recipient, MessageSubject subject, Object event) { | ||
| 486 | + try { | ||
| 487 | + ClusterMessage message = new ClusterMessage( | ||
| 488 | + clusterService.getLocalNode().id(), | ||
| 489 | + subject, | ||
| 490 | + SERIALIZER.encode(event)); | ||
| 491 | + clusterCommunicator.unicast(message, recipient); | ||
| 492 | + } catch (IOException e) { | ||
| 493 | + log.error("Failed to send a {} message to {}", subject.value(), recipient); | ||
| 494 | + } | ||
| 495 | + } | ||
| 496 | + | ||
| 497 | + private void notifyPeers(InternalLinkEvent event) throws IOException { | ||
| 498 | + broadcastMessage(GossipLinkStoreMessageSubjects.LINK_UPDATE, event); | ||
| 499 | + } | ||
| 500 | + | ||
| 501 | + private void notifyPeers(InternalLinkRemovedEvent event) throws IOException { | ||
| 502 | + broadcastMessage(GossipLinkStoreMessageSubjects.LINK_REMOVED, event); | ||
| 503 | + } | ||
| 504 | + | ||
| 505 | + private void notifyPeer(NodeId peer, InternalLinkEvent event) { | ||
| 506 | + unicastMessage(peer, GossipLinkStoreMessageSubjects.LINK_UPDATE, event); | ||
| 507 | + } | ||
| 508 | + | ||
| 509 | + private void notifyPeer(NodeId peer, InternalLinkRemovedEvent event) { | ||
| 510 | + unicastMessage(peer, GossipLinkStoreMessageSubjects.LINK_REMOVED, event); | ||
| 511 | + } | ||
| 512 | + | ||
| 513 | + private final class SendAdvertisementTask implements Runnable { | ||
| 514 | + | ||
| 515 | + @Override | ||
| 516 | + public void run() { | ||
| 517 | + if (Thread.currentThread().isInterrupted()) { | ||
| 518 | + log.info("Interrupted, quitting"); | ||
| 519 | + return; | ||
| 520 | + } | ||
| 521 | + | ||
| 522 | + try { | ||
| 523 | + final NodeId self = clusterService.getLocalNode().id(); | ||
| 524 | + Set<ControllerNode> nodes = clusterService.getNodes(); | ||
| 525 | + | ||
| 526 | + ImmutableList<NodeId> nodeIds = FluentIterable.from(nodes) | ||
| 527 | + .transform(toNodeId()) | ||
| 528 | + .toList(); | ||
| 529 | + | ||
| 530 | + if (nodeIds.size() == 1 && nodeIds.get(0).equals(self)) { | ||
| 531 | + log.info("No other peers in the cluster."); | ||
| 532 | + return; | ||
| 533 | + } | ||
| 534 | + | ||
| 535 | + NodeId peer; | ||
| 536 | + do { | ||
| 537 | + int idx = RandomUtils.nextInt(0, nodeIds.size()); | ||
| 538 | + peer = nodeIds.get(idx); | ||
| 539 | + } while (peer.equals(self)); | ||
| 540 | + | ||
| 541 | + LinkAntiEntropyAdvertisement ad = createAdvertisement(); | ||
| 542 | + | ||
| 543 | + if (Thread.currentThread().isInterrupted()) { | ||
| 544 | + log.info("Interrupted, quitting"); | ||
| 545 | + return; | ||
| 546 | + } | ||
| 547 | + | ||
| 548 | + try { | ||
| 549 | + unicastMessage(peer, GossipLinkStoreMessageSubjects.LINK_ANTI_ENTROPY_ADVERTISEMENT, ad); | ||
| 550 | + } catch (Exception e) { | ||
| 551 | + log.error("Failed to send anti-entropy advertisement", e); | ||
| 552 | + return; | ||
| 553 | + } | ||
| 554 | + } catch (Exception e) { | ||
| 555 | + // catch all Exception to avoid Scheduled task being suppressed. | ||
| 556 | + log.error("Exception thrown while sending advertisement", e); | ||
| 557 | + } | ||
| 558 | + } | ||
| 559 | + } | ||
| 560 | + | ||
| 561 | + private LinkAntiEntropyAdvertisement createAdvertisement() { | ||
| 562 | + final NodeId self = clusterService.getLocalNode().id(); | ||
| 563 | + | ||
| 564 | + Map<LinkFragmentId, Timestamp> linkTimestamps = new HashMap<>(linkDescs.size()); | ||
| 565 | + Map<LinkKey, Timestamp> linkTombstones = new HashMap<>(removedLinks.size()); | ||
| 566 | + | ||
| 567 | + for (Entry<LinkKey, ConcurrentMap<ProviderId, Timestamped<LinkDescription>>> | ||
| 568 | + provs : linkDescs.entrySet()) { | ||
| 569 | + | ||
| 570 | + final LinkKey linkKey = provs.getKey(); | ||
| 571 | + final ConcurrentMap<ProviderId, Timestamped<LinkDescription>> linkDesc = provs.getValue(); | ||
| 572 | + synchronized (linkDesc) { | ||
| 573 | + for (Map.Entry<ProviderId, Timestamped<LinkDescription>> e : linkDesc.entrySet()) { | ||
| 574 | + linkTimestamps.put(new LinkFragmentId(linkKey, e.getKey()), e.getValue().timestamp()); | ||
| 575 | + } | ||
| 576 | + } | ||
| 577 | + } | ||
| 578 | + | ||
| 579 | + linkTombstones.putAll(removedLinks); | ||
| 580 | + | ||
| 581 | + return new LinkAntiEntropyAdvertisement(self, linkTimestamps, linkTombstones); | ||
| 582 | + } | ||
| 583 | + | ||
| 584 | + private void handleAntiEntropyAdvertisement(LinkAntiEntropyAdvertisement advertisement) { | ||
| 585 | + | ||
| 586 | + NodeId peer = advertisement.sender(); | ||
| 587 | + | ||
| 588 | + Map<LinkFragmentId, Timestamp> linkTimestamps = advertisement.linkTimestamps(); | ||
| 589 | + Map<LinkKey, Timestamp> linkTombstones = advertisement.linkTombstones(); | ||
| 590 | + for (Map.Entry<LinkFragmentId, Timestamp> entry : linkTimestamps.entrySet()) { | ||
| 591 | + LinkFragmentId linkFragmentId = entry.getKey(); | ||
| 592 | + Timestamp peerTimestamp = entry.getValue(); | ||
| 593 | + | ||
| 594 | + LinkKey key = linkFragmentId.linkKey(); | ||
| 595 | + ProviderId providerId = linkFragmentId.providerId(); | ||
| 596 | + | ||
| 597 | + Timestamped<LinkDescription> linkDescription = getLinkDescription(key, providerId); | ||
| 598 | + if (linkDescription.isNewer(peerTimestamp)) { | ||
| 599 | + // I have more recent link description. update peer. | ||
| 600 | + notifyPeer(peer, new InternalLinkEvent(providerId, linkDescription)); | ||
| 601 | + } | ||
| 602 | + // else TODO: Peer has more recent link description. request it. | ||
| 603 | + | ||
| 604 | + Timestamp linkRemovedTimestamp = removedLinks.get(key); | ||
| 605 | + if (linkRemovedTimestamp != null && linkRemovedTimestamp.compareTo(peerTimestamp) > 0) { | ||
| 606 | + // peer has a zombie link. update peer. | ||
| 607 | + notifyPeer(peer, new InternalLinkRemovedEvent(key, linkRemovedTimestamp)); | ||
| 608 | + } | ||
| 609 | + } | ||
| 610 | + | ||
| 611 | + for (Map.Entry<LinkKey, Timestamp> entry : linkTombstones.entrySet()) { | ||
| 612 | + LinkKey key = entry.getKey(); | ||
| 613 | + Timestamp peerTimestamp = entry.getValue(); | ||
| 614 | + | ||
| 615 | + ProviderId primaryProviderId = pickPrimaryProviderId(getLinkDescriptions(key)); | ||
| 616 | + if (primaryProviderId != null) { | ||
| 617 | + if (!getLinkDescription(key, primaryProviderId).isNewer(peerTimestamp)) { | ||
| 618 | + notifyDelegateIfNotNull(removeLinkInternal(key, peerTimestamp)); | ||
| 619 | + } | ||
| 620 | + } | ||
| 621 | + } | ||
| 622 | + } | ||
| 623 | + | ||
| 624 | + private class InternalLinkEventListener implements ClusterMessageHandler { | ||
| 625 | + @Override | ||
| 626 | + public void handle(ClusterMessage message) { | ||
| 627 | + | ||
| 628 | + log.info("Received link event from peer: {}", message.sender()); | ||
| 629 | + InternalLinkEvent event = (InternalLinkEvent) SERIALIZER.decode(message.payload()); | ||
| 630 | + | ||
| 631 | + ProviderId providerId = event.providerId(); | ||
| 632 | + Timestamped<LinkDescription> linkDescription = event.linkDescription(); | ||
| 633 | + | ||
| 634 | + notifyDelegateIfNotNull(createOrUpdateLinkInternal(providerId, linkDescription)); | ||
| 635 | + } | ||
| 636 | + } | ||
| 637 | + | ||
| 638 | + private class InternalLinkRemovedEventListener implements ClusterMessageHandler { | ||
| 639 | + @Override | ||
| 640 | + public void handle(ClusterMessage message) { | ||
| 641 | + | ||
| 642 | + log.info("Received link removed event from peer: {}", message.sender()); | ||
| 643 | + InternalLinkRemovedEvent event = (InternalLinkRemovedEvent) SERIALIZER.decode(message.payload()); | ||
| 644 | + | ||
| 645 | + LinkKey linkKey = event.linkKey(); | ||
| 646 | + Timestamp timestamp = event.timestamp(); | ||
| 647 | + | ||
| 648 | + notifyDelegateIfNotNull(removeLinkInternal(linkKey, timestamp)); | ||
| 649 | + } | ||
| 650 | + } | ||
| 651 | + | ||
| 652 | + private final class InternalLinkAntiEntropyAdvertisementListener implements ClusterMessageHandler { | ||
| 653 | + | ||
| 654 | + @Override | ||
| 655 | + public void handle(ClusterMessage message) { | ||
| 656 | + log.info("Received Link Anti-Entropy advertisement from peer: {}", message.sender()); | ||
| 657 | + LinkAntiEntropyAdvertisement advertisement = SERIALIZER.decode(message.payload()); | ||
| 658 | + handleAntiEntropyAdvertisement(advertisement); | ||
| 659 | + } | ||
| 660 | + } | ||
| 661 | +} |
core/store/dist/src/main/java/org/onlab/onos/store/link/impl/GossipLinkStoreMessageSubjects.java
0 → 100644
| 1 | +package org.onlab.onos.store.link.impl; | ||
| 2 | + | ||
| 3 | +import org.onlab.onos.store.cluster.messaging.MessageSubject; | ||
| 4 | + | ||
| 5 | +/** | ||
| 6 | + * MessageSubjects used by GossipLinkStore peer-peer communication. | ||
| 7 | + */ | ||
| 8 | +public final class GossipLinkStoreMessageSubjects { | ||
| 9 | + | ||
| 10 | + private GossipLinkStoreMessageSubjects() {} | ||
| 11 | + | ||
| 12 | + public static final MessageSubject LINK_UPDATE = | ||
| 13 | + new MessageSubject("peer-link-update"); | ||
| 14 | + public static final MessageSubject LINK_REMOVED = | ||
| 15 | + new MessageSubject("peer-link-removed"); | ||
| 16 | + public static final MessageSubject LINK_ANTI_ENTROPY_ADVERTISEMENT = | ||
| 17 | + new MessageSubject("link-enti-entropy-advertisement"); | ||
| 18 | +} |
| 1 | +package org.onlab.onos.store.link.impl; | ||
| 2 | + | ||
| 3 | +import com.google.common.base.MoreObjects; | ||
| 4 | + | ||
| 5 | +import org.onlab.onos.net.link.LinkDescription; | ||
| 6 | +import org.onlab.onos.net.provider.ProviderId; | ||
| 7 | +import org.onlab.onos.store.common.impl.Timestamped; | ||
| 8 | + | ||
| 9 | +/** | ||
| 10 | + * Information published by GossipDeviceStore to notify peers of a device | ||
| 11 | + * change event. | ||
| 12 | + */ | ||
| 13 | +public class InternalLinkEvent { | ||
| 14 | + | ||
| 15 | + private final ProviderId providerId; | ||
| 16 | + private final Timestamped<LinkDescription> linkDescription; | ||
| 17 | + | ||
| 18 | + protected InternalLinkEvent( | ||
| 19 | + ProviderId providerId, | ||
| 20 | + Timestamped<LinkDescription> linkDescription) { | ||
| 21 | + this.providerId = providerId; | ||
| 22 | + this.linkDescription = linkDescription; | ||
| 23 | + } | ||
| 24 | + | ||
| 25 | + public ProviderId providerId() { | ||
| 26 | + return providerId; | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | + public Timestamped<LinkDescription> linkDescription() { | ||
| 30 | + return linkDescription; | ||
| 31 | + } | ||
| 32 | + | ||
| 33 | + @Override | ||
| 34 | + public String toString() { | ||
| 35 | + return MoreObjects.toStringHelper(getClass()) | ||
| 36 | + .add("providerId", providerId) | ||
| 37 | + .add("linkDescription", linkDescription) | ||
| 38 | + .toString(); | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + // for serializer | ||
| 42 | + protected InternalLinkEvent() { | ||
| 43 | + this.providerId = null; | ||
| 44 | + this.linkDescription = null; | ||
| 45 | + } | ||
| 46 | +} |
core/store/dist/src/main/java/org/onlab/onos/store/link/impl/InternalLinkRemovedEvent.java
0 → 100644
| 1 | +package org.onlab.onos.store.link.impl; | ||
| 2 | + | ||
| 3 | +import org.onlab.onos.net.LinkKey; | ||
| 4 | +import org.onlab.onos.store.Timestamp; | ||
| 5 | + | ||
| 6 | +import com.google.common.base.MoreObjects; | ||
| 7 | + | ||
| 8 | +/** | ||
| 9 | + * Information published by GossipLinkStore to notify peers of a link | ||
| 10 | + * being removed. | ||
| 11 | + */ | ||
| 12 | +public class InternalLinkRemovedEvent { | ||
| 13 | + | ||
| 14 | + private final LinkKey linkKey; | ||
| 15 | + private final Timestamp timestamp; | ||
| 16 | + | ||
| 17 | + /** | ||
| 18 | + * Creates a InternalLinkRemovedEvent. | ||
| 19 | + * @param linkKey identifier of the removed link. | ||
| 20 | + * @param timestamp timestamp of when the link was removed. | ||
| 21 | + */ | ||
| 22 | + public InternalLinkRemovedEvent(LinkKey linkKey, Timestamp timestamp) { | ||
| 23 | + this.linkKey = linkKey; | ||
| 24 | + this.timestamp = timestamp; | ||
| 25 | + } | ||
| 26 | + | ||
| 27 | + public LinkKey linkKey() { | ||
| 28 | + return linkKey; | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + public Timestamp timestamp() { | ||
| 32 | + return timestamp; | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + @Override | ||
| 36 | + public String toString() { | ||
| 37 | + return MoreObjects.toStringHelper(getClass()) | ||
| 38 | + .add("linkKey", linkKey) | ||
| 39 | + .add("timestamp", timestamp) | ||
| 40 | + .toString(); | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + // for serializer | ||
| 44 | + @SuppressWarnings("unused") | ||
| 45 | + private InternalLinkRemovedEvent() { | ||
| 46 | + linkKey = null; | ||
| 47 | + timestamp = null; | ||
| 48 | + } | ||
| 49 | +} | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
core/store/dist/src/main/java/org/onlab/onos/store/link/impl/LinkAntiEntropyAdvertisement.java
0 → 100644
| 1 | +package org.onlab.onos.store.link.impl; | ||
| 2 | + | ||
| 3 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
| 4 | + | ||
| 5 | +import java.util.Map; | ||
| 6 | + | ||
| 7 | +import org.onlab.onos.cluster.NodeId; | ||
| 8 | +import org.onlab.onos.net.LinkKey; | ||
| 9 | +import org.onlab.onos.store.Timestamp; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * Link AE Advertisement message. | ||
| 13 | + */ | ||
| 14 | +public class LinkAntiEntropyAdvertisement { | ||
| 15 | + | ||
| 16 | + private final NodeId sender; | ||
| 17 | + private final Map<LinkFragmentId, Timestamp> linkTimestamps; | ||
| 18 | + private final Map<LinkKey, Timestamp> linkTombstones; | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + public LinkAntiEntropyAdvertisement(NodeId sender, | ||
| 22 | + Map<LinkFragmentId, Timestamp> linkTimestamps, | ||
| 23 | + Map<LinkKey, Timestamp> linkTombstones) { | ||
| 24 | + this.sender = checkNotNull(sender); | ||
| 25 | + this.linkTimestamps = checkNotNull(linkTimestamps); | ||
| 26 | + this.linkTombstones = checkNotNull(linkTombstones); | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | + public NodeId sender() { | ||
| 30 | + return sender; | ||
| 31 | + } | ||
| 32 | + | ||
| 33 | + public Map<LinkFragmentId, Timestamp> linkTimestamps() { | ||
| 34 | + return linkTimestamps; | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + public Map<LinkKey, Timestamp> linkTombstones() { | ||
| 38 | + return linkTombstones; | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + // For serializer | ||
| 42 | + @SuppressWarnings("unused") | ||
| 43 | + private LinkAntiEntropyAdvertisement() { | ||
| 44 | + this.sender = null; | ||
| 45 | + this.linkTimestamps = null; | ||
| 46 | + this.linkTombstones = null; | ||
| 47 | + } | ||
| 48 | +} |
| 1 | +package org.onlab.onos.store.link.impl; | ||
| 2 | + | ||
| 3 | +import java.util.Objects; | ||
| 4 | + | ||
| 5 | +import org.onlab.onos.net.LinkKey; | ||
| 6 | +import org.onlab.onos.net.provider.ProviderId; | ||
| 7 | + | ||
| 8 | +import com.google.common.base.MoreObjects; | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * Identifier for LinkDescription from a Provider. | ||
| 12 | + */ | ||
| 13 | +public final class LinkFragmentId { | ||
| 14 | + public final ProviderId providerId; | ||
| 15 | + public final LinkKey linkKey; | ||
| 16 | + | ||
| 17 | + public LinkFragmentId(LinkKey linkKey, ProviderId providerId) { | ||
| 18 | + this.providerId = providerId; | ||
| 19 | + this.linkKey = linkKey; | ||
| 20 | + } | ||
| 21 | + | ||
| 22 | + public LinkKey linkKey() { | ||
| 23 | + return linkKey; | ||
| 24 | + } | ||
| 25 | + | ||
| 26 | + public ProviderId providerId() { | ||
| 27 | + return providerId; | ||
| 28 | + } | ||
| 29 | + | ||
| 30 | + @Override | ||
| 31 | + public int hashCode() { | ||
| 32 | + return Objects.hash(providerId, linkKey); | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + @Override | ||
| 36 | + public boolean equals(Object obj) { | ||
| 37 | + if (this == obj) { | ||
| 38 | + return true; | ||
| 39 | + } | ||
| 40 | + if (!(obj instanceof LinkFragmentId)) { | ||
| 41 | + return false; | ||
| 42 | + } | ||
| 43 | + LinkFragmentId that = (LinkFragmentId) obj; | ||
| 44 | + return Objects.equals(this.linkKey, that.linkKey) && | ||
| 45 | + Objects.equals(this.providerId, that.providerId); | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + @Override | ||
| 49 | + public String toString() { | ||
| 50 | + return MoreObjects.toStringHelper(getClass()) | ||
| 51 | + .add("providerId", providerId) | ||
| 52 | + .add("linkKey", linkKey) | ||
| 53 | + .toString(); | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + // for serializer | ||
| 57 | + @SuppressWarnings("unused") | ||
| 58 | + private LinkFragmentId() { | ||
| 59 | + this.providerId = null; | ||
| 60 | + this.linkKey = null; | ||
| 61 | + } | ||
| 62 | +} |
core/store/dist/src/main/java/org/onlab/onos/store/link/impl/OnosDistributedLinkStore.java
deleted
100644 → 0
| 1 | -package org.onlab.onos.store.link.impl; | ||
| 2 | - | ||
| 3 | -import static org.onlab.onos.net.Link.Type.DIRECT; | ||
| 4 | -import static org.onlab.onos.net.Link.Type.INDIRECT; | ||
| 5 | -import static org.onlab.onos.net.link.LinkEvent.Type.LINK_ADDED; | ||
| 6 | -import static org.onlab.onos.net.link.LinkEvent.Type.LINK_REMOVED; | ||
| 7 | -import static org.onlab.onos.net.link.LinkEvent.Type.LINK_UPDATED; | ||
| 8 | -import static org.slf4j.LoggerFactory.getLogger; | ||
| 9 | - | ||
| 10 | -import java.util.HashSet; | ||
| 11 | -import java.util.Set; | ||
| 12 | -import java.util.concurrent.ConcurrentHashMap; | ||
| 13 | -import java.util.concurrent.ConcurrentMap; | ||
| 14 | - | ||
| 15 | -import org.apache.felix.scr.annotations.Activate; | ||
| 16 | -import org.apache.felix.scr.annotations.Component; | ||
| 17 | -import org.apache.felix.scr.annotations.Deactivate; | ||
| 18 | -import org.apache.felix.scr.annotations.Reference; | ||
| 19 | -import org.apache.felix.scr.annotations.ReferenceCardinality; | ||
| 20 | -import org.apache.felix.scr.annotations.Service; | ||
| 21 | -import org.onlab.onos.net.ConnectPoint; | ||
| 22 | -import org.onlab.onos.net.DefaultLink; | ||
| 23 | -import org.onlab.onos.net.DeviceId; | ||
| 24 | -import org.onlab.onos.net.Link; | ||
| 25 | -import org.onlab.onos.net.LinkKey; | ||
| 26 | -import org.onlab.onos.net.link.LinkDescription; | ||
| 27 | -import org.onlab.onos.net.link.LinkEvent; | ||
| 28 | -import org.onlab.onos.net.link.LinkStore; | ||
| 29 | -import org.onlab.onos.net.link.LinkStoreDelegate; | ||
| 30 | -import org.onlab.onos.net.provider.ProviderId; | ||
| 31 | -import org.onlab.onos.store.AbstractStore; | ||
| 32 | -import org.onlab.onos.store.ClockService; | ||
| 33 | -import org.onlab.onos.store.Timestamp; | ||
| 34 | -import org.slf4j.Logger; | ||
| 35 | - | ||
| 36 | -import com.google.common.collect.HashMultimap; | ||
| 37 | -import com.google.common.collect.ImmutableSet; | ||
| 38 | -import com.google.common.collect.Multimap; | ||
| 39 | -import com.google.common.collect.ImmutableSet.Builder; | ||
| 40 | - | ||
| 41 | -import static com.google.common.base.Preconditions.checkArgument; | ||
| 42 | -import static com.google.common.base.Preconditions.checkState; | ||
| 43 | - | ||
| 44 | -//TODO: Add support for multiple provider and annotations | ||
| 45 | -/** | ||
| 46 | - * Manages inventory of infrastructure links using a protocol that takes into consideration | ||
| 47 | - * the order in which events occur. | ||
| 48 | - */ | ||
| 49 | -// FIXME: This does not yet implement the full protocol. | ||
| 50 | -// The full protocol requires the sender of LLDP message to include the | ||
| 51 | -// version information of src device/port and the receiver to | ||
| 52 | -// take that into account when figuring out if a more recent src | ||
| 53 | -// device/port down event renders the link discovery obsolete. | ||
| 54 | -@Component(immediate = true) | ||
| 55 | -@Service | ||
| 56 | -public class OnosDistributedLinkStore | ||
| 57 | - extends AbstractStore<LinkEvent, LinkStoreDelegate> | ||
| 58 | - implements LinkStore { | ||
| 59 | - | ||
| 60 | - private final Logger log = getLogger(getClass()); | ||
| 61 | - | ||
| 62 | - // Link inventory | ||
| 63 | - private ConcurrentMap<LinkKey, VersionedValue<Link>> links; | ||
| 64 | - | ||
| 65 | - public static final String LINK_NOT_FOUND = "Link between %s and %s not found"; | ||
| 66 | - | ||
| 67 | - // TODO synchronize? | ||
| 68 | - // Egress and ingress link sets | ||
| 69 | - private final Multimap<DeviceId, VersionedValue<Link>> srcLinks = HashMultimap.create(); | ||
| 70 | - private final Multimap<DeviceId, VersionedValue<Link>> dstLinks = HashMultimap.create(); | ||
| 71 | - | ||
| 72 | - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
| 73 | - protected ClockService clockService; | ||
| 74 | - | ||
| 75 | - @Activate | ||
| 76 | - public void activate() { | ||
| 77 | - | ||
| 78 | - links = new ConcurrentHashMap<>(); | ||
| 79 | - | ||
| 80 | - log.info("Started"); | ||
| 81 | - } | ||
| 82 | - | ||
| 83 | - @Deactivate | ||
| 84 | - public void deactivate() { | ||
| 85 | - log.info("Stopped"); | ||
| 86 | - } | ||
| 87 | - | ||
| 88 | - @Override | ||
| 89 | - public int getLinkCount() { | ||
| 90 | - return links.size(); | ||
| 91 | - } | ||
| 92 | - | ||
| 93 | - @Override | ||
| 94 | - public Iterable<Link> getLinks() { | ||
| 95 | - Builder<Link> builder = ImmutableSet.builder(); | ||
| 96 | - synchronized (this) { | ||
| 97 | - for (VersionedValue<Link> link : links.values()) { | ||
| 98 | - builder.add(link.entity()); | ||
| 99 | - } | ||
| 100 | - return builder.build(); | ||
| 101 | - } | ||
| 102 | - } | ||
| 103 | - | ||
| 104 | - @Override | ||
| 105 | - public Set<Link> getDeviceEgressLinks(DeviceId deviceId) { | ||
| 106 | - Set<VersionedValue<Link>> egressLinks = ImmutableSet.copyOf(srcLinks.get(deviceId)); | ||
| 107 | - Set<Link> rawEgressLinks = new HashSet<>(); | ||
| 108 | - for (VersionedValue<Link> link : egressLinks) { | ||
| 109 | - rawEgressLinks.add(link.entity()); | ||
| 110 | - } | ||
| 111 | - return rawEgressLinks; | ||
| 112 | - } | ||
| 113 | - | ||
| 114 | - @Override | ||
| 115 | - public Set<Link> getDeviceIngressLinks(DeviceId deviceId) { | ||
| 116 | - Set<VersionedValue<Link>> ingressLinks = ImmutableSet.copyOf(dstLinks.get(deviceId)); | ||
| 117 | - Set<Link> rawIngressLinks = new HashSet<>(); | ||
| 118 | - for (VersionedValue<Link> link : ingressLinks) { | ||
| 119 | - rawIngressLinks.add(link.entity()); | ||
| 120 | - } | ||
| 121 | - return rawIngressLinks; | ||
| 122 | - } | ||
| 123 | - | ||
| 124 | - @Override | ||
| 125 | - public Link getLink(ConnectPoint src, ConnectPoint dst) { | ||
| 126 | - VersionedValue<Link> link = links.get(new LinkKey(src, dst)); | ||
| 127 | - checkArgument(link != null, "LINK_NOT_FOUND", src, dst); | ||
| 128 | - return link.entity(); | ||
| 129 | - } | ||
| 130 | - | ||
| 131 | - @Override | ||
| 132 | - public Set<Link> getEgressLinks(ConnectPoint src) { | ||
| 133 | - Set<Link> egressLinks = new HashSet<>(); | ||
| 134 | - for (VersionedValue<Link> link : srcLinks.get(src.deviceId())) { | ||
| 135 | - if (link.entity().src().equals(src)) { | ||
| 136 | - egressLinks.add(link.entity()); | ||
| 137 | - } | ||
| 138 | - } | ||
| 139 | - return egressLinks; | ||
| 140 | - } | ||
| 141 | - | ||
| 142 | - @Override | ||
| 143 | - public Set<Link> getIngressLinks(ConnectPoint dst) { | ||
| 144 | - Set<Link> ingressLinks = new HashSet<>(); | ||
| 145 | - for (VersionedValue<Link> link : dstLinks.get(dst.deviceId())) { | ||
| 146 | - if (link.entity().dst().equals(dst)) { | ||
| 147 | - ingressLinks.add(link.entity()); | ||
| 148 | - } | ||
| 149 | - } | ||
| 150 | - return ingressLinks; | ||
| 151 | - } | ||
| 152 | - | ||
| 153 | - @Override | ||
| 154 | - public LinkEvent createOrUpdateLink(ProviderId providerId, | ||
| 155 | - LinkDescription linkDescription) { | ||
| 156 | - | ||
| 157 | - final DeviceId destinationDeviceId = linkDescription.dst().deviceId(); | ||
| 158 | - final Timestamp newTimestamp = clockService.getTimestamp(destinationDeviceId); | ||
| 159 | - | ||
| 160 | - LinkKey key = new LinkKey(linkDescription.src(), linkDescription.dst()); | ||
| 161 | - VersionedValue<Link> link = links.get(key); | ||
| 162 | - if (link == null) { | ||
| 163 | - return createLink(providerId, key, linkDescription, newTimestamp); | ||
| 164 | - } | ||
| 165 | - | ||
| 166 | - checkState(newTimestamp.compareTo(link.timestamp()) > 0, | ||
| 167 | - "Existing Link has a timestamp in the future!"); | ||
| 168 | - | ||
| 169 | - return updateLink(providerId, link, key, linkDescription, newTimestamp); | ||
| 170 | - } | ||
| 171 | - | ||
| 172 | - // Creates and stores the link and returns the appropriate event. | ||
| 173 | - private LinkEvent createLink(ProviderId providerId, LinkKey key, | ||
| 174 | - LinkDescription linkDescription, Timestamp timestamp) { | ||
| 175 | - VersionedValue<Link> link = new VersionedValue<Link>(new DefaultLink(providerId, key.src(), key.dst(), | ||
| 176 | - linkDescription.type()), true, timestamp); | ||
| 177 | - synchronized (this) { | ||
| 178 | - links.put(key, link); | ||
| 179 | - addNewLink(link, timestamp); | ||
| 180 | - } | ||
| 181 | - // FIXME: notify peers. | ||
| 182 | - return new LinkEvent(LINK_ADDED, link.entity()); | ||
| 183 | - } | ||
| 184 | - | ||
| 185 | - // update Egress and ingress link sets | ||
| 186 | - private void addNewLink(VersionedValue<Link> link, Timestamp timestamp) { | ||
| 187 | - Link rawLink = link.entity(); | ||
| 188 | - synchronized (this) { | ||
| 189 | - srcLinks.put(rawLink.src().deviceId(), link); | ||
| 190 | - dstLinks.put(rawLink.dst().deviceId(), link); | ||
| 191 | - } | ||
| 192 | - } | ||
| 193 | - | ||
| 194 | - // Updates, if necessary the specified link and returns the appropriate event. | ||
| 195 | - private LinkEvent updateLink(ProviderId providerId, VersionedValue<Link> existingLink, | ||
| 196 | - LinkKey key, LinkDescription linkDescription, Timestamp timestamp) { | ||
| 197 | - // FIXME confirm Link update condition is OK | ||
| 198 | - if (existingLink.entity().type() == INDIRECT && linkDescription.type() == DIRECT) { | ||
| 199 | - synchronized (this) { | ||
| 200 | - | ||
| 201 | - VersionedValue<Link> updatedLink = new VersionedValue<Link>( | ||
| 202 | - new DefaultLink(providerId, existingLink.entity().src(), existingLink.entity().dst(), | ||
| 203 | - linkDescription.type()), true, timestamp); | ||
| 204 | - links.replace(key, existingLink, updatedLink); | ||
| 205 | - | ||
| 206 | - replaceLink(existingLink, updatedLink); | ||
| 207 | - // FIXME: notify peers. | ||
| 208 | - return new LinkEvent(LINK_UPDATED, updatedLink.entity()); | ||
| 209 | - } | ||
| 210 | - } | ||
| 211 | - return null; | ||
| 212 | - } | ||
| 213 | - | ||
| 214 | - // update Egress and ingress link sets | ||
| 215 | - private void replaceLink(VersionedValue<Link> current, VersionedValue<Link> updated) { | ||
| 216 | - synchronized (this) { | ||
| 217 | - srcLinks.remove(current.entity().src().deviceId(), current); | ||
| 218 | - dstLinks.remove(current.entity().dst().deviceId(), current); | ||
| 219 | - | ||
| 220 | - srcLinks.put(current.entity().src().deviceId(), updated); | ||
| 221 | - dstLinks.put(current.entity().dst().deviceId(), updated); | ||
| 222 | - } | ||
| 223 | - } | ||
| 224 | - | ||
| 225 | - @Override | ||
| 226 | - public LinkEvent removeLink(ConnectPoint src, ConnectPoint dst) { | ||
| 227 | - synchronized (this) { | ||
| 228 | - LinkKey key = new LinkKey(src, dst); | ||
| 229 | - VersionedValue<Link> link = links.remove(key); | ||
| 230 | - if (link != null) { | ||
| 231 | - removeLink(link); | ||
| 232 | - // notify peers | ||
| 233 | - return new LinkEvent(LINK_REMOVED, link.entity()); | ||
| 234 | - } | ||
| 235 | - return null; | ||
| 236 | - } | ||
| 237 | - } | ||
| 238 | - | ||
| 239 | - // update Egress and ingress link sets | ||
| 240 | - private void removeLink(VersionedValue<Link> link) { | ||
| 241 | - synchronized (this) { | ||
| 242 | - srcLinks.remove(link.entity().src().deviceId(), link); | ||
| 243 | - dstLinks.remove(link.entity().dst().deviceId(), link); | ||
| 244 | - } | ||
| 245 | - } | ||
| 246 | -} |
| 1 | -package org.onlab.onos.store.link.impl; | ||
| 2 | - | ||
| 3 | -import java.util.Objects; | ||
| 4 | - | ||
| 5 | -import org.onlab.onos.store.Timestamp; | ||
| 6 | - | ||
| 7 | -// TODO: remove once we stop using this | ||
| 8 | -/** | ||
| 9 | - * Wrapper class for a entity that is versioned | ||
| 10 | - * and can either be up or down. | ||
| 11 | - * | ||
| 12 | - * @param <T> type of the value. | ||
| 13 | - */ | ||
| 14 | -public class VersionedValue<T> { | ||
| 15 | - private final T entity; | ||
| 16 | - private final Timestamp timestamp; | ||
| 17 | - private final boolean isUp; | ||
| 18 | - | ||
| 19 | - public VersionedValue(T entity, boolean isUp, Timestamp timestamp) { | ||
| 20 | - this.entity = entity; | ||
| 21 | - this.isUp = isUp; | ||
| 22 | - this.timestamp = timestamp; | ||
| 23 | - } | ||
| 24 | - | ||
| 25 | - /** | ||
| 26 | - * Returns the value. | ||
| 27 | - * @return value. | ||
| 28 | - */ | ||
| 29 | - public T entity() { | ||
| 30 | - return entity; | ||
| 31 | - } | ||
| 32 | - | ||
| 33 | - /** | ||
| 34 | - * Tells whether the entity is up or down. | ||
| 35 | - * @return true if up, false otherwise. | ||
| 36 | - */ | ||
| 37 | - public boolean isUp() { | ||
| 38 | - return isUp; | ||
| 39 | - } | ||
| 40 | - | ||
| 41 | - /** | ||
| 42 | - * Returns the timestamp (version) associated with this entity. | ||
| 43 | - * @return timestamp. | ||
| 44 | - */ | ||
| 45 | - public Timestamp timestamp() { | ||
| 46 | - return timestamp; | ||
| 47 | - } | ||
| 48 | - | ||
| 49 | - | ||
| 50 | - @Override | ||
| 51 | - public int hashCode() { | ||
| 52 | - return Objects.hash(entity, timestamp, isUp); | ||
| 53 | - } | ||
| 54 | - | ||
| 55 | - @Override | ||
| 56 | - public boolean equals(Object obj) { | ||
| 57 | - if (this == obj) { | ||
| 58 | - return true; | ||
| 59 | - } | ||
| 60 | - if (obj == null) { | ||
| 61 | - return false; | ||
| 62 | - } | ||
| 63 | - if (getClass() != obj.getClass()) { | ||
| 64 | - return false; | ||
| 65 | - } | ||
| 66 | - @SuppressWarnings("unchecked") | ||
| 67 | - VersionedValue<T> that = (VersionedValue<T>) obj; | ||
| 68 | - return Objects.equals(this.entity, that.entity) && | ||
| 69 | - Objects.equals(this.timestamp, that.timestamp) && | ||
| 70 | - Objects.equals(this.isUp, that.isUp); | ||
| 71 | - } | ||
| 72 | - | ||
| 73 | - // Default constructor for serializer | ||
| 74 | - protected VersionedValue() { | ||
| 75 | - this.entity = null; | ||
| 76 | - this.isUp = false; | ||
| 77 | - this.timestamp = null; | ||
| 78 | - } | ||
| 79 | -} |
core/store/dist/src/test/java/org/onlab/onos/store/device/impl/peermsg/DeviceFragmentIdTest.java
0 → 100644
| 1 | +package org.onlab.onos.store.device.impl.peermsg; | ||
| 2 | + | ||
| 3 | +import static org.onlab.onos.net.DeviceId.deviceId; | ||
| 4 | + | ||
| 5 | +import org.junit.Test; | ||
| 6 | +import org.onlab.onos.net.DeviceId; | ||
| 7 | +import org.onlab.onos.net.provider.ProviderId; | ||
| 8 | + | ||
| 9 | +import com.google.common.testing.EqualsTester; | ||
| 10 | + | ||
| 11 | +public class DeviceFragmentIdTest { | ||
| 12 | + | ||
| 13 | + private static final ProviderId PID = new ProviderId("of", "foo"); | ||
| 14 | + private static final ProviderId PIDA = new ProviderId("of", "bar", true); | ||
| 15 | + private static final DeviceId DID1 = deviceId("of:foo"); | ||
| 16 | + private static final DeviceId DID2 = deviceId("of:bar"); | ||
| 17 | + | ||
| 18 | + @Test | ||
| 19 | + public final void testEquals() { | ||
| 20 | + | ||
| 21 | + new EqualsTester() | ||
| 22 | + .addEqualityGroup(new DeviceFragmentId(DID1, PID), | ||
| 23 | + new DeviceFragmentId(DID1, PID)) | ||
| 24 | + .addEqualityGroup(new DeviceFragmentId(DID2, PID), | ||
| 25 | + new DeviceFragmentId(DID2, PID)) | ||
| 26 | + .addEqualityGroup(new DeviceFragmentId(DID1, PIDA), | ||
| 27 | + new DeviceFragmentId(DID1, PIDA)) | ||
| 28 | + .addEqualityGroup(new DeviceFragmentId(DID2, PIDA), | ||
| 29 | + new DeviceFragmentId(DID2, PIDA)) | ||
| 30 | + .testEquals(); | ||
| 31 | + } | ||
| 32 | + | ||
| 33 | +} |
core/store/dist/src/test/java/org/onlab/onos/store/device/impl/peermsg/PortFragmentIdTest.java
0 → 100644
| 1 | +package org.onlab.onos.store.device.impl.peermsg; | ||
| 2 | + | ||
| 3 | +import static org.onlab.onos.net.DeviceId.deviceId; | ||
| 4 | + | ||
| 5 | +import org.junit.Test; | ||
| 6 | +import org.onlab.onos.net.DeviceId; | ||
| 7 | +import org.onlab.onos.net.PortNumber; | ||
| 8 | +import org.onlab.onos.net.provider.ProviderId; | ||
| 9 | + | ||
| 10 | +import com.google.common.testing.EqualsTester; | ||
| 11 | + | ||
| 12 | +public class PortFragmentIdTest { | ||
| 13 | + | ||
| 14 | + private static final ProviderId PID = new ProviderId("of", "foo"); | ||
| 15 | + private static final ProviderId PIDA = new ProviderId("of", "bar", true); | ||
| 16 | + | ||
| 17 | + private static final DeviceId DID1 = deviceId("of:foo"); | ||
| 18 | + private static final DeviceId DID2 = deviceId("of:bar"); | ||
| 19 | + | ||
| 20 | + private static final PortNumber PN1 = PortNumber.portNumber(1); | ||
| 21 | + private static final PortNumber PN2 = PortNumber.portNumber(2); | ||
| 22 | + | ||
| 23 | + @Test | ||
| 24 | + public final void testEquals() { | ||
| 25 | + new EqualsTester() | ||
| 26 | + .addEqualityGroup(new PortFragmentId(DID1, PID, PN1), | ||
| 27 | + new PortFragmentId(DID1, PID, PN1)) | ||
| 28 | + .addEqualityGroup(new PortFragmentId(DID2, PID, PN1), | ||
| 29 | + new PortFragmentId(DID2, PID, PN1)) | ||
| 30 | + .addEqualityGroup(new PortFragmentId(DID1, PIDA, PN1), | ||
| 31 | + new PortFragmentId(DID1, PIDA, PN1)) | ||
| 32 | + .addEqualityGroup(new PortFragmentId(DID2, PIDA, PN1), | ||
| 33 | + new PortFragmentId(DID2, PIDA, PN1)) | ||
| 34 | + | ||
| 35 | + .addEqualityGroup(new PortFragmentId(DID1, PID, PN2), | ||
| 36 | + new PortFragmentId(DID1, PID, PN2)) | ||
| 37 | + .addEqualityGroup(new PortFragmentId(DID2, PID, PN2), | ||
| 38 | + new PortFragmentId(DID2, PID, PN2)) | ||
| 39 | + .addEqualityGroup(new PortFragmentId(DID1, PIDA, PN2), | ||
| 40 | + new PortFragmentId(DID1, PIDA, PN2)) | ||
| 41 | + .addEqualityGroup(new PortFragmentId(DID2, PIDA, PN2), | ||
| 42 | + new PortFragmentId(DID2, PIDA, PN2)) | ||
| 43 | + .testEquals(); | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | +} |
| ... | @@ -46,10 +46,6 @@ | ... | @@ -46,10 +46,6 @@ |
| 46 | <groupId>com.hazelcast</groupId> | 46 | <groupId>com.hazelcast</groupId> |
| 47 | <artifactId>hazelcast</artifactId> | 47 | <artifactId>hazelcast</artifactId> |
| 48 | </dependency> | 48 | </dependency> |
| 49 | - <dependency> | ||
| 50 | - <groupId>de.javakaffee</groupId> | ||
| 51 | - <artifactId>kryo-serializers</artifactId> | ||
| 52 | - </dependency> | ||
| 53 | </dependencies> | 49 | </dependencies> |
| 54 | 50 | ||
| 55 | <build> | 51 | <build> | ... | ... |
| ... | @@ -35,8 +35,8 @@ | ... | @@ -35,8 +35,8 @@ |
| 35 | <artifactId>hazelcast</artifactId> | 35 | <artifactId>hazelcast</artifactId> |
| 36 | </dependency> | 36 | </dependency> |
| 37 | <dependency> | 37 | <dependency> |
| 38 | - <groupId>de.javakaffee</groupId> | 38 | + <groupId>org.apache.commons</groupId> |
| 39 | - <artifactId>kryo-serializers</artifactId> | 39 | + <artifactId>commons-lang3</artifactId> |
| 40 | </dependency> | 40 | </dependency> |
| 41 | </dependencies> | 41 | </dependencies> |
| 42 | 42 | ... | ... |
| ... | @@ -23,11 +23,6 @@ | ... | @@ -23,11 +23,6 @@ |
| 23 | </dependency> | 23 | </dependency> |
| 24 | <dependency> | 24 | <dependency> |
| 25 | <groupId>org.onlab.onos</groupId> | 25 | <groupId>org.onlab.onos</groupId> |
| 26 | - <artifactId>onos-core-serializers</artifactId> | ||
| 27 | - <version>${project.version}</version> | ||
| 28 | - </dependency> | ||
| 29 | - <dependency> | ||
| 30 | - <groupId>org.onlab.onos</groupId> | ||
| 31 | <artifactId>onos-core-hz-common</artifactId> | 26 | <artifactId>onos-core-hz-common</artifactId> |
| 32 | <version>${project.version}</version> | 27 | <version>${project.version}</version> |
| 33 | </dependency> | 28 | </dependency> |
| ... | @@ -46,10 +41,6 @@ | ... | @@ -46,10 +41,6 @@ |
| 46 | <groupId>com.hazelcast</groupId> | 41 | <groupId>com.hazelcast</groupId> |
| 47 | <artifactId>hazelcast</artifactId> | 42 | <artifactId>hazelcast</artifactId> |
| 48 | </dependency> | 43 | </dependency> |
| 49 | - <dependency> | ||
| 50 | - <groupId>de.javakaffee</groupId> | ||
| 51 | - <artifactId>kryo-serializers</artifactId> | ||
| 52 | - </dependency> | ||
| 53 | </dependencies> | 44 | </dependencies> |
| 54 | 45 | ||
| 55 | <build> | 46 | <build> | ... | ... |
| ... | @@ -26,8 +26,13 @@ | ... | @@ -26,8 +26,13 @@ |
| 26 | <artifactId>org.apache.felix.scr.annotations</artifactId> | 26 | <artifactId>org.apache.felix.scr.annotations</artifactId> |
| 27 | </dependency> | 27 | </dependency> |
| 28 | <dependency> | 28 | <dependency> |
| 29 | - <groupId>de.javakaffee</groupId> | 29 | + <groupId>com.esotericsoftware</groupId> |
| 30 | - <artifactId>kryo-serializers</artifactId> | 30 | + <artifactId>kryo</artifactId> |
| 31 | + </dependency> | ||
| 32 | + <dependency> | ||
| 33 | + <groupId>com.google.guava</groupId> | ||
| 34 | + <artifactId>guava-testlib</artifactId> | ||
| 35 | + <scope>test</scope> | ||
| 31 | </dependency> | 36 | </dependency> |
| 32 | </dependencies> | 37 | </dependencies> |
| 33 | 38 | ... | ... |
| ... | @@ -24,14 +24,13 @@ import org.onlab.onos.net.Port; | ... | @@ -24,14 +24,13 @@ import org.onlab.onos.net.Port; |
| 24 | import org.onlab.onos.net.PortNumber; | 24 | import org.onlab.onos.net.PortNumber; |
| 25 | import org.onlab.onos.net.device.DefaultDeviceDescription; | 25 | import org.onlab.onos.net.device.DefaultDeviceDescription; |
| 26 | import org.onlab.onos.net.device.DefaultPortDescription; | 26 | import org.onlab.onos.net.device.DefaultPortDescription; |
| 27 | +import org.onlab.onos.net.link.DefaultLinkDescription; | ||
| 27 | import org.onlab.onos.net.provider.ProviderId; | 28 | import org.onlab.onos.net.provider.ProviderId; |
| 28 | import org.onlab.onos.store.Timestamp; | 29 | import org.onlab.onos.store.Timestamp; |
| 29 | import org.onlab.packet.IpAddress; | 30 | import org.onlab.packet.IpAddress; |
| 30 | import org.onlab.packet.IpPrefix; | 31 | import org.onlab.packet.IpPrefix; |
| 31 | import org.onlab.util.KryoPool; | 32 | import org.onlab.util.KryoPool; |
| 32 | 33 | ||
| 33 | -import de.javakaffee.kryoserializers.URISerializer; | ||
| 34 | - | ||
| 35 | public final class KryoPoolUtil { | 34 | public final class KryoPoolUtil { |
| 36 | 35 | ||
| 37 | /** | 36 | /** |
| ... | @@ -60,6 +59,7 @@ public final class KryoPoolUtil { | ... | @@ -60,6 +59,7 @@ public final class KryoPoolUtil { |
| 60 | DefaultControllerNode.class, | 59 | DefaultControllerNode.class, |
| 61 | DefaultDevice.class, | 60 | DefaultDevice.class, |
| 62 | DefaultDeviceDescription.class, | 61 | DefaultDeviceDescription.class, |
| 62 | + DefaultLinkDescription.class, | ||
| 63 | MastershipRole.class, | 63 | MastershipRole.class, |
| 64 | Port.class, | 64 | Port.class, |
| 65 | DefaultPortDescription.class, | 65 | DefaultPortDescription.class, | ... | ... |
| 1 | +package org.onlab.onos.store.serializers; | ||
| 2 | + | ||
| 3 | +import java.net.URI; | ||
| 4 | + | ||
| 5 | +import com.esotericsoftware.kryo.Kryo; | ||
| 6 | +import com.esotericsoftware.kryo.Serializer; | ||
| 7 | +import com.esotericsoftware.kryo.io.Input; | ||
| 8 | +import com.esotericsoftware.kryo.io.Output; | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * Serializer for {@link URI}. | ||
| 12 | + */ | ||
| 13 | +public class URISerializer extends Serializer<URI> { | ||
| 14 | + | ||
| 15 | + /** | ||
| 16 | + * Creates {@link URI} serializer instance. | ||
| 17 | + */ | ||
| 18 | + public URISerializer() { | ||
| 19 | + super(false); | ||
| 20 | + } | ||
| 21 | + | ||
| 22 | + @Override | ||
| 23 | + public void write(Kryo kryo, Output output, URI object) { | ||
| 24 | + output.writeString(object.toString()); | ||
| 25 | + } | ||
| 26 | + | ||
| 27 | + @Override | ||
| 28 | + public URI read(Kryo kryo, Input input, Class<URI> type) { | ||
| 29 | + return URI.create(input.readString()); | ||
| 30 | + } | ||
| 31 | +} |
| ... | @@ -20,10 +20,11 @@ | ... | @@ -20,10 +20,11 @@ |
| 20 | <bundle>mvn:io.dropwizard.metrics/metrics-core/3.1.0</bundle> | 20 | <bundle>mvn:io.dropwizard.metrics/metrics-core/3.1.0</bundle> |
| 21 | <bundle>mvn:com.eclipsesource.minimal-json/minimal-json/0.9.1</bundle> | 21 | <bundle>mvn:com.eclipsesource.minimal-json/minimal-json/0.9.1</bundle> |
| 22 | 22 | ||
| 23 | - <bundle>mvn:com.esotericsoftware.kryo/kryo/2.24.0</bundle> | 23 | + <bundle>mvn:com.esotericsoftware/kryo/3.0.0</bundle> |
| 24 | + <bundle>mvn:com.esotericsoftware/reflectasm/1.10.0</bundle> | ||
| 25 | + <bundle>mvn:org.ow2.asm/asm/4.2</bundle> | ||
| 24 | <bundle>mvn:com.esotericsoftware/minlog/1.3.0</bundle> | 26 | <bundle>mvn:com.esotericsoftware/minlog/1.3.0</bundle> |
| 25 | <bundle>mvn:org.objenesis/objenesis/2.1</bundle> | 27 | <bundle>mvn:org.objenesis/objenesis/2.1</bundle> |
| 26 | - <bundle>mvn:de.javakaffee/kryo-serializers/0.27</bundle> | ||
| 27 | 28 | ||
| 28 | <bundle>mvn:org.onlab.onos/onlab-nio/1.0.0-SNAPSHOT</bundle> | 29 | <bundle>mvn:org.onlab.onos/onlab-nio/1.0.0-SNAPSHOT</bundle> |
| 29 | 30 | ... | ... |
| ... | @@ -193,9 +193,20 @@ | ... | @@ -193,9 +193,20 @@ |
| 193 | <version>0.9.1</version> | 193 | <version>0.9.1</version> |
| 194 | </dependency> | 194 | </dependency> |
| 195 | <dependency> | 195 | <dependency> |
| 196 | - <groupId>com.esotericsoftware.kryo</groupId> | 196 | + <groupId>com.esotericsoftware</groupId> |
| 197 | - <artifactId>kryo</artifactId> | 197 | + <artifactId>kryo</artifactId> |
| 198 | - <version>2.24.0</version> | 198 | + <version>3.0.0</version> |
| 199 | + </dependency> | ||
| 200 | + <dependency> | ||
| 201 | + <groupId>com.esotericsoftware</groupId> | ||
| 202 | + <artifactId>reflectasm</artifactId> | ||
| 203 | + <version>1.10.0</version> | ||
| 204 | + <type>bundle</type> | ||
| 205 | + </dependency> | ||
| 206 | + <dependency> | ||
| 207 | + <groupId>org.ow2.asm</groupId> | ||
| 208 | + <artifactId>asm</artifactId> | ||
| 209 | + <version>4.2</version> | ||
| 199 | </dependency> | 210 | </dependency> |
| 200 | <dependency> | 211 | <dependency> |
| 201 | <groupId>com.esotericsoftware</groupId> | 212 | <groupId>com.esotericsoftware</groupId> |
| ... | @@ -207,11 +218,6 @@ | ... | @@ -207,11 +218,6 @@ |
| 207 | <artifactId>objenesis</artifactId> | 218 | <artifactId>objenesis</artifactId> |
| 208 | <version>2.1</version> | 219 | <version>2.1</version> |
| 209 | </dependency> | 220 | </dependency> |
| 210 | - <dependency> | ||
| 211 | - <groupId>de.javakaffee</groupId> | ||
| 212 | - <artifactId>kryo-serializers</artifactId> | ||
| 213 | - <version>0.27</version> | ||
| 214 | - </dependency> | ||
| 215 | 221 | ||
| 216 | <!-- ONOS related --> | 222 | <!-- ONOS related --> |
| 217 | <dependency> | 223 | <dependency> |
| ... | @@ -284,6 +290,10 @@ | ... | @@ -284,6 +290,10 @@ |
| 284 | </dependency> | 290 | </dependency> |
| 285 | <dependency> | 291 | <dependency> |
| 286 | <groupId>org.slf4j</groupId> | 292 | <groupId>org.slf4j</groupId> |
| 293 | + <artifactId>slf4j-api</artifactId> | ||
| 294 | + </dependency> | ||
| 295 | + <dependency> | ||
| 296 | + <groupId>org.slf4j</groupId> | ||
| 287 | <artifactId>slf4j-jdk14</artifactId> | 297 | <artifactId>slf4j-jdk14</artifactId> |
| 288 | </dependency> | 298 | </dependency> |
| 289 | </dependencies> | 299 | </dependencies> |
| ... | @@ -434,9 +444,6 @@ | ... | @@ -434,9 +444,6 @@ |
| 434 | <version>3.2</version> | 444 | <version>3.2</version> |
| 435 | <configuration> | 445 | <configuration> |
| 436 | <excludes> | 446 | <excludes> |
| 437 | - <exclude>**/datastore/serializers/**</exclude> | ||
| 438 | - <exclude>**/edu/stanford/**</exclude> | ||
| 439 | - <exclude>**/net/floodlightcontroller/**</exclude> | ||
| 440 | </excludes> | 447 | </excludes> |
| 441 | <rulesets> | 448 | <rulesets> |
| 442 | <ruleset>onos/pmd.xml</ruleset> | 449 | <ruleset>onos/pmd.xml</ruleset> |
| ... | @@ -545,9 +552,6 @@ | ... | @@ -545,9 +552,6 @@ |
| 545 | <version>3.2</version> | 552 | <version>3.2</version> |
| 546 | <configuration> | 553 | <configuration> |
| 547 | <excludes> | 554 | <excludes> |
| 548 | - <exclude>**/datastore/serializers/**</exclude> | ||
| 549 | - <exclude>**/edu/stanford/**</exclude> | ||
| 550 | - <exclude>**/net/floodlightcontroller/**</exclude> | ||
| 551 | </excludes> | 555 | </excludes> |
| 552 | <rulesets> | 556 | <rulesets> |
| 553 | <ruleset>onos/pmd.xml</ruleset> | 557 | <ruleset>onos/pmd.xml</ruleset> | ... | ... |
| 1 | +#!/bin/bash | ||
| 1 | #------------------------------------------------------------------------------ | 2 | #------------------------------------------------------------------------------ |
| 2 | # Echoes project-level directory if a Java file within is newer than the | 3 | # Echoes project-level directory if a Java file within is newer than the |
| 3 | # target directory. | 4 | # target directory. | ... | ... |
| ... | @@ -44,18 +44,10 @@ | ... | @@ -44,18 +44,10 @@ |
| 44 | <artifactId>minimal-json</artifactId> | 44 | <artifactId>minimal-json</artifactId> |
| 45 | </dependency> | 45 | </dependency> |
| 46 | <dependency> | 46 | <dependency> |
| 47 | - <groupId>com.esotericsoftware.kryo</groupId> | 47 | + <groupId>com.esotericsoftware</groupId> |
| 48 | <artifactId>kryo</artifactId> | 48 | <artifactId>kryo</artifactId> |
| 49 | </dependency> | 49 | </dependency> |
| 50 | <dependency> | 50 | <dependency> |
| 51 | - <groupId>com.esotericsoftware</groupId> | ||
| 52 | - <artifactId>minlog</artifactId> | ||
| 53 | - </dependency> | ||
| 54 | - <dependency> | ||
| 55 | - <groupId>org.objenesis</groupId> | ||
| 56 | - <artifactId>objenesis</artifactId> | ||
| 57 | - </dependency> | ||
| 58 | - <dependency> | ||
| 59 | <groupId>io.dropwizard.metrics</groupId> | 51 | <groupId>io.dropwizard.metrics</groupId> |
| 60 | <artifactId>metrics-core</artifactId> | 52 | <artifactId>metrics-core</artifactId> |
| 61 | <version>3.1.0</version> | 53 | <version>3.1.0</version> | ... | ... |
| ... | @@ -32,10 +32,6 @@ | ... | @@ -32,10 +32,6 @@ |
| 32 | <scope>test</scope> | 32 | <scope>test</scope> |
| 33 | </dependency> | 33 | </dependency> |
| 34 | <dependency> | 34 | <dependency> |
| 35 | - <groupId>de.javakaffee</groupId> | ||
| 36 | - <artifactId>kryo-serializers</artifactId> | ||
| 37 | - </dependency> | ||
| 38 | - <dependency> | ||
| 39 | <groupId>io.netty</groupId> | 35 | <groupId>io.netty</groupId> |
| 40 | <artifactId>netty-all</artifactId> | 36 | <artifactId>netty-all</artifactId> |
| 41 | </dependency> | 37 | </dependency> | ... | ... |
-
Please register or login to post a comment