tom

Merge remote-tracking branch 'origin/master'

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>
......
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 +/**
2 + * SDN-IP peering application.
3 + */
4 +package org.onlab.onos.sdnip;
...\ No newline at end of file ...\ No newline at end of file
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 +}
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 +}
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
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 +}
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 -}
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 +}
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>
......