Ayaka Koshibe

Merge branch 'master' of ssh://gerrit.onlab.us:29418/onos-next

Showing 147 changed files with 4928 additions and 1541 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,48 +52,87 @@ private static Logger log = LoggerFactory.getLogger(SimpleNettyClient.class); ...@@ -34,48 +52,87 @@ private static Logger log = LoggerFactory.getLogger(SimpleNettyClient.class);
34 52
35 System.exit(0); 53 System.exit(0);
36 } 54 }
37 - public static void startStandalone(String... args) throws Exception { 55 +
56 + /**
57 + * Start standalone.
58 + *
59 + * @param args the args
60 + * @throws Exception the exception
61 + */
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();
47 MetricsFeature feature = new MetricsFeature("latency"); 72 MetricsFeature feature = new MetricsFeature("latency");
48 MetricsComponent component = metrics.registerComponent("NettyMessaging"); 73 MetricsComponent component = metrics.registerComponent("NettyMessaging");
49 - log.info("warmup...."); 74 + log.info("connecting " + host + ":" + port + " warmup:" + warmup + " iterations:" + iterations);
50 75
51 for (int i = 0; i < warmup; i++) { 76 for (int i = 0; i < warmup; i++) {
52 messaging.sendAsync(endpoint, "simple", "Hello World".getBytes()); 77 messaging.sendAsync(endpoint, "simple", "Hello World".getBytes());
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(10000);
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 } 124 }
77 125
126 + /**
127 + * The type Test netty messaging service.
128 + */
78 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 + */
79 public TestNettyMessagingService(int port) throws Exception { 136 public TestNettyMessagingService(int port) throws Exception {
80 super(port); 137 super(port);
81 } 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.
...@@ -18,17 +19,17 @@ public class SimpleNettyClientCommand extends AbstractShellCommand { ...@@ -18,17 +19,17 @@ public class SimpleNettyClientCommand extends AbstractShellCommand {
18 required = false, multiValued = false) 19 required = false, multiValued = false)
19 String hostname = "localhost"; 20 String hostname = "localhost";
20 21
21 - @Argument(index = 3, name = "port", description = "Port", 22 + @Argument(index = 1, name = "port", description = "Port",
22 required = false, multiValued = false) 23 required = false, multiValued = false)
23 String port = "8081"; 24 String port = "8081";
24 25
25 - @Argument(index = 1, name = "warmupCount", description = "Warm-up count", 26 + @Argument(index = 2, name = "warmupCount", description = "Warm-up count",
26 required = false, multiValued = false) 27 required = false, multiValued = false)
27 String warmupCount = "1000"; 28 String warmupCount = "1000";
28 29
29 - @Argument(index = 2, 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 }
......
...@@ -10,6 +10,7 @@ import org.apache.felix.scr.annotations.Deactivate; ...@@ -10,6 +10,7 @@ import org.apache.felix.scr.annotations.Deactivate;
10 import org.apache.felix.scr.annotations.Reference; 10 import org.apache.felix.scr.annotations.Reference;
11 import org.apache.felix.scr.annotations.ReferenceCardinality; 11 import org.apache.felix.scr.annotations.ReferenceCardinality;
12 import org.onlab.onos.ApplicationId; 12 import org.onlab.onos.ApplicationId;
13 +import org.onlab.onos.CoreService;
13 import org.onlab.onos.net.Host; 14 import org.onlab.onos.net.Host;
14 import org.onlab.onos.net.HostId; 15 import org.onlab.onos.net.HostId;
15 import org.onlab.onos.net.Path; 16 import org.onlab.onos.net.Path;
...@@ -53,13 +54,16 @@ public class ReactiveForwarding { ...@@ -53,13 +54,16 @@ public class ReactiveForwarding {
53 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 54 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
54 protected FlowRuleService flowRuleService; 55 protected FlowRuleService flowRuleService;
55 56
57 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
58 + protected CoreService coreService;
59 +
56 private ReactivePacketProcessor processor = new ReactivePacketProcessor(); 60 private ReactivePacketProcessor processor = new ReactivePacketProcessor();
57 61
58 private ApplicationId appId; 62 private ApplicationId appId;
59 63
60 @Activate 64 @Activate
61 public void activate() { 65 public void activate() {
62 - appId = ApplicationId.getAppId(); 66 + appId = coreService.registerApplication("org.onlab.onos.fwd");
63 packetService.addProcessor(processor, PacketProcessor.ADVISOR_MAX + 2); 67 packetService.addProcessor(processor, PacketProcessor.ADVISOR_MAX + 2);
64 log.info("Started with Application ID {}", appId.id()); 68 log.info("Started with Application ID {}", appId.id());
65 } 69 }
...@@ -166,8 +170,6 @@ public class ReactiveForwarding { ...@@ -166,8 +170,6 @@ public class ReactiveForwarding {
166 // We don't yet support bufferids in the flowservice so packet out first. 170 // We don't yet support bufferids in the flowservice so packet out first.
167 packetOut(context, portNumber); 171 packetOut(context, portNumber);
168 172
169 -
170 -
171 // Install the flow rule to handle this type of message from now on. 173 // Install the flow rule to handle this type of message from now on.
172 Ethernet inPkt = context.inPacket().parsed(); 174 Ethernet inPkt = context.inPacket().parsed();
173 TrafficSelector.Builder builder = DefaultTrafficSelector.builder(); 175 TrafficSelector.Builder builder = DefaultTrafficSelector.builder();
......
...@@ -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>
......
...@@ -10,6 +10,7 @@ import org.apache.felix.scr.annotations.Deactivate; ...@@ -10,6 +10,7 @@ import org.apache.felix.scr.annotations.Deactivate;
10 import org.apache.felix.scr.annotations.Reference; 10 import org.apache.felix.scr.annotations.Reference;
11 import org.apache.felix.scr.annotations.ReferenceCardinality; 11 import org.apache.felix.scr.annotations.ReferenceCardinality;
12 import org.onlab.onos.ApplicationId; 12 import org.onlab.onos.ApplicationId;
13 +import org.onlab.onos.CoreService;
13 import org.onlab.onos.net.Device; 14 import org.onlab.onos.net.Device;
14 import org.onlab.onos.net.Host; 15 import org.onlab.onos.net.Host;
15 import org.onlab.onos.net.device.DeviceService; 16 import org.onlab.onos.net.device.DeviceService;
...@@ -44,11 +45,14 @@ public class HostMobility { ...@@ -44,11 +45,14 @@ public class HostMobility {
44 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 45 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
45 protected DeviceService deviceService; 46 protected DeviceService deviceService;
46 47
48 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
49 + protected CoreService coreService;
50 +
47 private ApplicationId appId; 51 private ApplicationId appId;
48 52
49 @Activate 53 @Activate
50 public void activate() { 54 public void activate() {
51 - appId = ApplicationId.getAppId(); 55 + appId = coreService.registerApplication("org.onlab.onos.mobility");
52 hostService.addListener(new InternalHostListener()); 56 hostService.addListener(new InternalHostListener());
53 log.info("Started with Application ID {}", appId.id()); 57 log.info("Started with Application ID {}", appId.id());
54 } 58 }
......
...@@ -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>
......
...@@ -8,6 +8,7 @@ import org.apache.felix.scr.annotations.Deactivate; ...@@ -8,6 +8,7 @@ import org.apache.felix.scr.annotations.Deactivate;
8 import org.apache.felix.scr.annotations.Reference; 8 import org.apache.felix.scr.annotations.Reference;
9 import org.apache.felix.scr.annotations.ReferenceCardinality; 9 import org.apache.felix.scr.annotations.ReferenceCardinality;
10 import org.onlab.onos.ApplicationId; 10 import org.onlab.onos.ApplicationId;
11 +import org.onlab.onos.CoreService;
11 import org.onlab.onos.net.packet.PacketContext; 12 import org.onlab.onos.net.packet.PacketContext;
12 import org.onlab.onos.net.packet.PacketProcessor; 13 import org.onlab.onos.net.packet.PacketProcessor;
13 import org.onlab.onos.net.packet.PacketService; 14 import org.onlab.onos.net.packet.PacketService;
...@@ -31,11 +32,14 @@ public class ProxyArp { ...@@ -31,11 +32,14 @@ public class ProxyArp {
31 32
32 private ProxyArpProcessor processor = new ProxyArpProcessor(); 33 private ProxyArpProcessor processor = new ProxyArpProcessor();
33 34
35 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
36 + protected CoreService coreService;
37 +
34 private ApplicationId appId; 38 private ApplicationId appId;
35 39
36 @Activate 40 @Activate
37 public void activate() { 41 public void activate() {
38 - appId = ApplicationId.getAppId(); 42 + appId = coreService.registerApplication("org.onlab.onos.proxyarp");
39 packetService.addProcessor(processor, PacketProcessor.ADVISOR_MAX + 1); 43 packetService.addProcessor(processor, PacketProcessor.ADVISOR_MAX + 1);
40 log.info("Started with Application ID {}", appId.id()); 44 log.info("Started with Application ID {}", appId.id());
41 } 45 }
......
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
...@@ -141,7 +141,7 @@ public class TopologyResource extends BaseResource { ...@@ -141,7 +141,7 @@ public class TopologyResource extends BaseResource {
141 private ObjectNode json(ObjectMapper mapper, ElementId id, int group, 141 private ObjectNode json(ObjectMapper mapper, ElementId id, int group,
142 String label, boolean isOnline) { 142 String label, boolean isOnline) {
143 return mapper.createObjectNode() 143 return mapper.createObjectNode()
144 - .put("name", id.uri().toString()) 144 + .put("name", id.toString())
145 .put("label", label) 145 .put("label", label)
146 .put("group", group) 146 .put("group", group)
147 .put("online", isOnline); 147 .put("online", isOnline);
...@@ -202,7 +202,7 @@ public class TopologyResource extends BaseResource { ...@@ -202,7 +202,7 @@ public class TopologyResource extends BaseResource {
202 // Returns a formatted string for the element associated with the given 202 // Returns a formatted string for the element associated with the given
203 // connection point. 203 // connection point.
204 private static String id(ConnectPoint cp) { 204 private static String id(ConnectPoint cp) {
205 - return cp.elementId().uri().toString(); 205 + return cp.elementId().toString();
206 } 206 }
207 207
208 } 208 }
......
1 /** 1 /**
2 - * REST resources for the sample topology viewer application. 2 + * Sample topology viewer application.
3 */ 3 */
4 package org.onlab.onos.tvue; 4 package org.onlab.onos.tvue;
......
...@@ -21,14 +21,14 @@ public final class Comparators { ...@@ -21,14 +21,14 @@ public final class Comparators {
21 public static final Comparator<ElementId> ELEMENT_ID_COMPARATOR = new Comparator<ElementId>() { 21 public static final Comparator<ElementId> ELEMENT_ID_COMPARATOR = new Comparator<ElementId>() {
22 @Override 22 @Override
23 public int compare(ElementId id1, ElementId id2) { 23 public int compare(ElementId id1, ElementId id2) {
24 - return id1.uri().toString().compareTo(id2.uri().toString()); 24 + return id1.toString().compareTo(id2.toString());
25 } 25 }
26 }; 26 };
27 27
28 public static final Comparator<Element> ELEMENT_COMPARATOR = new Comparator<Element>() { 28 public static final Comparator<Element> ELEMENT_COMPARATOR = new Comparator<Element>() {
29 @Override 29 @Override
30 public int compare(Element e1, Element e2) { 30 public int compare(Element e1, Element e2) {
31 - return e1.id().uri().toString().compareTo(e2.id().uri().toString()); 31 + return e1.id().toString().compareTo(e2.id().toString());
32 } 32 }
33 }; 33 };
34 34
......
...@@ -22,8 +22,10 @@ public class SummaryCommand extends AbstractShellCommand { ...@@ -22,8 +22,10 @@ public class SummaryCommand extends AbstractShellCommand {
22 protected void execute() { 22 protected void execute() {
23 TopologyService topologyService = get(TopologyService.class); 23 TopologyService topologyService = get(TopologyService.class);
24 Topology topology = topologyService.currentTopology(); 24 Topology topology = topologyService.currentTopology();
25 - print("version=%s, nodes=%d, devices=%d, links=%d, hosts=%d, clusters=%s, paths=%d, flows=%d, intents=%d", 25 + print("node=%s, version=%s",
26 - get(CoreService.class).version().toString(), 26 + get(ClusterService.class).getLocalNode().ip(),
27 + get(CoreService.class).version().toString());
28 + print("nodes=%d, devices=%d, links=%d, hosts=%d, clusters=%s, paths=%d, flows=%d, intents=%d",
27 get(ClusterService.class).getNodes().size(), 29 get(ClusterService.class).getNodes().size(),
28 get(DeviceService.class).getDeviceCount(), 30 get(DeviceService.class).getDeviceCount(),
29 get(LinkService.class).getLinkCount(), 31 get(LinkService.class).getLinkCount(),
......
1 package org.onlab.onos.cli.net; 1 package org.onlab.onos.cli.net;
2 2
3 -import static com.google.common.collect.Lists.newArrayList; 3 +import com.google.common.collect.Maps;
4 -import static org.onlab.onos.cli.net.DevicesListCommand.getSortedDevices;
5 -
6 -import java.util.Collections;
7 -import java.util.List;
8 -import java.util.Map;
9 -
10 import org.apache.karaf.shell.commands.Argument; 4 import org.apache.karaf.shell.commands.Argument;
11 import org.apache.karaf.shell.commands.Command; 5 import org.apache.karaf.shell.commands.Command;
6 +import org.onlab.onos.CoreService;
12 import org.onlab.onos.cli.AbstractShellCommand; 7 import org.onlab.onos.cli.AbstractShellCommand;
13 import org.onlab.onos.cli.Comparators; 8 import org.onlab.onos.cli.Comparators;
14 import org.onlab.onos.net.Device; 9 import org.onlab.onos.net.Device;
...@@ -18,37 +13,43 @@ import org.onlab.onos.net.flow.FlowEntry; ...@@ -18,37 +13,43 @@ import org.onlab.onos.net.flow.FlowEntry;
18 import org.onlab.onos.net.flow.FlowEntry.FlowEntryState; 13 import org.onlab.onos.net.flow.FlowEntry.FlowEntryState;
19 import org.onlab.onos.net.flow.FlowRuleService; 14 import org.onlab.onos.net.flow.FlowRuleService;
20 15
21 -import com.google.common.collect.Maps; 16 +import java.util.Collections;
17 +import java.util.List;
18 +import java.util.Map;
19 +
20 +import static com.google.common.collect.Lists.newArrayList;
21 +import static org.onlab.onos.cli.net.DevicesListCommand.getSortedDevices;
22 22
23 /** 23 /**
24 * Lists all currently-known hosts. 24 * Lists all currently-known hosts.
25 */ 25 */
26 @Command(scope = "onos", name = "flows", 26 @Command(scope = "onos", name = "flows",
27 -description = "Lists all currently-known flows.") 27 + description = "Lists all currently-known flows.")
28 public class FlowsListCommand extends AbstractShellCommand { 28 public class FlowsListCommand extends AbstractShellCommand {
29 29
30 public static final String ANY = "any"; 30 public static final String ANY = "any";
31 31
32 private static final String FMT = 32 private static final String FMT =
33 - " id=%s, state=%s, bytes=%s, packets=%s, duration=%s, priority=%s"; 33 + " id=%s, state=%s, bytes=%s, packets=%s, duration=%s, priority=%s, appId=%s";
34 private static final String TFMT = " treatment=%s"; 34 private static final String TFMT = " treatment=%s";
35 private static final String SFMT = " selector=%s"; 35 private static final String SFMT = " selector=%s";
36 36
37 @Argument(index = 1, name = "uri", description = "Device ID", 37 @Argument(index = 1, name = "uri", description = "Device ID",
38 - required = false, multiValued = false) 38 + required = false, multiValued = false)
39 String uri = null; 39 String uri = null;
40 40
41 @Argument(index = 0, name = "state", description = "Flow Rule state", 41 @Argument(index = 0, name = "state", description = "Flow Rule state",
42 - required = false, multiValued = false) 42 + required = false, multiValued = false)
43 String state = null; 43 String state = null;
44 44
45 @Override 45 @Override
46 protected void execute() { 46 protected void execute() {
47 + CoreService coreService = get(CoreService.class);
47 DeviceService deviceService = get(DeviceService.class); 48 DeviceService deviceService = get(DeviceService.class);
48 FlowRuleService service = get(FlowRuleService.class); 49 FlowRuleService service = get(FlowRuleService.class);
49 Map<Device, List<FlowEntry>> flows = getSortedFlows(deviceService, service); 50 Map<Device, List<FlowEntry>> flows = getSortedFlows(deviceService, service);
50 for (Device d : getSortedDevices(deviceService)) { 51 for (Device d : getSortedDevices(deviceService)) {
51 - printFlows(d, flows.get(d)); 52 + printFlows(d, flows.get(d), coreService);
52 } 53 }
53 } 54 }
54 55
...@@ -67,7 +68,7 @@ public class FlowsListCommand extends AbstractShellCommand { ...@@ -67,7 +68,7 @@ public class FlowsListCommand extends AbstractShellCommand {
67 s = FlowEntryState.valueOf(state.toUpperCase()); 68 s = FlowEntryState.valueOf(state.toUpperCase());
68 } 69 }
69 Iterable<Device> devices = uri == null ? deviceService.getDevices() : 70 Iterable<Device> devices = uri == null ? deviceService.getDevices() :
70 - Collections.singletonList(deviceService.getDevice(DeviceId.deviceId(uri))); 71 + Collections.singletonList(deviceService.getDevice(DeviceId.deviceId(uri)));
71 for (Device d : devices) { 72 for (Device d : devices) {
72 if (s == null) { 73 if (s == null) {
73 rules = newArrayList(service.getFlowEntries(d.id())); 74 rules = newArrayList(service.getFlowEntries(d.id()));
...@@ -87,16 +88,19 @@ public class FlowsListCommand extends AbstractShellCommand { ...@@ -87,16 +88,19 @@ public class FlowsListCommand extends AbstractShellCommand {
87 88
88 /** 89 /**
89 * Prints flows. 90 * Prints flows.
90 - * @param d the device 91 + *
92 + * @param d the device
91 * @param flows the set of flows for that device. 93 * @param flows the set of flows for that device.
92 */ 94 */
93 - protected void printFlows(Device d, List<FlowEntry> flows) { 95 + protected void printFlows(Device d, List<FlowEntry> flows,
96 + CoreService coreService) {
94 boolean empty = flows == null || flows.isEmpty(); 97 boolean empty = flows == null || flows.isEmpty();
95 print("deviceId=%s, flowRuleCount=%d", d.id(), empty ? 0 : flows.size()); 98 print("deviceId=%s, flowRuleCount=%d", d.id(), empty ? 0 : flows.size());
96 if (!empty) { 99 if (!empty) {
97 for (FlowEntry f : flows) { 100 for (FlowEntry f : flows) {
98 - print(FMT, Long.toHexString(f.id().value()), f.state(), f.bytes(), 101 + print(FMT, Long.toHexString(f.id().value()), f.state(),
99 - f.packets(), f.life(), f.priority()); 102 + f.bytes(), f.packets(), f.life(), f.priority(),
103 + coreService.getAppId(f.appId()).name());
100 print(SFMT, f.selector().criteria()); 104 print(SFMT, f.selector().criteria());
101 print(TFMT, f.treatment().instructions()); 105 print(TFMT, f.treatment().instructions());
102 } 106 }
......
1 +package org.onlab.onos.cli.net;
2 +
3 +import java.util.concurrent.CountDownLatch;
4 +import java.util.concurrent.TimeUnit;
5 +
6 +import org.apache.karaf.shell.commands.Argument;
7 +import org.apache.karaf.shell.commands.Command;
8 +import org.onlab.onos.cli.AbstractShellCommand;
9 +import org.onlab.onos.net.ConnectPoint;
10 +import org.onlab.onos.net.DeviceId;
11 +import org.onlab.onos.net.PortNumber;
12 +import org.onlab.onos.net.flow.DefaultTrafficSelector;
13 +import org.onlab.onos.net.flow.DefaultTrafficTreatment;
14 +import org.onlab.onos.net.flow.TrafficSelector;
15 +import org.onlab.onos.net.flow.TrafficTreatment;
16 +import org.onlab.onos.net.intent.Intent;
17 +import org.onlab.onos.net.intent.IntentEvent;
18 +import org.onlab.onos.net.intent.IntentEvent.Type;
19 +import org.onlab.onos.net.intent.IntentId;
20 +import org.onlab.onos.net.intent.IntentListener;
21 +import org.onlab.onos.net.intent.IntentService;
22 +import org.onlab.onos.net.intent.PointToPointIntent;
23 +import org.onlab.packet.Ethernet;
24 +import org.onlab.packet.MacAddress;
25 +
26 +/**
27 + * Installs point-to-point connectivity intents.
28 + */
29 +@Command(scope = "onos", name = "push-test-intents",
30 + description = "Installs random intents to test throughput")
31 +public class IntentPushTestCommand extends AbstractShellCommand
32 + implements IntentListener {
33 +
34 + @Argument(index = 0, name = "ingressDevice",
35 + description = "Ingress Device/Port Description",
36 + required = true, multiValued = false)
37 + String ingressDeviceString = null;
38 +
39 + @Argument(index = 1, name = "egressDevice",
40 + description = "Egress Device/Port Description",
41 + required = true, multiValued = false)
42 + String egressDeviceString = null;
43 +
44 + @Argument(index = 2, name = "count",
45 + description = "Number of intents to push",
46 + required = true, multiValued = false)
47 + String countString = null;
48 +
49 +
50 + private static long id = 0x7870001;
51 +
52 + private IntentService service;
53 + private CountDownLatch latch;
54 + private long start, end;
55 +
56 + @Override
57 + protected void execute() {
58 + service = get(IntentService.class);
59 +
60 + DeviceId ingressDeviceId = DeviceId.deviceId(getDeviceId(ingressDeviceString));
61 + PortNumber ingressPortNumber =
62 + PortNumber.portNumber(getPortNumber(ingressDeviceString));
63 + ConnectPoint ingress = new ConnectPoint(ingressDeviceId, ingressPortNumber);
64 +
65 + DeviceId egressDeviceId = DeviceId.deviceId(getDeviceId(egressDeviceString));
66 + PortNumber egressPortNumber =
67 + PortNumber.portNumber(getPortNumber(egressDeviceString));
68 + ConnectPoint egress = new ConnectPoint(egressDeviceId, egressPortNumber);
69 +
70 + TrafficSelector.Builder selector = DefaultTrafficSelector.builder()
71 + .matchEthType(Ethernet.TYPE_IPV4);
72 + TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
73 +
74 + int count = Integer.parseInt(countString);
75 +
76 + service.addListener(this);
77 + latch = new CountDownLatch(count);
78 +
79 + start = System.currentTimeMillis();
80 + for (int i = 0; i < count; i++) {
81 + TrafficSelector s = selector
82 + .matchEthSrc(MacAddress.valueOf(i))
83 + .build();
84 + Intent intent =
85 + new PointToPointIntent(new IntentId(id++),
86 + s,
87 + treatment,
88 + ingress,
89 + egress);
90 + service.submit(intent);
91 + }
92 + try {
93 + latch.await(5, TimeUnit.SECONDS);
94 + printResults(count);
95 + } catch (InterruptedException e) {
96 + print(e.toString());
97 + }
98 + service.removeListener(this);
99 + }
100 +
101 + private void printResults(int count) {
102 + long delta = end - start;
103 + print("Time to install %d intents: %d ms", count, delta);
104 + }
105 +
106 + /**
107 + * Extracts the port number portion of the ConnectPoint.
108 + *
109 + * @param deviceString string representing the device/port
110 + * @return port number as a string, empty string if the port is not found
111 + */
112 + private String getPortNumber(String deviceString) {
113 + int slash = deviceString.indexOf('/');
114 + if (slash <= 0) {
115 + return "";
116 + }
117 + return deviceString.substring(slash + 1, deviceString.length());
118 + }
119 +
120 + /**
121 + * Extracts the device ID portion of the ConnectPoint.
122 + *
123 + * @param deviceString string representing the device/port
124 + * @return device ID string
125 + */
126 + private String getDeviceId(String deviceString) {
127 + int slash = deviceString.indexOf('/');
128 + if (slash <= 0) {
129 + return "";
130 + }
131 + return deviceString.substring(0, slash);
132 + }
133 +
134 + @Override
135 + public void event(IntentEvent event) {
136 + if (event.type() == Type.INSTALLED) {
137 + end = event.time();
138 + if (latch != null) {
139 + latch.countDown();
140 + } else {
141 + log.warn("install event latch is null");
142 + }
143 + }
144 + }
145 +}
...@@ -19,17 +19,16 @@ import org.onlab.onos.net.intent.IntentState; ...@@ -19,17 +19,16 @@ import org.onlab.onos.net.intent.IntentState;
19 description = "Wipes-out the entire network information base, i.e. devices, links, hosts") 19 description = "Wipes-out the entire network information base, i.e. devices, links, hosts")
20 public class WipeOutCommand extends ClustersListCommand { 20 public class WipeOutCommand extends ClustersListCommand {
21 21
22 - private static final String DISCLAIMER = "Delete everything please."; 22 + private static final String PLEASE = "please";
23 23
24 - @Argument(index = 0, name = "disclaimer", description = "Device ID", 24 + @Argument(index = 0, name = "please", description = "Confirmation phrase",
25 required = false, multiValued = false) 25 required = false, multiValued = false)
26 - String disclaimer = null; 26 + String please = null;
27 27
28 @Override 28 @Override
29 protected void execute() { 29 protected void execute() {
30 - if (disclaimer == null || !disclaimer.equals(DISCLAIMER)) { 30 + if (please == null || !please.equals(PLEASE)) {
31 - print("I'm afraid I can't do that!\nPlease acknowledge with phrase: '%s'", 31 + print("I'm afraid I can't do that!\nSay: %s", PLEASE);
32 - DISCLAIMER);
33 return; 32 return;
34 } 33 }
35 34
......
...@@ -82,6 +82,13 @@ ...@@ -82,6 +82,13 @@
82 <ref component-id="connectPointCompleter"/> 82 <ref component-id="connectPointCompleter"/>
83 </completers> 83 </completers>
84 </command> 84 </command>
85 + <command>
86 + <action class="org.onlab.onos.cli.net.IntentPushTestCommand"/>
87 + <completers>
88 + <ref component-id="connectPointCompleter"/>
89 + <ref component-id="connectPointCompleter"/>
90 + </completers>
91 + </command>
85 92
86 <command> 93 <command>
87 <action class="org.onlab.onos.cli.net.ClustersListCommand"/> 94 <action class="org.onlab.onos.cli.net.ClustersListCommand"/>
......
1 package org.onlab.onos; 1 package org.onlab.onos;
2 2
3 -import java.util.Objects;
4 -import java.util.concurrent.atomic.AtomicInteger;
5 3
6 /** 4 /**
7 - * Application id generator class. 5 + * Application identifier.
8 */ 6 */
9 -public final class ApplicationId { 7 +public interface ApplicationId {
10 8
11 - private static final AtomicInteger ID_DISPENCER = new AtomicInteger(1); 9 + /**
12 - private final Integer id; 10 + * Returns the application id.
13 - 11 + * @return a short value
14 - // Ban public construction 12 + */
15 - private ApplicationId(Integer id) { 13 + short id();
16 - this.id = id;
17 - }
18 -
19 - public Integer id() {
20 - return id;
21 - }
22 -
23 - public static ApplicationId valueOf(Integer id) {
24 - return new ApplicationId(id);
25 - }
26 -
27 - @Override
28 - public int hashCode() {
29 - return Objects.hash(id);
30 - }
31 -
32 - @Override
33 - public boolean equals(Object obj) {
34 - if (this == obj) {
35 - return true;
36 - }
37 - if (obj == null) {
38 - return false;
39 - }
40 - if (!(obj instanceof ApplicationId)) {
41 - return false;
42 - }
43 - ApplicationId other = (ApplicationId) obj;
44 - return Objects.equals(this.id, other.id);
45 - }
46 14
47 /** 15 /**
48 - * Returns a new application id. 16 + * Returns the applications supplied identifier.
49 - * 17 + * @return a string identifier
50 - * @return app id
51 */ 18 */
52 - public static ApplicationId getAppId() { 19 + String name();
53 - return new ApplicationId(ApplicationId.ID_DISPENCER.getAndIncrement());
54 - }
55 20
56 } 21 }
......
...@@ -12,4 +12,21 @@ public interface CoreService { ...@@ -12,4 +12,21 @@ public interface CoreService {
12 */ 12 */
13 Version version(); 13 Version version();
14 14
15 + /**
16 + * Registers a new application by its name, which is expected
17 + * to follow the reverse DNS convention, e.g.
18 + * {@code org.flying.circus.app}
19 + *
20 + * @param identifier string identifier
21 + * @return the application id
22 + */
23 + ApplicationId registerApplication(String identifier);
24 +
25 + /**
26 + * Returns an existing application id from a given id.
27 + * @param id the short value of the id
28 + * @return an application id
29 + */
30 + ApplicationId getAppId(Short id);
31 +
15 } 32 }
......
1 +package org.onlab.onos.cluster;
2 +
3 +import com.google.common.base.Function;
4 +
5 +/**
6 + * Function to convert ControllerNode to NodeId.
7 + */
8 +public final class ControllerNodeToNodeId
9 + implements Function<ControllerNode, NodeId> {
10 +
11 + private static final ControllerNodeToNodeId INSTANCE = new ControllerNodeToNodeId();
12 +
13 + @Override
14 + public NodeId apply(ControllerNode input) {
15 + return input.id();
16 + }
17 +
18 + /**
19 + * Returns a Function to convert ControllerNode to NodeId.
20 + *
21 + * @return ControllerNodeToNodeId instance.
22 + */
23 + public static ControllerNodeToNodeId toNodeId() {
24 + return INSTANCE;
25 + }
26 +}
1 package org.onlab.onos.net; 1 package org.onlab.onos.net;
2 2
3 import java.net.URI; 3 import java.net.URI;
4 +import java.util.Objects;
4 5
5 /** 6 /**
6 * Immutable representation of a device identity. 7 * Immutable representation of a device identity.
7 */ 8 */
8 public final class DeviceId extends ElementId { 9 public final class DeviceId extends ElementId {
9 10
11 + /**
12 + * Represents either no device, or an unspecified device.
13 + */
14 + public static final DeviceId NONE = deviceId("none:none");
15 +
16 + private final URI uri;
17 + private final String str;
18 +
10 // Public construction is prohibited 19 // Public construction is prohibited
11 private DeviceId(URI uri) { 20 private DeviceId(URI uri) {
12 - super(uri); 21 + this.uri = uri;
22 + this.str = uri.toString();
23 + }
24 +
25 +
26 + // Default constructor for serialization
27 + protected DeviceId() {
28 + this.uri = null;
29 + this.str = null;
13 } 30 }
14 31
15 /** 32 /**
...@@ -30,4 +47,36 @@ public final class DeviceId extends ElementId { ...@@ -30,4 +47,36 @@ public final class DeviceId extends ElementId {
30 return deviceId(URI.create(string)); 47 return deviceId(URI.create(string));
31 } 48 }
32 49
50 + /**
51 + * Returns the backing URI.
52 + *
53 + * @return backing URI
54 + */
55 + public URI uri() {
56 + return uri;
57 + }
58 +
59 + @Override
60 + public int hashCode() {
61 + return Objects.hash(str);
62 + }
63 +
64 + @Override
65 + public boolean equals(Object obj) {
66 + if (this == obj) {
67 + return true;
68 + }
69 + if (obj instanceof DeviceId) {
70 + final DeviceId that = (DeviceId) obj;
71 + return this.getClass() == that.getClass() &&
72 + Objects.equals(this.str, that.str);
73 + }
74 + return false;
75 + }
76 +
77 + @Override
78 + public String toString() {
79 + return str;
80 + }
81 +
33 } 82 }
......
1 package org.onlab.onos.net; 1 package org.onlab.onos.net;
2 2
3 -import java.net.URI;
4 -import java.util.Objects;
5 -
6 /** 3 /**
7 * Immutable representation of a network element identity. 4 * Immutable representation of a network element identity.
8 */ 5 */
9 public abstract class ElementId { 6 public abstract class ElementId {
10 -
11 - private final URI uri;
12 -
13 - // Default constructor for serialization
14 - protected ElementId() {
15 - this.uri = null;
16 - }
17 -
18 - /**
19 - * Creates an element identifier using the supplied URI.
20 - *
21 - * @param uri backing URI
22 - */
23 - protected ElementId(URI uri) {
24 - this.uri = uri;
25 - }
26 -
27 - /**
28 - * Returns the backing URI.
29 - *
30 - * @return backing URI
31 - */
32 - public URI uri() {
33 - return uri;
34 - }
35 -
36 - @Override
37 - public int hashCode() {
38 - return Objects.hash(uri);
39 - }
40 -
41 - @Override
42 - public boolean equals(Object obj) {
43 - if (this == obj) {
44 - return true;
45 - }
46 - if (obj instanceof ElementId) {
47 - final ElementId that = (ElementId) obj;
48 - return this.getClass() == that.getClass() &&
49 - Objects.equals(this.uri, that.uri);
50 - }
51 - return false;
52 - }
53 -
54 - @Override
55 - public String toString() {
56 - return uri.toString();
57 - }
58 -
59 } 7 }
......
...@@ -3,44 +3,69 @@ package org.onlab.onos.net; ...@@ -3,44 +3,69 @@ package org.onlab.onos.net;
3 import org.onlab.packet.MacAddress; 3 import org.onlab.packet.MacAddress;
4 import org.onlab.packet.VlanId; 4 import org.onlab.packet.VlanId;
5 5
6 -import java.net.URI; 6 +import java.util.Objects;
7 +
8 +import static com.google.common.base.Preconditions.checkArgument;
7 9
8 /** 10 /**
9 * Immutable representation of a host identity. 11 * Immutable representation of a host identity.
10 */ 12 */
11 public final class HostId extends ElementId { 13 public final class HostId extends ElementId {
12 14
13 - private static final String NIC = "nic";
14 -
15 /** 15 /**
16 * Represents either no host, or an unspecified host; used for creating 16 * Represents either no host, or an unspecified host; used for creating
17 * open ingress/egress edge links. 17 * open ingress/egress edge links.
18 */ 18 */
19 - public static final HostId NONE = hostId(NIC + ":none-0"); 19 + public static final HostId NONE = new HostId(MacAddress.ZERO, VlanId.NONE);
20 +
21 + private static final int MAC_LENGTH = 17;
22 + private static final int MIN_ID_LENGTH = 19;
23 +
24 + private final MacAddress mac;
25 + private final VlanId vlanId;
20 26
21 // Public construction is prohibited 27 // Public construction is prohibited
22 - private HostId(URI uri) { 28 + private HostId(MacAddress mac, VlanId vlanId) {
23 - super(uri); 29 + this.mac = mac;
30 + this.vlanId = vlanId;
31 + }
32 +
33 + // Default constructor for serialization
34 + private HostId() {
35 + this.mac = null;
36 + this.vlanId = null;
24 } 37 }
25 38
26 /** 39 /**
27 - * Creates a device id using the supplied URI. 40 + * Returns the host MAC address.
28 * 41 *
29 - * @param uri device URI 42 + * @return MAC address
30 - * @return host identifier 43 + */
44 + public MacAddress mac() {
45 + return mac;
46 + }
47 +
48 + /**
49 + * Returns the host MAC address.
50 + *
51 + * @return MAC address
31 */ 52 */
32 - public static HostId hostId(URI uri) { 53 + public VlanId vlanId() {
33 - return new HostId(uri); 54 + return vlanId;
34 } 55 }
35 56
36 /** 57 /**
37 - * Creates a device id using the supplied URI string. 58 + * Creates a device id using the supplied ID string.
38 * 59 *
39 * @param string device URI string 60 * @param string device URI string
40 * @return host identifier 61 * @return host identifier
41 */ 62 */
42 public static HostId hostId(String string) { 63 public static HostId hostId(String string) {
43 - return hostId(URI.create(string)); 64 + checkArgument(string.length() >= MIN_ID_LENGTH,
65 + "Host ID must be at least %s characters", MIN_ID_LENGTH);
66 + MacAddress mac = MacAddress.valueOf(string.substring(0, MAC_LENGTH));
67 + VlanId vlanId = VlanId.vlanId(Short.parseShort(string.substring(MAC_LENGTH + 1)));
68 + return new HostId(mac, vlanId);
44 } 69 }
45 70
46 /** 71 /**
...@@ -51,7 +76,7 @@ public final class HostId extends ElementId { ...@@ -51,7 +76,7 @@ public final class HostId extends ElementId {
51 * @return host identifier 76 * @return host identifier
52 */ 77 */
53 public static HostId hostId(MacAddress mac, VlanId vlanId) { 78 public static HostId hostId(MacAddress mac, VlanId vlanId) {
54 - return hostId(NIC + ":" + mac + "-" + vlanId); 79 + return new HostId(mac, vlanId);
55 } 80 }
56 81
57 /** 82 /**
...@@ -64,4 +89,26 @@ public final class HostId extends ElementId { ...@@ -64,4 +89,26 @@ public final class HostId extends ElementId {
64 return hostId(mac, VlanId.vlanId(VlanId.UNTAGGED)); 89 return hostId(mac, VlanId.vlanId(VlanId.UNTAGGED));
65 } 90 }
66 91
92 + public String toString() {
93 + return mac + "/" + vlanId;
94 + }
95 +
96 + @Override
97 + public int hashCode() {
98 + return Objects.hash(mac, vlanId);
99 + }
100 +
101 + @Override
102 + public boolean equals(Object obj) {
103 + if (this == obj) {
104 + return true;
105 + }
106 + if (obj instanceof HostId) {
107 + final HostId other = (HostId) obj;
108 + return Objects.equals(this.mac, other.mac) &&
109 + Objects.equals(this.vlanId, other.vlanId);
110 + }
111 + return false;
112 + }
113 +
67 } 114 }
......
1 package org.onlab.onos.net; 1 package org.onlab.onos.net;
2 2
3 +import static org.onlab.onos.net.PortNumber.P0;
4 +
3 /** 5 /**
4 * Representation of a network edge location where an end-station host is 6 * Representation of a network edge location where an end-station host is
5 * connected. 7 * connected.
6 */ 8 */
7 public class HostLocation extends ConnectPoint { 9 public class HostLocation extends ConnectPoint {
8 10
11 + /**
12 + * Represents a no location or an unknown location.
13 + */
14 + public static final HostLocation NONE = new HostLocation(DeviceId.NONE, P0, 0L);
15 +
9 // Note that time is explicitly excluded from the notion of equality. 16 // Note that time is explicitly excluded from the notion of equality.
10 private final long time; 17 private final long time;
11 18
......
1 +package org.onlab.onos.net;
2 +
3 +/**
4 + * Representation of a network resource.
5 + */
6 +public interface NetworkResource {
7 +}
...@@ -4,6 +4,8 @@ import org.onlab.onos.net.AbstractDescription; ...@@ -4,6 +4,8 @@ import org.onlab.onos.net.AbstractDescription;
4 import org.onlab.onos.net.PortNumber; 4 import org.onlab.onos.net.PortNumber;
5 import org.onlab.onos.net.SparseAnnotations; 5 import org.onlab.onos.net.SparseAnnotations;
6 6
7 +import com.google.common.base.MoreObjects;
8 +
7 /** 9 /**
8 * Default implementation of immutable port description. 10 * Default implementation of immutable port description.
9 */ 11 */
...@@ -48,6 +50,15 @@ public class DefaultPortDescription extends AbstractDescription ...@@ -48,6 +50,15 @@ public class DefaultPortDescription extends AbstractDescription
48 return isEnabled; 50 return isEnabled;
49 } 51 }
50 52
53 + @Override
54 + public String toString() {
55 + return MoreObjects.toStringHelper(getClass())
56 + .add("number", number)
57 + .add("isEnabled", isEnabled)
58 + .add("annotations", annotations())
59 + .toString();
60 + }
61 +
51 // default constructor for serialization 62 // default constructor for serialization
52 private DefaultPortDescription() { 63 private DefaultPortDescription() {
53 this.number = null; 64 this.number = null;
......
1 +package org.onlab.onos.net.flow;
2 +
3 +import java.util.List;
4 +
5 +/**
6 + * Interface capturing the result of a batch operation.
7 + *
8 + */
9 +public interface BatchOperationResult<T> {
10 +
11 + /**
12 + * Returns whether the operation was successful.
13 + * @return true if successful, false otherwise
14 + */
15 + boolean isSuccess();
16 +
17 + /**
18 + * Obtains a list of items which failed.
19 + * @return a list of failures
20 + */
21 + List<T> failedItems();
22 +
23 +}
1 package org.onlab.onos.net.flow; 1 package org.onlab.onos.net.flow;
2 2
3 -public class CompletedBatchOperation { 3 +import java.util.List;
4 +
5 +import com.google.common.collect.ImmutableList;
6 +
7 +public class CompletedBatchOperation implements BatchOperationResult<FlowEntry> {
8 +
9 +
10 + private final boolean success;
11 + private final List<FlowEntry> failures;
12 +
13 + public CompletedBatchOperation(boolean success, List<FlowEntry> failures) {
14 + this.success = success;
15 + this.failures = ImmutableList.copyOf(failures);
16 + }
17 +
18 + @Override
19 + public boolean isSuccess() {
20 + return success;
21 + }
22 +
23 + @Override
24 + public List<FlowEntry> failedItems() {
25 + return failures;
26 + }
4 27
5 28
6 } 29 }
......
...@@ -17,6 +17,10 @@ public class DefaultFlowEntry extends DefaultFlowRule implements FlowEntry { ...@@ -17,6 +17,10 @@ public class DefaultFlowEntry extends DefaultFlowRule implements FlowEntry {
17 17
18 private long lastSeen = -1; 18 private long lastSeen = -1;
19 19
20 + private final int errType;
21 +
22 + private final int errCode;
23 +
20 24
21 public DefaultFlowEntry(DeviceId deviceId, TrafficSelector selector, 25 public DefaultFlowEntry(DeviceId deviceId, TrafficSelector selector,
22 TrafficTreatment treatment, int priority, FlowEntryState state, 26 TrafficTreatment treatment, int priority, FlowEntryState state,
...@@ -27,6 +31,8 @@ public class DefaultFlowEntry extends DefaultFlowRule implements FlowEntry { ...@@ -27,6 +31,8 @@ public class DefaultFlowEntry extends DefaultFlowRule implements FlowEntry {
27 this.life = life; 31 this.life = life;
28 this.packets = packets; 32 this.packets = packets;
29 this.bytes = bytes; 33 this.bytes = bytes;
34 + this.errCode = -1;
35 + this.errType = -1;
30 this.lastSeen = System.currentTimeMillis(); 36 this.lastSeen = System.currentTimeMillis();
31 } 37 }
32 38
...@@ -37,6 +43,8 @@ public class DefaultFlowEntry extends DefaultFlowRule implements FlowEntry { ...@@ -37,6 +43,8 @@ public class DefaultFlowEntry extends DefaultFlowRule implements FlowEntry {
37 this.life = life; 43 this.life = life;
38 this.packets = packets; 44 this.packets = packets;
39 this.bytes = bytes; 45 this.bytes = bytes;
46 + this.errCode = -1;
47 + this.errType = -1;
40 this.lastSeen = System.currentTimeMillis(); 48 this.lastSeen = System.currentTimeMillis();
41 } 49 }
42 50
...@@ -46,9 +54,18 @@ public class DefaultFlowEntry extends DefaultFlowRule implements FlowEntry { ...@@ -46,9 +54,18 @@ public class DefaultFlowEntry extends DefaultFlowRule implements FlowEntry {
46 this.life = 0; 54 this.life = 0;
47 this.packets = 0; 55 this.packets = 0;
48 this.bytes = 0; 56 this.bytes = 0;
57 + this.errCode = -1;
58 + this.errType = -1;
49 this.lastSeen = System.currentTimeMillis(); 59 this.lastSeen = System.currentTimeMillis();
50 } 60 }
51 61
62 + public DefaultFlowEntry(FlowRule rule, int errType, int errCode) {
63 + super(rule);
64 + this.state = FlowEntryState.FAILED;
65 + this.errType = errType;
66 + this.errCode = errCode;
67 + }
68 +
52 @Override 69 @Override
53 public long life() { 70 public long life() {
54 return life; 71 return life;
...@@ -100,6 +117,16 @@ public class DefaultFlowEntry extends DefaultFlowRule implements FlowEntry { ...@@ -100,6 +117,16 @@ public class DefaultFlowEntry extends DefaultFlowRule implements FlowEntry {
100 } 117 }
101 118
102 @Override 119 @Override
120 + public int errType() {
121 + return this.errType;
122 + }
123 +
124 + @Override
125 + public int errCode() {
126 + return this.errCode;
127 + }
128 +
129 + @Override
103 public String toString() { 130 public String toString() {
104 return toStringHelper(this) 131 return toStringHelper(this)
105 .add("rule", super.toString()) 132 .add("rule", super.toString())
...@@ -108,4 +135,6 @@ public class DefaultFlowEntry extends DefaultFlowRule implements FlowEntry { ...@@ -108,4 +135,6 @@ public class DefaultFlowEntry extends DefaultFlowRule implements FlowEntry {
108 } 135 }
109 136
110 137
138 +
139 +
111 } 140 }
......
...@@ -21,7 +21,7 @@ public class DefaultFlowRule implements FlowRule { ...@@ -21,7 +21,7 @@ public class DefaultFlowRule implements FlowRule {
21 21
22 private final FlowId id; 22 private final FlowId id;
23 23
24 - private final ApplicationId appId; 24 + private final short appId;
25 25
26 private final int timeout; 26 private final int timeout;
27 27
...@@ -36,7 +36,7 @@ public class DefaultFlowRule implements FlowRule { ...@@ -36,7 +36,7 @@ public class DefaultFlowRule implements FlowRule {
36 this.timeout = timeout; 36 this.timeout = timeout;
37 this.created = System.currentTimeMillis(); 37 this.created = System.currentTimeMillis();
38 38
39 - this.appId = ApplicationId.valueOf((int) (flowId >> 32)); 39 + this.appId = (short) (flowId >>> 48);
40 this.id = FlowId.valueOf(flowId); 40 this.id = FlowId.valueOf(flowId);
41 } 41 }
42 42
...@@ -52,11 +52,11 @@ public class DefaultFlowRule implements FlowRule { ...@@ -52,11 +52,11 @@ public class DefaultFlowRule implements FlowRule {
52 this.priority = priority; 52 this.priority = priority;
53 this.selector = selector; 53 this.selector = selector;
54 this.treatment = treatement; 54 this.treatment = treatement;
55 - this.appId = appId; 55 + this.appId = appId.id();
56 this.timeout = timeout; 56 this.timeout = timeout;
57 this.created = System.currentTimeMillis(); 57 this.created = System.currentTimeMillis();
58 58
59 - this.id = FlowId.valueOf((((long) appId().id()) << 32) | (this.hash() & 0xffffffffL)); 59 + this.id = FlowId.valueOf((((long) this.appId) << 48) | (this.hash() & 0x0000ffffffffL));
60 } 60 }
61 61
62 public DefaultFlowRule(FlowRule rule) { 62 public DefaultFlowRule(FlowRule rule) {
...@@ -78,7 +78,7 @@ public class DefaultFlowRule implements FlowRule { ...@@ -78,7 +78,7 @@ public class DefaultFlowRule implements FlowRule {
78 } 78 }
79 79
80 @Override 80 @Override
81 - public ApplicationId appId() { 81 + public short appId() {
82 return appId; 82 return appId;
83 } 83 }
84 84
......
...@@ -140,6 +140,16 @@ public final class DefaultTrafficSelector implements TrafficSelector { ...@@ -140,6 +140,16 @@ public final class DefaultTrafficSelector implements TrafficSelector {
140 } 140 }
141 141
142 @Override 142 @Override
143 + public Builder matchTcpSrc(Short tcpPort) {
144 + return add(Criteria.matchTcpSrc(tcpPort));
145 + }
146 +
147 + @Override
148 + public Builder matchTcpDst(Short tcpPort) {
149 + return add(Criteria.matchTcpDst(tcpPort));
150 + }
151 +
152 + @Override
143 public TrafficSelector build() { 153 public TrafficSelector build() {
144 return new DefaultTrafficSelector(ImmutableSet.copyOf(selector.values())); 154 return new DefaultTrafficSelector(ImmutableSet.copyOf(selector.values()));
145 } 155 }
......
1 package org.onlab.onos.net.flow; 1 package org.onlab.onos.net.flow;
2 2
3 -import static org.slf4j.LoggerFactory.getLogger;
4 -
5 -import java.util.Collections;
6 -import java.util.LinkedList;
7 -import java.util.List;
8 -import java.util.Objects;
9 -
10 import org.onlab.onos.net.PortNumber; 3 import org.onlab.onos.net.PortNumber;
11 import org.onlab.onos.net.flow.instructions.Instruction; 4 import org.onlab.onos.net.flow.instructions.Instruction;
12 import org.onlab.onos.net.flow.instructions.Instructions; 5 import org.onlab.onos.net.flow.instructions.Instructions;
13 import org.onlab.packet.IpPrefix; 6 import org.onlab.packet.IpPrefix;
14 import org.onlab.packet.MacAddress; 7 import org.onlab.packet.MacAddress;
15 import org.onlab.packet.VlanId; 8 import org.onlab.packet.VlanId;
16 -import org.slf4j.Logger; 9 +
10 +import java.util.Collections;
11 +import java.util.LinkedList;
12 +import java.util.List;
13 +import java.util.Objects;
17 14
18 /** 15 /**
19 * Default traffic treatment implementation. 16 * Default traffic treatment implementation.
...@@ -58,7 +55,7 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { ...@@ -58,7 +55,7 @@ public final class DefaultTrafficTreatment implements TrafficTreatment {
58 } 55 }
59 if (obj instanceof DefaultTrafficTreatment) { 56 if (obj instanceof DefaultTrafficTreatment) {
60 DefaultTrafficTreatment that = (DefaultTrafficTreatment) obj; 57 DefaultTrafficTreatment that = (DefaultTrafficTreatment) obj;
61 - return Objects.equals(instructions, that.instructions); 58 + return Objects.equals(instructions, that.instructions);
62 59
63 } 60 }
64 return false; 61 return false;
...@@ -70,8 +67,6 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { ...@@ -70,8 +67,6 @@ public final class DefaultTrafficTreatment implements TrafficTreatment {
70 */ 67 */
71 public static final class Builder implements TrafficTreatment.Builder { 68 public static final class Builder implements TrafficTreatment.Builder {
72 69
73 - private final Logger log = getLogger(getClass());
74 -
75 boolean drop = false; 70 boolean drop = false;
76 71
77 List<Instruction> outputs = new LinkedList<>(); 72 List<Instruction> outputs = new LinkedList<>();
...@@ -107,7 +102,8 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { ...@@ -107,7 +102,8 @@ public final class DefaultTrafficTreatment implements TrafficTreatment {
107 groups.add(instruction); 102 groups.add(instruction);
108 break; 103 break;
109 default: 104 default:
110 - log.warn("Unknown instruction type {}", instruction.type()); 105 + throw new IllegalArgumentException("Unknown instruction type: " +
106 + instruction.type());
111 } 107 }
112 return this; 108 return this;
113 } 109 }
......
...@@ -29,7 +29,12 @@ public interface FlowEntry extends FlowRule { ...@@ -29,7 +29,12 @@ public interface FlowEntry extends FlowRule {
29 /** 29 /**
30 * Flow has been removed from flow table and can be purged. 30 * Flow has been removed from flow table and can be purged.
31 */ 31 */
32 - REMOVED 32 + REMOVED,
33 +
34 + /**
35 + * Indicates that the installation of this flow has failed.
36 + */
37 + FAILED
33 } 38 }
34 39
35 /** 40 /**
...@@ -95,4 +100,16 @@ public interface FlowEntry extends FlowRule { ...@@ -95,4 +100,16 @@ public interface FlowEntry extends FlowRule {
95 */ 100 */
96 void setBytes(long bytes); 101 void setBytes(long bytes);
97 102
103 + /**
104 + * Indicates the error type.
105 + * @return an integer value of the error
106 + */
107 + int errType();
108 +
109 + /**
110 + * Indicates the error code.
111 + * @return an integer value of the error
112 + */
113 + int errCode();
114 +
98 } 115 }
......
1 package org.onlab.onos.net.flow; 1 package org.onlab.onos.net.flow;
2 2
3 -import org.onlab.onos.ApplicationId;
4 import org.onlab.onos.net.DeviceId; 3 import org.onlab.onos.net.DeviceId;
5 import org.onlab.onos.net.intent.BatchOperationTarget; 4 import org.onlab.onos.net.intent.BatchOperationTarget;
6 5
...@@ -26,7 +25,7 @@ public interface FlowRule extends BatchOperationTarget { ...@@ -26,7 +25,7 @@ public interface FlowRule extends BatchOperationTarget {
26 * 25 *
27 * @return an applicationId 26 * @return an applicationId
28 */ 27 */
29 - ApplicationId appId(); 28 + short appId();
30 29
31 /** 30 /**
32 * Returns the flow rule priority given in natural order; higher numbers 31 * Returns the flow rule priority given in natural order; higher numbers
......
...@@ -37,6 +37,12 @@ public interface FlowRuleProvider extends Provider { ...@@ -37,6 +37,12 @@ public interface FlowRuleProvider extends Provider {
37 */ 37 */
38 void removeRulesById(ApplicationId id, FlowRule... flowRules); 38 void removeRulesById(ApplicationId id, FlowRule... flowRules);
39 39
40 - Future<Void> executeBatch(BatchOperation<FlowRuleBatchEntry> batch); 40 + /**
41 + * Installs a batch of flow rules. Each flowrule is associated to an
42 + * operation which results in either addition, removal or modification.
43 + * @param batch a batch of flow rules
44 + * @return a future indicating the status of this execution
45 + */
46 + Future<CompletedBatchOperation> executeBatch(BatchOperation<FlowRuleBatchEntry> batch);
41 47
42 } 48 }
......
...@@ -98,6 +98,20 @@ public interface TrafficSelector { ...@@ -98,6 +98,20 @@ public interface TrafficSelector {
98 public Builder matchIPDst(IpPrefix ip); 98 public Builder matchIPDst(IpPrefix ip);
99 99
100 /** 100 /**
101 + * Matches a TCP source port number.
102 + * @param tcpPort a TCP source port number
103 + * @return a selection builder
104 + */
105 + public Builder matchTcpSrc(Short tcpPort);
106 +
107 + /**
108 + * Matches a TCP destination port number.
109 + * @param tcpPort a TCP destination port number
110 + * @return a selection builder
111 + */
112 + public Builder matchTcpDst(Short tcpPort);
113 +
114 + /**
101 * Builds an immutable traffic selector. 115 * Builds an immutable traffic selector.
102 * 116 *
103 * @return traffic selector 117 * @return traffic selector
......
...@@ -113,6 +113,25 @@ public final class Criteria { ...@@ -113,6 +113,25 @@ public final class Criteria {
113 return new IPCriterion(ip, Type.IPV4_DST); 113 return new IPCriterion(ip, Type.IPV4_DST);
114 } 114 }
115 115
116 + /**
117 + * Creates a match on TCP source port field using the specified value.
118 + *
119 + * @param tcpPort
120 + * @return match criterion
121 + */
122 + public static Criterion matchTcpSrc(Short tcpPort) {
123 + return new TcpPortCriterion(tcpPort, Type.TCP_SRC);
124 + }
125 +
126 + /**
127 + * Creates a match on TCP destination port field using the specified value.
128 + *
129 + * @param tcpPort
130 + * @return match criterion
131 + */
132 + public static Criterion matchTcpDst(Short tcpPort) {
133 + return new TcpPortCriterion(tcpPort, Type.TCP_DST);
134 + }
116 135
117 /* 136 /*
118 * Implementations of criteria. 137 * Implementations of criteria.
...@@ -437,4 +456,49 @@ public final class Criteria { ...@@ -437,4 +456,49 @@ public final class Criteria {
437 } 456 }
438 457
439 458
459 + public static final class TcpPortCriterion implements Criterion {
460 +
461 + private final Short tcpPort;
462 + private final Type type;
463 +
464 + public TcpPortCriterion(Short tcpPort, Type type) {
465 + this.tcpPort = tcpPort;
466 + this.type = type;
467 + }
468 +
469 + @Override
470 + public Type type() {
471 + return this.type;
472 + }
473 +
474 + public Short tcpPort() {
475 + return this.tcpPort;
476 + }
477 +
478 + @Override
479 + public String toString() {
480 + return toStringHelper(type().toString())
481 + .add("tcpPort", tcpPort).toString();
482 + }
483 +
484 + @Override
485 + public int hashCode() {
486 + return Objects.hash(tcpPort, type);
487 + }
488 +
489 + @Override
490 + public boolean equals(Object obj) {
491 + if (this == obj) {
492 + return true;
493 + }
494 + if (obj instanceof TcpPortCriterion) {
495 + TcpPortCriterion that = (TcpPortCriterion) obj;
496 + return Objects.equals(tcpPort, that.tcpPort) &&
497 + Objects.equals(type, that.type);
498 +
499 +
500 + }
501 + return false;
502 + }
503 + }
440 } 504 }
......
1 package org.onlab.onos.net.host; 1 package org.onlab.onos.net.host;
2 2
3 -import com.google.common.collect.ImmutableSet;
4 import org.onlab.onos.net.AbstractDescription; 3 import org.onlab.onos.net.AbstractDescription;
5 import org.onlab.onos.net.HostLocation; 4 import org.onlab.onos.net.HostLocation;
6 import org.onlab.onos.net.SparseAnnotations; 5 import org.onlab.onos.net.SparseAnnotations;
...@@ -8,9 +7,6 @@ import org.onlab.packet.IpPrefix; ...@@ -8,9 +7,6 @@ import org.onlab.packet.IpPrefix;
8 import org.onlab.packet.MacAddress; 7 import org.onlab.packet.MacAddress;
9 import org.onlab.packet.VlanId; 8 import org.onlab.packet.VlanId;
10 9
11 -import java.util.HashSet;
12 -import java.util.Set;
13 -
14 import static com.google.common.base.MoreObjects.toStringHelper; 10 import static com.google.common.base.MoreObjects.toStringHelper;
15 11
16 /** 12 /**
...@@ -22,7 +18,7 @@ public class DefaultHostDescription extends AbstractDescription ...@@ -22,7 +18,7 @@ public class DefaultHostDescription extends AbstractDescription
22 private final MacAddress mac; 18 private final MacAddress mac;
23 private final VlanId vlan; 19 private final VlanId vlan;
24 private final HostLocation location; 20 private final HostLocation location;
25 - private final Set<IpPrefix> ips; 21 + private final IpPrefix ip;
26 22
27 /** 23 /**
28 * Creates a host description using the supplied information. 24 * Creates a host description using the supplied information.
...@@ -35,7 +31,7 @@ public class DefaultHostDescription extends AbstractDescription ...@@ -35,7 +31,7 @@ public class DefaultHostDescription extends AbstractDescription
35 public DefaultHostDescription(MacAddress mac, VlanId vlan, 31 public DefaultHostDescription(MacAddress mac, VlanId vlan,
36 HostLocation location, 32 HostLocation location,
37 SparseAnnotations... annotations) { 33 SparseAnnotations... annotations) {
38 - this(mac, vlan, location, new HashSet<IpPrefix>(), annotations); 34 + this(mac, vlan, location, null, annotations);
39 } 35 }
40 36
41 /** 37 /**
...@@ -44,17 +40,17 @@ public class DefaultHostDescription extends AbstractDescription ...@@ -44,17 +40,17 @@ public class DefaultHostDescription extends AbstractDescription
44 * @param mac host MAC address 40 * @param mac host MAC address
45 * @param vlan host VLAN identifier 41 * @param vlan host VLAN identifier
46 * @param location host location 42 * @param location host location
47 - * @param ips of host IP addresses 43 + * @param ip host IP address
48 * @param annotations optional key/value annotations map 44 * @param annotations optional key/value annotations map
49 */ 45 */
50 public DefaultHostDescription(MacAddress mac, VlanId vlan, 46 public DefaultHostDescription(MacAddress mac, VlanId vlan,
51 - HostLocation location, Set<IpPrefix> ips, 47 + HostLocation location, IpPrefix ip,
52 SparseAnnotations... annotations) { 48 SparseAnnotations... annotations) {
53 super(annotations); 49 super(annotations);
54 this.mac = mac; 50 this.mac = mac;
55 this.vlan = vlan; 51 this.vlan = vlan;
56 this.location = location; 52 this.location = location;
57 - this.ips = new HashSet<>(ips); 53 + this.ip = ip;
58 } 54 }
59 55
60 @Override 56 @Override
...@@ -73,8 +69,8 @@ public class DefaultHostDescription extends AbstractDescription ...@@ -73,8 +69,8 @@ public class DefaultHostDescription extends AbstractDescription
73 } 69 }
74 70
75 @Override 71 @Override
76 - public Set<IpPrefix> ipAddresses() { 72 + public IpPrefix ipAddress() {
77 - return ImmutableSet.copyOf(ips); 73 + return ip;
78 } 74 }
79 75
80 @Override 76 @Override
...@@ -83,7 +79,7 @@ public class DefaultHostDescription extends AbstractDescription ...@@ -83,7 +79,7 @@ public class DefaultHostDescription extends AbstractDescription
83 .add("mac", mac) 79 .add("mac", mac)
84 .add("vlan", vlan) 80 .add("vlan", vlan)
85 .add("location", location) 81 .add("location", location)
86 - .add("ipAddresses", ips) 82 + .add("ipAddress", ip)
87 .toString(); 83 .toString();
88 } 84 }
89 85
......
1 package org.onlab.onos.net.host; 1 package org.onlab.onos.net.host;
2 2
3 -import java.util.Set;
4 -
5 import org.onlab.onos.net.Description; 3 import org.onlab.onos.net.Description;
6 import org.onlab.onos.net.HostLocation; 4 import org.onlab.onos.net.HostLocation;
7 import org.onlab.packet.IpPrefix; 5 import org.onlab.packet.IpPrefix;
...@@ -35,10 +33,10 @@ public interface HostDescription extends Description { ...@@ -35,10 +33,10 @@ public interface HostDescription extends Description {
35 HostLocation location(); 33 HostLocation location();
36 34
37 /** 35 /**
38 - * Returns zero or more IP address(es) associated with this host's MAC. 36 + * Returns the IP address associated with this host's MAC.
39 * 37 *
40 - * @return a set of IP addresses. 38 + * @return host IP address
41 */ 39 */
42 - Set<IpPrefix> ipAddresses(); 40 + IpPrefix ipAddress();
43 41
44 } 42 }
......
1 package org.onlab.onos.net.intent; 1 package org.onlab.onos.net.intent;
2 2
3 +import java.util.concurrent.Future;
4 +
5 +import org.onlab.onos.net.flow.CompletedBatchOperation;
6 +
3 /** 7 /**
4 * Abstraction of entity capable of installing intents to the environment. 8 * Abstraction of entity capable of installing intents to the environment.
5 */ 9 */
...@@ -10,7 +14,7 @@ public interface IntentInstaller<T extends InstallableIntent> { ...@@ -10,7 +14,7 @@ public interface IntentInstaller<T extends InstallableIntent> {
10 * @param intent intent to be installed 14 * @param intent intent to be installed
11 * @throws IntentException if issues are encountered while installing the intent 15 * @throws IntentException if issues are encountered while installing the intent
12 */ 16 */
13 - void install(T intent); 17 + Future<CompletedBatchOperation> install(T intent);
14 18
15 /** 19 /**
16 * Uninstalls the specified intent from the environment. 20 * Uninstalls the specified intent from the environment.
...@@ -18,5 +22,5 @@ public interface IntentInstaller<T extends InstallableIntent> { ...@@ -18,5 +22,5 @@ public interface IntentInstaller<T extends InstallableIntent> {
18 * @param intent intent to be uninstalled 22 * @param intent intent to be uninstalled
19 * @throws IntentException if issues are encountered while uninstalling the intent 23 * @throws IntentException if issues are encountered while uninstalling the intent
20 */ 24 */
21 - void uninstall(T intent); 25 + Future<CompletedBatchOperation> uninstall(T intent);
22 } 26 }
......
...@@ -33,6 +33,8 @@ public interface IntentStore extends Store<IntentEvent, IntentStoreDelegate> { ...@@ -33,6 +33,8 @@ public interface IntentStore extends Store<IntentEvent, IntentStoreDelegate> {
33 33
34 /** 34 /**
35 * Returns the number of intents in the store. 35 * Returns the number of intents in the store.
36 + *
37 + * @return the number of intents in the store
36 */ 38 */
37 long getIntentCount(); 39 long getIntentCount();
38 40
...@@ -44,7 +46,7 @@ public interface IntentStore extends Store<IntentEvent, IntentStoreDelegate> { ...@@ -44,7 +46,7 @@ public interface IntentStore extends Store<IntentEvent, IntentStoreDelegate> {
44 Iterable<Intent> getIntents(); 46 Iterable<Intent> getIntents();
45 47
46 /** 48 /**
47 - * Returns the intent with the specified identifer. 49 + * Returns the intent with the specified identifier.
48 * 50 *
49 * @param intentId intent identification 51 * @param intentId intent identification
50 * @return intent or null if not found 52 * @return intent or null if not found
...@@ -94,7 +96,6 @@ public interface IntentStore extends Store<IntentEvent, IntentStoreDelegate> { ...@@ -94,7 +96,6 @@ public interface IntentStore extends Store<IntentEvent, IntentStoreDelegate> {
94 * specified original intent. 96 * specified original intent.
95 * 97 *
96 * @param intentId original intent identifier 98 * @param intentId original intent identifier
97 - * @return compiled state transition event
98 */ 99 */
99 void removeInstalledIntents(IntentId intentId); 100 void removeInstalledIntents(IntentId intentId);
100 101
......
...@@ -53,4 +53,4 @@ ...@@ -53,4 +53,4 @@
53 * while the system determines where to perform the compilation or while it 53 * while the system determines where to perform the compilation or while it
54 * performs global recomputation/optimization across all prior intents. 54 * performs global recomputation/optimization across all prior intents.
55 */ 55 */
56 -package org.onlab.onos.net.intent;
...\ No newline at end of file ...\ No newline at end of file
56 +package org.onlab.onos.net.intent;
......
1 package org.onlab.onos.store; 1 package org.onlab.onos.store;
2 2
3 +import java.util.List;
4 +
3 import org.onlab.onos.event.Event; 5 import org.onlab.onos.event.Event;
4 6
5 import static com.google.common.base.Preconditions.checkState; 7 import static com.google.common.base.Preconditions.checkState;
...@@ -41,4 +43,15 @@ public class AbstractStore<E extends Event, D extends StoreDelegate<E>> ...@@ -41,4 +43,15 @@ public class AbstractStore<E extends Event, D extends StoreDelegate<E>>
41 delegate.notify(event); 43 delegate.notify(event);
42 } 44 }
43 } 45 }
46 +
47 + /**
48 + * Notifies the delegate with the specified list of events.
49 + *
50 + * @param events list of events to delegate
51 + */
52 + protected void notifyDelegate(List<E> events) {
53 + for (E event: events) {
54 + notifyDelegate(event);
55 + }
56 + }
44 } 57 }
......
1 +package org.onlab.onos;
2 +
3 +import java.util.Objects;
4 +
5 +/**
6 + * Test application ID.
7 + */
8 +public class TestApplicationId implements ApplicationId {
9 +
10 + private final String name;
11 + private final short id;
12 +
13 + public TestApplicationId(String name) {
14 + this.name = name;
15 + this.id = (short) Objects.hash(name);
16 + }
17 +
18 + public static ApplicationId create(String name) {
19 + return new TestApplicationId(name);
20 + }
21 +
22 + @Override
23 + public short id() {
24 + return id;
25 + }
26 +
27 + @Override
28 + public String name() {
29 + return name;
30 + }
31 +}
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,19 +42,23 @@ public class AbstractEventAccumulatorTest { ...@@ -41,19 +42,23 @@ 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();
47 accumulator.add(new TestEvent(FOO, "a")); 49 accumulator.add(new TestEvent(FOO, "a"));
48 - delay(40); 50 + delay(30);
49 assertTrue("should not have fired yet", accumulator.batch.isEmpty()); 51 assertTrue("should not have fired yet", accumulator.batch.isEmpty());
50 accumulator.add(new TestEvent(FOO, "b")); 52 accumulator.add(new TestEvent(FOO, "b"));
51 - delay(40); 53 + delay(30);
52 assertTrue("should not have fired yet", accumulator.batch.isEmpty()); 54 assertTrue("should not have fired yet", accumulator.batch.isEmpty());
53 accumulator.add(new TestEvent(FOO, "c")); 55 accumulator.add(new TestEvent(FOO, "c"));
54 - delay(40); 56 + delay(30);
57 + assertTrue("should not have fired yet", accumulator.batch.isEmpty());
58 + accumulator.add(new TestEvent(FOO, "d"));
59 + delay(30);
55 assertFalse("should have fired", accumulator.batch.isEmpty()); 60 assertFalse("should have fired", accumulator.batch.isEmpty());
56 - assertEquals("incorrect batch", "abc", accumulator.batch); 61 + assertEquals("incorrect batch", "abcd", accumulator.batch);
57 } 62 }
58 63
59 @Test 64 @Test
......
...@@ -18,8 +18,8 @@ public class DefaultEdgeLinkTest { ...@@ -18,8 +18,8 @@ public class DefaultEdgeLinkTest {
18 18
19 private static final ProviderId PID = new ProviderId("of", "foo"); 19 private static final ProviderId PID = new ProviderId("of", "foo");
20 private static final DeviceId DID1 = deviceId("of:foo"); 20 private static final DeviceId DID1 = deviceId("of:foo");
21 - private static final HostId HID1 = hostId("nic:foobar"); 21 + private static final HostId HID1 = hostId("00:00:00:00:00:01/-1");
22 - private static final HostId HID2 = hostId("nic:barfoo"); 22 + private static final HostId HID2 = hostId("00:00:00:00:00:01/-1");
23 private static final PortNumber P0 = portNumber(0); 23 private static final PortNumber P0 = portNumber(0);
24 private static final PortNumber P1 = portNumber(1); 24 private static final PortNumber P1 = portNumber(1);
25 25
...@@ -35,12 +35,8 @@ public class DefaultEdgeLinkTest { ...@@ -35,12 +35,8 @@ public class DefaultEdgeLinkTest {
35 EdgeLink l4 = new DefaultEdgeLink(PID, cp(HID2, P0), 35 EdgeLink l4 = new DefaultEdgeLink(PID, cp(HID2, P0),
36 new HostLocation(DID1, P1, 123L), false); 36 new HostLocation(DID1, P1, 123L), false);
37 37
38 - EdgeLink l5 = new DefaultEdgeLink(PID, cp(HID1, P0),
39 - new HostLocation(DID1, P1, 123L), false);
40 -
41 new EqualsTester().addEqualityGroup(l1, l2) 38 new EqualsTester().addEqualityGroup(l1, l2)
42 .addEqualityGroup(l3, l4) 39 .addEqualityGroup(l3, l4)
43 - .addEqualityGroup(l5)
44 .testEquals(); 40 .testEquals();
45 } 41 }
46 42
......
...@@ -8,7 +8,7 @@ import static org.onlab.onos.net.DeviceId.deviceId; ...@@ -8,7 +8,7 @@ import static org.onlab.onos.net.DeviceId.deviceId;
8 /** 8 /**
9 * Test of the device identifier. 9 * Test of the device identifier.
10 */ 10 */
11 -public class DeviceIdTest extends ElementIdTest { 11 +public class DeviceIdTest {
12 12
13 @Test 13 @Test
14 public void basics() { 14 public void basics() {
......
1 -package org.onlab.onos.net;
2 -
3 -import com.google.common.testing.EqualsTester;
4 -import org.junit.Test;
5 -
6 -import java.net.URI;
7 -
8 -import static org.junit.Assert.assertEquals;
9 -
10 -/**
11 - * Test of the network element identifier.
12 - */
13 -public class ElementIdTest {
14 -
15 - private static class FooId extends ElementId {
16 - public FooId(URI uri) {
17 - super(uri);
18 - }
19 - }
20 -
21 - public static URI uri(String str) {
22 - return URI.create(str);
23 - }
24 -
25 - @Test
26 - public void basics() {
27 - new EqualsTester()
28 - .addEqualityGroup(new FooId(uri("of:foo")),
29 - new FooId(uri("of:foo")))
30 - .addEqualityGroup(new FooId(uri("of:bar")))
31 - .testEquals();
32 - assertEquals("wrong uri", uri("ofcfg:foo"),
33 - new FooId(uri("ofcfg:foo")).uri());
34 - }
35 -
36 -}
...@@ -11,20 +11,18 @@ import static org.onlab.onos.net.HostId.hostId; ...@@ -11,20 +11,18 @@ import static org.onlab.onos.net.HostId.hostId;
11 /** 11 /**
12 * Test for the host identifier. 12 * Test for the host identifier.
13 */ 13 */
14 -public class HostIdTest extends ElementIdTest { 14 +public class HostIdTest {
15 15
16 private static final MacAddress MAC1 = MacAddress.valueOf("00:11:00:00:00:01"); 16 private static final MacAddress MAC1 = MacAddress.valueOf("00:11:00:00:00:01");
17 private static final MacAddress MAC2 = MacAddress.valueOf("00:22:00:00:00:02"); 17 private static final MacAddress MAC2 = MacAddress.valueOf("00:22:00:00:00:02");
18 private static final VlanId VLAN1 = VlanId.vlanId((short) 11); 18 private static final VlanId VLAN1 = VlanId.vlanId((short) 11);
19 private static final VlanId VLAN2 = VlanId.vlanId((short) 22); 19 private static final VlanId VLAN2 = VlanId.vlanId((short) 22);
20 20
21 - @Override
22 @Test 21 @Test
23 public void basics() { 22 public void basics() {
24 new EqualsTester() 23 new EqualsTester()
25 - .addEqualityGroup(hostId("nic:00:11:00:00:00:01-11"), 24 + .addEqualityGroup(hostId(MAC1, VLAN1), hostId(MAC1, VLAN1))
26 - hostId(MAC1, VLAN1)) 25 + .addEqualityGroup(hostId(MAC2, VLAN2), hostId(MAC2, VLAN2))
27 - .addEqualityGroup(hostId(MAC2, VLAN2))
28 .testEquals(); 26 .testEquals();
29 } 27 }
30 28
......
...@@ -31,7 +31,7 @@ public final class NetTestTools { ...@@ -31,7 +31,7 @@ public final class NetTestTools {
31 31
32 // Short-hand for producing a host id from a string 32 // Short-hand for producing a host id from a string
33 public static HostId hid(String id) { 33 public static HostId hid(String id) {
34 - return hostId("nic:" + id); 34 + return hostId(id);
35 } 35 }
36 36
37 // Crates a new device with the specified id 37 // Crates a new device with the specified id
......
...@@ -10,9 +10,8 @@ import com.google.common.testing.EqualsTester; ...@@ -10,9 +10,8 @@ import com.google.common.testing.EqualsTester;
10 /** 10 /**
11 * Test of the port number. 11 * Test of the port number.
12 */ 12 */
13 -public class PortNumberTest extends ElementIdTest { 13 +public class PortNumberTest {
14 14
15 - @Override
16 @Test 15 @Test
17 public void basics() { 16 public void basics() {
18 new EqualsTester() 17 new EqualsTester()
......
1 package org.onlab.onos.net.host; 1 package org.onlab.onos.net.host;
2 2
3 -import static org.junit.Assert.assertEquals;
4 -import static org.junit.Assert.assertTrue;
5 -
6 -import java.util.Set;
7 -
8 import org.junit.Test; 3 import org.junit.Test;
9 import org.onlab.onos.net.DeviceId; 4 import org.onlab.onos.net.DeviceId;
10 import org.onlab.onos.net.HostLocation; 5 import org.onlab.onos.net.HostLocation;
...@@ -13,7 +8,8 @@ import org.onlab.packet.IpPrefix; ...@@ -13,7 +8,8 @@ import org.onlab.packet.IpPrefix;
13 import org.onlab.packet.MacAddress; 8 import org.onlab.packet.MacAddress;
14 import org.onlab.packet.VlanId; 9 import org.onlab.packet.VlanId;
15 10
16 -import com.google.common.collect.Sets; 11 +import static org.junit.Assert.assertEquals;
12 +import static org.junit.Assert.assertTrue;
17 13
18 /** 14 /**
19 * Test for the default host description. 15 * Test for the default host description.
...@@ -22,24 +18,22 @@ public class DefualtHostDecriptionTest { ...@@ -22,24 +18,22 @@ public class DefualtHostDecriptionTest {
22 18
23 private static final MacAddress MAC = MacAddress.valueOf("00:00:11:00:00:01"); 19 private static final MacAddress MAC = MacAddress.valueOf("00:00:11:00:00:01");
24 private static final VlanId VLAN = VlanId.vlanId((short) 10); 20 private static final VlanId VLAN = VlanId.vlanId((short) 10);
21 + private static final IpPrefix IP = IpPrefix.valueOf("10.0.0.1");
22 +
25 private static final HostLocation LOC = new HostLocation( 23 private static final HostLocation LOC = new HostLocation(
26 - DeviceId.deviceId("of:foo"), 24 + DeviceId.deviceId("of:foo"),
27 - PortNumber.portNumber(100), 25 + PortNumber.portNumber(100),
28 - 123L 26 + 123L
29 - ); 27 + );
30 - private static final Set<IpPrefix> IPS = Sets.newHashSet(
31 - IpPrefix.valueOf("10.0.0.1"),
32 - IpPrefix.valueOf("10.0.0.2")
33 - );
34 28
35 @Test 29 @Test
36 public void basics() { 30 public void basics() {
37 HostDescription host = 31 HostDescription host =
38 - new DefaultHostDescription(MAC, VLAN, LOC, IPS); 32 + new DefaultHostDescription(MAC, VLAN, LOC, IP);
39 assertEquals("incorrect mac", MAC, host.hwAddress()); 33 assertEquals("incorrect mac", MAC, host.hwAddress());
40 assertEquals("incorrect vlan", VLAN, host.vlan()); 34 assertEquals("incorrect vlan", VLAN, host.vlan());
41 assertEquals("incorrect location", LOC, host.location()); 35 assertEquals("incorrect location", LOC, host.location());
42 - assertTrue("incorrect ip's", IPS.equals(host.ipAddresses())); 36 + assertEquals("incorrect ip's", IP, host.ipAddress());
43 assertTrue("incorrect toString", host.toString().contains("vlan=10")); 37 assertTrue("incorrect toString", host.toString().contains("vlan=10"));
44 } 38 }
45 39
......
1 package org.onlab.onos.net.intent; 1 package org.onlab.onos.net.intent;
2 2
3 -import org.junit.After; 3 +import static org.junit.Assert.assertEquals;
4 -import org.junit.Before; 4 +import static org.junit.Assert.assertFalse;
5 -import org.junit.Test; 5 +import static org.junit.Assert.assertNull;
6 +import static org.junit.Assert.fail;
7 +import static org.onlab.onos.net.intent.IntentEvent.Type.FAILED;
8 +import static org.onlab.onos.net.intent.IntentEvent.Type.INSTALLED;
9 +import static org.onlab.onos.net.intent.IntentEvent.Type.SUBMITTED;
10 +import static org.onlab.onos.net.intent.IntentEvent.Type.WITHDRAWN;
6 11
7 import java.util.ArrayList; 12 import java.util.ArrayList;
8 import java.util.Arrays; 13 import java.util.Arrays;
9 import java.util.Collections; 14 import java.util.Collections;
10 import java.util.Iterator; 15 import java.util.Iterator;
11 import java.util.List; 16 import java.util.List;
17 +import java.util.concurrent.Future;
12 18
13 -import static org.junit.Assert.*; 19 +import org.junit.After;
14 -import static org.onlab.onos.net.intent.IntentEvent.Type.*; 20 +import org.junit.Before;
21 +import org.junit.Test;
22 +import org.onlab.onos.net.flow.CompletedBatchOperation;
15 23
16 /** 24 /**
17 * Suite of tests for the intent service contract. 25 * Suite of tests for the intent service contract.
...@@ -290,17 +298,19 @@ public class IntentServiceTest { ...@@ -290,17 +298,19 @@ public class IntentServiceTest {
290 } 298 }
291 299
292 @Override 300 @Override
293 - public void install(TestInstallableIntent intent) { 301 + public Future<CompletedBatchOperation> install(TestInstallableIntent intent) {
294 if (fail) { 302 if (fail) {
295 throw new IntentException("install failed by design"); 303 throw new IntentException("install failed by design");
296 } 304 }
305 + return null;
297 } 306 }
298 307
299 @Override 308 @Override
300 - public void uninstall(TestInstallableIntent intent) { 309 + public Future<CompletedBatchOperation> uninstall(TestInstallableIntent intent) {
301 if (fail) { 310 if (fail) {
302 throw new IntentException("remove failed by design"); 311 throw new IntentException("remove failed by design");
303 } 312 }
313 + return null;
304 } 314 }
305 } 315 }
306 316
......
1 -package org.onlab.onos.cluster.impl; 1 +package org.onlab.onos.impl;
2 2
3 import org.apache.felix.scr.annotations.Activate; 3 import org.apache.felix.scr.annotations.Activate;
4 import org.apache.felix.scr.annotations.Component; 4 import org.apache.felix.scr.annotations.Component;
5 import org.apache.felix.scr.annotations.Service; 5 import org.apache.felix.scr.annotations.Service;
6 +import org.onlab.onos.ApplicationId;
6 import org.onlab.onos.CoreService; 7 import org.onlab.onos.CoreService;
7 import org.onlab.onos.Version; 8 import org.onlab.onos.Version;
8 import org.onlab.util.Tools; 9 import org.onlab.util.Tools;
9 10
10 import java.io.File; 11 import java.io.File;
11 import java.util.List; 12 import java.util.List;
13 +import java.util.Map;
14 +import java.util.concurrent.ConcurrentHashMap;
15 +import java.util.concurrent.atomic.AtomicInteger;
12 16
13 /** 17 /**
14 * Core service implementation. 18 * Core service implementation.
...@@ -17,9 +21,13 @@ import java.util.List; ...@@ -17,9 +21,13 @@ import java.util.List;
17 @Service 21 @Service
18 public class CoreManager implements CoreService { 22 public class CoreManager implements CoreService {
19 23
24 + private static final AtomicInteger ID_DISPENSER = new AtomicInteger(1);
25 +
20 private static final File VERSION_FILE = new File("../VERSION"); 26 private static final File VERSION_FILE = new File("../VERSION");
21 private static Version version = Version.version("1.0.0-SNAPSHOT"); 27 private static Version version = Version.version("1.0.0-SNAPSHOT");
22 28
29 + private final Map<Short, DefaultApplicationId> appIds = new ConcurrentHashMap<>();
30 +
23 // TODO: work in progress 31 // TODO: work in progress
24 32
25 @Activate 33 @Activate
...@@ -35,4 +43,17 @@ public class CoreManager implements CoreService { ...@@ -35,4 +43,17 @@ public class CoreManager implements CoreService {
35 return version; 43 return version;
36 } 44 }
37 45
46 + @Override
47 + public ApplicationId getAppId(Short id) {
48 + return appIds.get(id);
49 + }
50 +
51 + @Override
52 + public ApplicationId registerApplication(String name) {
53 + short id = (short) ID_DISPENSER.getAndIncrement();
54 + DefaultApplicationId appId = new DefaultApplicationId(id, name);
55 + appIds.put(id, appId);
56 + return appId;
57 + }
58 +
38 } 59 }
......
1 +package org.onlab.onos.impl;
2 +
3 +import org.onlab.onos.ApplicationId;
4 +
5 +import java.util.Objects;
6 +
7 +import static com.google.common.base.MoreObjects.toStringHelper;
8 +
9 +/**
10 + * Application id generator class.
11 + */
12 +public class DefaultApplicationId implements ApplicationId {
13 +
14 + private final short id;
15 + private final String name;
16 +
17 + // Ban public construction
18 + protected DefaultApplicationId(Short id, String identifier) {
19 + this.id = id;
20 + this.name = identifier;
21 + }
22 +
23 + @Override
24 + public short id() {
25 + return id;
26 + }
27 +
28 + @Override
29 + public String name() {
30 + return name;
31 + }
32 +
33 + @Override
34 + public int hashCode() {
35 + return Objects.hash(id);
36 + }
37 +
38 + @Override
39 + public boolean equals(Object obj) {
40 + if (this == obj) {
41 + return true;
42 + }
43 + if (obj instanceof DefaultApplicationId) {
44 + DefaultApplicationId other = (DefaultApplicationId) obj;
45 + return Objects.equals(this.id, other.id);
46 + }
47 + return false;
48 + }
49 +
50 + @Override
51 + public String toString() {
52 + return toStringHelper(this).add("id", id).add("name", name).toString();
53 + }
54 +
55 +}
1 +/**
2 + *
3 + */
4 +package org.onlab.onos.impl;
...\ No newline at end of file ...\ No newline at end of file
...@@ -5,10 +5,12 @@ import static org.slf4j.LoggerFactory.getLogger; ...@@ -5,10 +5,12 @@ import static org.slf4j.LoggerFactory.getLogger;
5 5
6 import java.util.Iterator; 6 import java.util.Iterator;
7 import java.util.List; 7 import java.util.List;
8 +import java.util.concurrent.CancellationException;
8 import java.util.concurrent.ExecutionException; 9 import java.util.concurrent.ExecutionException;
9 import java.util.concurrent.Future; 10 import java.util.concurrent.Future;
10 import java.util.concurrent.TimeUnit; 11 import java.util.concurrent.TimeUnit;
11 import java.util.concurrent.TimeoutException; 12 import java.util.concurrent.TimeoutException;
13 +import java.util.concurrent.atomic.AtomicReference;
12 14
13 import org.apache.felix.scr.annotations.Activate; 15 import org.apache.felix.scr.annotations.Activate;
14 import org.apache.felix.scr.annotations.Component; 16 import org.apache.felix.scr.annotations.Component;
...@@ -26,6 +28,7 @@ import org.onlab.onos.net.flow.CompletedBatchOperation; ...@@ -26,6 +28,7 @@ import org.onlab.onos.net.flow.CompletedBatchOperation;
26 import org.onlab.onos.net.flow.FlowEntry; 28 import org.onlab.onos.net.flow.FlowEntry;
27 import org.onlab.onos.net.flow.FlowRule; 29 import org.onlab.onos.net.flow.FlowRule;
28 import org.onlab.onos.net.flow.FlowRuleBatchEntry; 30 import org.onlab.onos.net.flow.FlowRuleBatchEntry;
31 +import org.onlab.onos.net.flow.FlowRuleBatchEntry.FlowRuleOperation;
29 import org.onlab.onos.net.flow.FlowRuleBatchOperation; 32 import org.onlab.onos.net.flow.FlowRuleBatchOperation;
30 import org.onlab.onos.net.flow.FlowRuleEvent; 33 import org.onlab.onos.net.flow.FlowRuleEvent;
31 import org.onlab.onos.net.flow.FlowRuleListener; 34 import org.onlab.onos.net.flow.FlowRuleListener;
...@@ -52,6 +55,8 @@ public class FlowRuleManager ...@@ -52,6 +55,8 @@ public class FlowRuleManager
52 extends AbstractProviderRegistry<FlowRuleProvider, FlowRuleProviderService> 55 extends AbstractProviderRegistry<FlowRuleProvider, FlowRuleProviderService>
53 implements FlowRuleService, FlowRuleProviderRegistry { 56 implements FlowRuleService, FlowRuleProviderRegistry {
54 57
58 + enum BatchState { STARTED, FINISHED, CANCELLED };
59 +
55 public static final String FLOW_RULE_NULL = "FlowRule cannot be null"; 60 public static final String FLOW_RULE_NULL = "FlowRule cannot be null";
56 private final Logger log = getLogger(getClass()); 61 private final Logger log = getLogger(getClass());
57 62
...@@ -144,7 +149,7 @@ public class FlowRuleManager ...@@ -144,7 +149,7 @@ public class FlowRuleManager
144 FlowRuleBatchOperation batch) { 149 FlowRuleBatchOperation batch) {
145 Multimap<FlowRuleProvider, FlowRuleBatchEntry> batches = 150 Multimap<FlowRuleProvider, FlowRuleBatchEntry> batches =
146 ArrayListMultimap.create(); 151 ArrayListMultimap.create();
147 - List<Future<Void>> futures = Lists.newArrayList(); 152 + List<Future<CompletedBatchOperation>> futures = Lists.newArrayList();
148 for (FlowRuleBatchEntry fbe : batch.getOperations()) { 153 for (FlowRuleBatchEntry fbe : batch.getOperations()) {
149 final FlowRule f = fbe.getTarget(); 154 final FlowRule f = fbe.getTarget();
150 final Device device = deviceService.getDevice(f.deviceId()); 155 final Device device = deviceService.getDevice(f.deviceId());
...@@ -165,10 +170,10 @@ public class FlowRuleManager ...@@ -165,10 +170,10 @@ public class FlowRuleManager
165 for (FlowRuleProvider provider : batches.keySet()) { 170 for (FlowRuleProvider provider : batches.keySet()) {
166 FlowRuleBatchOperation b = 171 FlowRuleBatchOperation b =
167 new FlowRuleBatchOperation(batches.get(provider)); 172 new FlowRuleBatchOperation(batches.get(provider));
168 - Future<Void> future = provider.executeBatch(b); 173 + Future<CompletedBatchOperation> future = provider.executeBatch(b);
169 futures.add(future); 174 futures.add(future);
170 } 175 }
171 - return new FlowRuleBatchFuture(futures); 176 + return new FlowRuleBatchFuture(futures, batches);
172 } 177 }
173 178
174 @Override 179 @Override
...@@ -341,59 +346,140 @@ public class FlowRuleManager ...@@ -341,59 +346,140 @@ public class FlowRuleManager
341 private class FlowRuleBatchFuture 346 private class FlowRuleBatchFuture
342 implements Future<CompletedBatchOperation> { 347 implements Future<CompletedBatchOperation> {
343 348
344 - private final List<Future<Void>> futures; 349 + private final List<Future<CompletedBatchOperation>> futures;
350 + private final Multimap<FlowRuleProvider, FlowRuleBatchEntry> batches;
351 + private final AtomicReference<BatchState> state;
352 + private CompletedBatchOperation overall;
353 +
354 +
345 355
346 - public FlowRuleBatchFuture(List<Future<Void>> futures) { 356 + public FlowRuleBatchFuture(List<Future<CompletedBatchOperation>> futures,
357 + Multimap<FlowRuleProvider, FlowRuleBatchEntry> batches) {
347 this.futures = futures; 358 this.futures = futures;
359 + this.batches = batches;
360 + state = new AtomicReference<FlowRuleManager.BatchState>();
361 + state.set(BatchState.STARTED);
348 } 362 }
349 363
350 @Override 364 @Override
351 public boolean cancel(boolean mayInterruptIfRunning) { 365 public boolean cancel(boolean mayInterruptIfRunning) {
352 - // TODO Auto-generated method stub 366 + if (state.get() == BatchState.FINISHED) {
353 - return false; 367 + return false;
368 + }
369 + if (!state.compareAndSet(BatchState.STARTED, BatchState.CANCELLED)) {
370 + return false;
371 + }
372 + cleanUpBatch();
373 + for (Future<CompletedBatchOperation> f : futures) {
374 + f.cancel(mayInterruptIfRunning);
375 + }
376 + return true;
354 } 377 }
355 378
356 @Override 379 @Override
357 public boolean isCancelled() { 380 public boolean isCancelled() {
358 - // TODO Auto-generated method stub 381 + return state.get() == BatchState.CANCELLED;
359 - return false;
360 } 382 }
361 383
362 @Override 384 @Override
363 public boolean isDone() { 385 public boolean isDone() {
364 - boolean isDone = true; 386 + return state.get() == BatchState.FINISHED;
365 - for (Future<Void> future : futures) {
366 - isDone &= future.isDone();
367 - }
368 - return isDone;
369 } 387 }
370 388
389 +
371 @Override 390 @Override
372 public CompletedBatchOperation get() throws InterruptedException, 391 public CompletedBatchOperation get() throws InterruptedException,
373 - ExecutionException { 392 + ExecutionException {
374 - // TODO Auto-generated method stub 393 +
375 - for (Future<Void> future : futures) { 394 + if (isDone()) {
376 - future.get(); 395 + return overall;
396 + }
397 +
398 + boolean success = true;
399 + List<FlowEntry> failed = Lists.newLinkedList();
400 + CompletedBatchOperation completed;
401 + for (Future<CompletedBatchOperation> future : futures) {
402 + completed = future.get();
403 + success = validateBatchOperation(failed, completed, future);
377 } 404 }
378 - return new CompletedBatchOperation(); 405 +
406 + return finalizeBatchOperation(success, failed);
407 +
379 } 408 }
380 409
381 @Override 410 @Override
382 public CompletedBatchOperation get(long timeout, TimeUnit unit) 411 public CompletedBatchOperation get(long timeout, TimeUnit unit)
383 throws InterruptedException, ExecutionException, 412 throws InterruptedException, ExecutionException,
384 TimeoutException { 413 TimeoutException {
385 - // TODO we should decrement the timeout 414 +
415 + if (isDone()) {
416 + return overall;
417 + }
418 + boolean success = true;
419 + List<FlowEntry> failed = Lists.newLinkedList();
420 + CompletedBatchOperation completed;
386 long start = System.nanoTime(); 421 long start = System.nanoTime();
387 long end = start + unit.toNanos(timeout); 422 long end = start + unit.toNanos(timeout);
388 - for (Future<Void> future : futures) { 423 +
424 + for (Future<CompletedBatchOperation> future : futures) {
389 long now = System.nanoTime(); 425 long now = System.nanoTime();
390 long thisTimeout = end - now; 426 long thisTimeout = end - now;
391 - future.get(thisTimeout, TimeUnit.NANOSECONDS); 427 + completed = future.get(thisTimeout, TimeUnit.NANOSECONDS);
428 + success = validateBatchOperation(failed, completed, future);
392 } 429 }
393 - return new CompletedBatchOperation(); 430 + return finalizeBatchOperation(success, failed);
394 } 431 }
395 432
433 + private boolean validateBatchOperation(List<FlowEntry> failed,
434 + CompletedBatchOperation completed,
435 + Future<CompletedBatchOperation> future) {
436 +
437 + if (isCancelled()) {
438 + throw new CancellationException();
439 + }
440 + if (!completed.isSuccess()) {
441 + failed.addAll(completed.failedItems());
442 + cleanUpBatch();
443 + cancelAllSubBatches();
444 + return false;
445 + }
446 + return true;
447 + }
448 +
449 + private void cancelAllSubBatches() {
450 + for (Future<CompletedBatchOperation> f : futures) {
451 + f.cancel(true);
452 + }
453 + }
454 +
455 + private CompletedBatchOperation finalizeBatchOperation(boolean success,
456 + List<FlowEntry> failed) {
457 + synchronized (this) {
458 + if (!state.compareAndSet(BatchState.STARTED, BatchState.FINISHED)) {
459 + if (state.get() == BatchState.FINISHED) {
460 + return overall;
461 + }
462 + throw new CancellationException();
463 + }
464 + overall = new CompletedBatchOperation(success, failed);
465 + return overall;
466 + }
467 + }
468 +
469 + private void cleanUpBatch() {
470 + for (FlowRuleBatchEntry fbe : batches.values()) {
471 + if (fbe.getOperator() == FlowRuleOperation.ADD ||
472 + fbe.getOperator() == FlowRuleOperation.MODIFY) {
473 + store.deleteFlowRule(fbe.getTarget());
474 + } else if (fbe.getOperator() == FlowRuleOperation.REMOVE) {
475 + store.storeFlowRule(fbe.getTarget());
476 + }
477 + }
478 +
479 + }
396 } 480 }
397 481
398 482
483 +
484 +
399 } 485 }
......
...@@ -168,7 +168,6 @@ public class HostManager ...@@ -168,7 +168,6 @@ public class HostManager
168 checkNotNull(hostId, HOST_ID_NULL); 168 checkNotNull(hostId, HOST_ID_NULL);
169 HostEvent event = store.removeHost(hostId); 169 HostEvent event = store.removeHost(hostId);
170 if (event != null) { 170 if (event != null) {
171 - log.info("Host {} administratively removed", hostId);
172 post(event); 171 post(event);
173 } 172 }
174 } 173 }
...@@ -214,7 +213,6 @@ public class HostManager ...@@ -214,7 +213,6 @@ public class HostManager
214 HostEvent event = store.createOrUpdateHost(provider().id(), hostId, 213 HostEvent event = store.createOrUpdateHost(provider().id(), hostId,
215 hostDescription); 214 hostDescription);
216 if (event != null) { 215 if (event != null) {
217 - log.debug("Host {} detected", hostId);
218 post(event); 216 post(event);
219 } 217 }
220 } 218 }
...@@ -225,7 +223,6 @@ public class HostManager ...@@ -225,7 +223,6 @@ public class HostManager
225 checkValidity(); 223 checkValidity();
226 HostEvent event = store.removeHost(hostId); 224 HostEvent event = store.removeHost(hostId);
227 if (event != null) { 225 if (event != null) {
228 - log.debug("Host {} vanished", hostId);
229 post(event); 226 post(event);
230 } 227 }
231 } 228 }
......
...@@ -13,12 +13,17 @@ import static org.onlab.util.Tools.namedThreads; ...@@ -13,12 +13,17 @@ import static org.onlab.util.Tools.namedThreads;
13 import static org.slf4j.LoggerFactory.getLogger; 13 import static org.slf4j.LoggerFactory.getLogger;
14 14
15 import java.util.ArrayList; 15 import java.util.ArrayList;
16 +import java.util.Iterator;
16 import java.util.List; 17 import java.util.List;
17 import java.util.Map; 18 import java.util.Map;
18 import java.util.Objects; 19 import java.util.Objects;
19 import java.util.concurrent.ConcurrentHashMap; 20 import java.util.concurrent.ConcurrentHashMap;
20 import java.util.concurrent.ConcurrentMap; 21 import java.util.concurrent.ConcurrentMap;
22 +import java.util.concurrent.ExecutionException;
21 import java.util.concurrent.ExecutorService; 23 import java.util.concurrent.ExecutorService;
24 +import java.util.concurrent.Future;
25 +import java.util.concurrent.TimeUnit;
26 +import java.util.concurrent.TimeoutException;
22 27
23 import org.apache.felix.scr.annotations.Activate; 28 import org.apache.felix.scr.annotations.Activate;
24 import org.apache.felix.scr.annotations.Component; 29 import org.apache.felix.scr.annotations.Component;
...@@ -28,6 +33,7 @@ import org.apache.felix.scr.annotations.ReferenceCardinality; ...@@ -28,6 +33,7 @@ import org.apache.felix.scr.annotations.ReferenceCardinality;
28 import org.apache.felix.scr.annotations.Service; 33 import org.apache.felix.scr.annotations.Service;
29 import org.onlab.onos.event.AbstractListenerRegistry; 34 import org.onlab.onos.event.AbstractListenerRegistry;
30 import org.onlab.onos.event.EventDeliveryService; 35 import org.onlab.onos.event.EventDeliveryService;
36 +import org.onlab.onos.net.flow.CompletedBatchOperation;
31 import org.onlab.onos.net.intent.InstallableIntent; 37 import org.onlab.onos.net.intent.InstallableIntent;
32 import org.onlab.onos.net.intent.Intent; 38 import org.onlab.onos.net.intent.Intent;
33 import org.onlab.onos.net.intent.IntentCompiler; 39 import org.onlab.onos.net.intent.IntentCompiler;
...@@ -44,7 +50,9 @@ import org.onlab.onos.net.intent.IntentStore; ...@@ -44,7 +50,9 @@ import org.onlab.onos.net.intent.IntentStore;
44 import org.onlab.onos.net.intent.IntentStoreDelegate; 50 import org.onlab.onos.net.intent.IntentStoreDelegate;
45 import org.slf4j.Logger; 51 import org.slf4j.Logger;
46 52
53 +import com.google.common.collect.ImmutableList;
47 import com.google.common.collect.ImmutableMap; 54 import com.google.common.collect.ImmutableMap;
55 +import com.google.common.collect.Lists;
48 56
49 /** 57 /**
50 * An implementation of Intent Manager. 58 * An implementation of Intent Manager.
...@@ -67,7 +75,8 @@ public class IntentManager ...@@ -67,7 +75,8 @@ public class IntentManager
67 private final AbstractListenerRegistry<IntentEvent, IntentListener> 75 private final AbstractListenerRegistry<IntentEvent, IntentListener>
68 listenerRegistry = new AbstractListenerRegistry<>(); 76 listenerRegistry = new AbstractListenerRegistry<>();
69 77
70 - private final ExecutorService executor = newSingleThreadExecutor(namedThreads("onos-intents")); 78 + private ExecutorService executor;
79 + private ExecutorService monitorExecutor;
71 80
72 private final IntentStoreDelegate delegate = new InternalStoreDelegate(); 81 private final IntentStoreDelegate delegate = new InternalStoreDelegate();
73 private final TopologyChangeDelegate topoDelegate = new InternalTopoChangeDelegate(); 82 private final TopologyChangeDelegate topoDelegate = new InternalTopoChangeDelegate();
...@@ -86,6 +95,8 @@ public class IntentManager ...@@ -86,6 +95,8 @@ public class IntentManager
86 store.setDelegate(delegate); 95 store.setDelegate(delegate);
87 trackerService.setDelegate(topoDelegate); 96 trackerService.setDelegate(topoDelegate);
88 eventDispatcher.addSink(IntentEvent.class, listenerRegistry); 97 eventDispatcher.addSink(IntentEvent.class, listenerRegistry);
98 + executor = newSingleThreadExecutor(namedThreads("onos-intents"));
99 + monitorExecutor = newSingleThreadExecutor(namedThreads("onos-intent-monitor"));
89 log.info("Started"); 100 log.info("Started");
90 } 101 }
91 102
...@@ -94,6 +105,8 @@ public class IntentManager ...@@ -94,6 +105,8 @@ public class IntentManager
94 store.unsetDelegate(delegate); 105 store.unsetDelegate(delegate);
95 trackerService.unsetDelegate(topoDelegate); 106 trackerService.unsetDelegate(topoDelegate);
96 eventDispatcher.removeSink(IntentEvent.class); 107 eventDispatcher.removeSink(IntentEvent.class);
108 + executor.shutdown();
109 + monitorExecutor.shutdown();
97 log.info("Stopped"); 110 log.info("Stopped");
98 } 111 }
99 112
...@@ -240,14 +253,23 @@ public class IntentManager ...@@ -240,14 +253,23 @@ public class IntentManager
240 } 253 }
241 } 254 }
242 255
243 - // FIXME: To make SDN-IP workable ASAP, only single level compilation is implemented 256 + /**
244 - // TODO: implement compilation traversing tree structure 257 + * Compiles an intent recursively.
258 + *
259 + * @param intent intent
260 + * @return result of compilation
261 + */
245 private List<InstallableIntent> compileIntent(Intent intent) { 262 private List<InstallableIntent> compileIntent(Intent intent) {
263 + if (intent instanceof InstallableIntent) {
264 + return ImmutableList.of((InstallableIntent) intent);
265 + }
266 +
246 List<InstallableIntent> installable = new ArrayList<>(); 267 List<InstallableIntent> installable = new ArrayList<>();
268 + // TODO do we need to registerSubclassCompiler?
247 for (Intent compiled : getCompiler(intent).compile(intent)) { 269 for (Intent compiled : getCompiler(intent).compile(intent)) {
248 - InstallableIntent installableIntent = (InstallableIntent) compiled; 270 + installable.addAll(compileIntent(compiled));
249 - installable.add(installableIntent);
250 } 271 }
272 +
251 return installable; 273 return installable;
252 } 274 }
253 275
...@@ -261,6 +283,7 @@ public class IntentManager ...@@ -261,6 +283,7 @@ public class IntentManager
261 // Indicate that the intent is entering the installing phase. 283 // Indicate that the intent is entering the installing phase.
262 store.setState(intent, INSTALLING); 284 store.setState(intent, INSTALLING);
263 285
286 + List<Future<CompletedBatchOperation>> installFutures = Lists.newArrayList();
264 try { 287 try {
265 List<InstallableIntent> installables = store.getInstallableIntents(intent.id()); 288 List<InstallableIntent> installables = store.getInstallableIntents(intent.id());
266 if (installables != null) { 289 if (installables != null) {
...@@ -268,17 +291,20 @@ public class IntentManager ...@@ -268,17 +291,20 @@ public class IntentManager
268 registerSubclassInstallerIfNeeded(installable); 291 registerSubclassInstallerIfNeeded(installable);
269 trackerService.addTrackedResources(intent.id(), 292 trackerService.addTrackedResources(intent.id(),
270 installable.requiredLinks()); 293 installable.requiredLinks());
271 - getInstaller(installable).install(installable); 294 + Future<CompletedBatchOperation> future = getInstaller(installable).install(installable);
295 + installFutures.add(future);
272 } 296 }
273 } 297 }
274 - eventDispatcher.post(store.setState(intent, INSTALLED)); 298 + // FIXME we have to wait for the installable intents
275 - 299 + //eventDispatcher.post(store.setState(intent, INSTALLED));
300 + monitorExecutor.execute(new IntentInstallMonitor(intent, installFutures, INSTALLED));
276 } catch (Exception e) { 301 } catch (Exception e) {
277 log.warn("Unable to install intent {} due to: {}", intent.id(), e); 302 log.warn("Unable to install intent {} due to: {}", intent.id(), e);
278 - uninstallIntent(intent); 303 + uninstallIntent(intent, RECOMPILING);
279 304
280 // If compilation failed, kick off the recompiling phase. 305 // If compilation failed, kick off the recompiling phase.
281 - executeRecompilingPhase(intent); 306 + // FIXME
307 + //executeRecompilingPhase(intent);
282 } 308 }
283 } 309 }
284 310
...@@ -327,12 +353,14 @@ public class IntentManager ...@@ -327,12 +353,14 @@ public class IntentManager
327 private void executeWithdrawingPhase(Intent intent) { 353 private void executeWithdrawingPhase(Intent intent) {
328 // Indicate that the intent is being withdrawn. 354 // Indicate that the intent is being withdrawn.
329 store.setState(intent, WITHDRAWING); 355 store.setState(intent, WITHDRAWING);
330 - uninstallIntent(intent); 356 + uninstallIntent(intent, WITHDRAWN);
331 357
332 // If all went well, disassociate the top-level intent with its 358 // If all went well, disassociate the top-level intent with its
333 // installable derivatives and mark it as withdrawn. 359 // installable derivatives and mark it as withdrawn.
334 - store.removeInstalledIntents(intent.id()); 360 + // FIXME need to clean up
335 - eventDispatcher.post(store.setState(intent, WITHDRAWN)); 361 + //store.removeInstalledIntents(intent.id());
362 + // FIXME
363 + //eventDispatcher.post(store.setState(intent, WITHDRAWN));
336 } 364 }
337 365
338 /** 366 /**
...@@ -340,14 +368,17 @@ public class IntentManager ...@@ -340,14 +368,17 @@ public class IntentManager
340 * 368 *
341 * @param intent intent to be uninstalled 369 * @param intent intent to be uninstalled
342 */ 370 */
343 - private void uninstallIntent(Intent intent) { 371 + private void uninstallIntent(Intent intent, IntentState nextState) {
372 + List<Future<CompletedBatchOperation>> uninstallFutures = Lists.newArrayList();
344 try { 373 try {
345 List<InstallableIntent> installables = store.getInstallableIntents(intent.id()); 374 List<InstallableIntent> installables = store.getInstallableIntents(intent.id());
346 if (installables != null) { 375 if (installables != null) {
347 for (InstallableIntent installable : installables) { 376 for (InstallableIntent installable : installables) {
348 - getInstaller(installable).uninstall(installable); 377 + Future<CompletedBatchOperation> future = getInstaller(installable).uninstall(installable);
378 + uninstallFutures.add(future);
349 } 379 }
350 } 380 }
381 + monitorExecutor.execute(new IntentInstallMonitor(intent, uninstallFutures, nextState));
351 } catch (IntentException e) { 382 } catch (IntentException e) {
352 log.warn("Unable to uninstall intent {} due to: {}", intent.id(), e); 383 log.warn("Unable to uninstall intent {} due to: {}", intent.id(), e);
353 } 384 }
...@@ -422,9 +453,10 @@ public class IntentManager ...@@ -422,9 +453,10 @@ public class IntentManager
422 // Attempt recompilation of the specified intents first. 453 // Attempt recompilation of the specified intents first.
423 for (IntentId intentId : intentIds) { 454 for (IntentId intentId : intentIds) {
424 Intent intent = getIntent(intentId); 455 Intent intent = getIntent(intentId);
425 - uninstallIntent(intent); 456 + uninstallIntent(intent, RECOMPILING);
426 457
427 - executeRecompilingPhase(intent); 458 + //FIXME
459 + //executeRecompilingPhase(intent);
428 } 460 }
429 461
430 if (compileAllFailed) { 462 if (compileAllFailed) {
...@@ -460,4 +492,49 @@ public class IntentManager ...@@ -460,4 +492,49 @@ public class IntentManager
460 } 492 }
461 } 493 }
462 494
495 + private class IntentInstallMonitor implements Runnable {
496 +
497 + private final Intent intent;
498 + private final List<Future<CompletedBatchOperation>> futures;
499 + private final IntentState nextState;
500 +
501 + public IntentInstallMonitor(Intent intent,
502 + List<Future<CompletedBatchOperation>> futures, IntentState nextState) {
503 + this.intent = intent;
504 + this.futures = futures;
505 + this.nextState = nextState;
506 + }
507 +
508 + private void updateIntent(Intent intent) {
509 + if (nextState == RECOMPILING) {
510 + executor.execute(new IntentTask(nextState, intent));
511 + } else if (nextState == INSTALLED || nextState == WITHDRAWN) {
512 + eventDispatcher.post(store.setState(intent, nextState));
513 + } else {
514 + log.warn("Invalid next intent state {} for intent {}", nextState, intent);
515 + }
516 + }
517 +
518 + @Override
519 + public void run() {
520 + for (Iterator<Future<CompletedBatchOperation>> i = futures.iterator(); i.hasNext();) {
521 + Future<CompletedBatchOperation> future = i.next();
522 + try {
523 + // TODO: we may want to get the future here and go back to the future.
524 + CompletedBatchOperation completed = future.get(100, TimeUnit.NANOSECONDS);
525 + // TODO check if future succeeded and if not report fail items
526 + i.remove();
527 +
528 + } catch (TimeoutException | InterruptedException | ExecutionException te) {
529 + log.debug("Intallations of intent {} is still pending", intent);
530 + }
531 + }
532 + if (futures.isEmpty()) {
533 + updateIntent(intent);
534 + } else {
535 + // resubmit ourselves if we are not done yet
536 + monitorExecutor.submit(this);
537 + }
538 + }
539 + }
463 } 540 }
......
...@@ -5,7 +5,7 @@ import static org.slf4j.LoggerFactory.getLogger; ...@@ -5,7 +5,7 @@ import static org.slf4j.LoggerFactory.getLogger;
5 5
6 import java.util.Iterator; 6 import java.util.Iterator;
7 import java.util.List; 7 import java.util.List;
8 -import java.util.concurrent.ExecutionException; 8 +import java.util.concurrent.Future;
9 9
10 import org.apache.felix.scr.annotations.Activate; 10 import org.apache.felix.scr.annotations.Activate;
11 import org.apache.felix.scr.annotations.Component; 11 import org.apache.felix.scr.annotations.Component;
...@@ -13,8 +13,10 @@ import org.apache.felix.scr.annotations.Deactivate; ...@@ -13,8 +13,10 @@ import org.apache.felix.scr.annotations.Deactivate;
13 import org.apache.felix.scr.annotations.Reference; 13 import org.apache.felix.scr.annotations.Reference;
14 import org.apache.felix.scr.annotations.ReferenceCardinality; 14 import org.apache.felix.scr.annotations.ReferenceCardinality;
15 import org.onlab.onos.ApplicationId; 15 import org.onlab.onos.ApplicationId;
16 +import org.onlab.onos.CoreService;
16 import org.onlab.onos.net.ConnectPoint; 17 import org.onlab.onos.net.ConnectPoint;
17 import org.onlab.onos.net.Link; 18 import org.onlab.onos.net.Link;
19 +import org.onlab.onos.net.flow.CompletedBatchOperation;
18 import org.onlab.onos.net.flow.DefaultFlowRule; 20 import org.onlab.onos.net.flow.DefaultFlowRule;
19 import org.onlab.onos.net.flow.DefaultTrafficSelector; 21 import org.onlab.onos.net.flow.DefaultTrafficSelector;
20 import org.onlab.onos.net.flow.FlowRule; 22 import org.onlab.onos.net.flow.FlowRule;
...@@ -45,10 +47,14 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> { ...@@ -45,10 +47,14 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> {
45 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 47 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
46 protected FlowRuleService flowRuleService; 48 protected FlowRuleService flowRuleService;
47 49
48 - private final ApplicationId appId = ApplicationId.getAppId(); 50 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
51 + protected CoreService coreService;
52 +
53 + private ApplicationId appId;
49 54
50 @Activate 55 @Activate
51 public void activate() { 56 public void activate() {
57 + appId = coreService.registerApplication("org.onlab.onos.net.intent");
52 intentManager.registerInstaller(PathIntent.class, this); 58 intentManager.registerInstaller(PathIntent.class, this);
53 } 59 }
54 60
...@@ -57,8 +63,26 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> { ...@@ -57,8 +63,26 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> {
57 intentManager.unregisterInstaller(PathIntent.class); 63 intentManager.unregisterInstaller(PathIntent.class);
58 } 64 }
59 65
66 + /**
67 + * Apply a list of FlowRules.
68 + *
69 + * @param rules rules to apply
70 + */
71 + private Future<CompletedBatchOperation> applyBatch(List<FlowRuleBatchEntry> rules) {
72 + FlowRuleBatchOperation batch = new FlowRuleBatchOperation(rules);
73 + Future<CompletedBatchOperation> future = flowRuleService.applyBatch(batch);
74 + return future;
75 +// try {
76 +// //FIXME don't do this here
77 +// future.get();
78 +// } catch (InterruptedException | ExecutionException e) {
79 +// // TODO Auto-generated catch block
80 +// e.printStackTrace();
81 +// }
82 + }
83 +
60 @Override 84 @Override
61 - public void install(PathIntent intent) { 85 + public Future<CompletedBatchOperation> install(PathIntent intent) {
62 TrafficSelector.Builder builder = 86 TrafficSelector.Builder builder =
63 DefaultTrafficSelector.builder(intent.selector()); 87 DefaultTrafficSelector.builder(intent.selector());
64 Iterator<Link> links = intent.path().links().iterator(); 88 Iterator<Link> links = intent.path().links().iterator();
...@@ -74,20 +98,14 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> { ...@@ -74,20 +98,14 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> {
74 builder.build(), treatment, 98 builder.build(), treatment,
75 123, appId, 600); 99 123, appId, 600);
76 rules.add(new FlowRuleBatchEntry(FlowRuleOperation.ADD, rule)); 100 rules.add(new FlowRuleBatchEntry(FlowRuleOperation.ADD, rule));
77 - //flowRuleService.applyFlowRules(rule);
78 prev = link.dst(); 101 prev = link.dst();
79 } 102 }
80 - FlowRuleBatchOperation batch = new FlowRuleBatchOperation(rules); 103 +
81 - try { 104 + return applyBatch(rules);
82 - flowRuleService.applyBatch(batch).get();
83 - } catch (InterruptedException | ExecutionException e) {
84 - // TODO Auto-generated catch block
85 - e.printStackTrace();
86 - }
87 } 105 }
88 106
89 @Override 107 @Override
90 - public void uninstall(PathIntent intent) { 108 + public Future<CompletedBatchOperation> uninstall(PathIntent intent) {
91 TrafficSelector.Builder builder = 109 TrafficSelector.Builder builder =
92 DefaultTrafficSelector.builder(intent.selector()); 110 DefaultTrafficSelector.builder(intent.selector());
93 Iterator<Link> links = intent.path().links().iterator(); 111 Iterator<Link> links = intent.path().links().iterator();
...@@ -103,15 +121,131 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> { ...@@ -103,15 +121,131 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> {
103 builder.build(), treatment, 121 builder.build(), treatment,
104 123, appId, 600); 122 123, appId, 600);
105 rules.add(new FlowRuleBatchEntry(FlowRuleOperation.REMOVE, rule)); 123 rules.add(new FlowRuleBatchEntry(FlowRuleOperation.REMOVE, rule));
106 - //flowRuleService.removeFlowRules(rule);
107 prev = link.dst(); 124 prev = link.dst();
108 } 125 }
109 - FlowRuleBatchOperation batch = new FlowRuleBatchOperation(rules); 126 + return applyBatch(rules);
110 - try { 127 + }
111 - flowRuleService.applyBatch(batch).get(); 128 +
112 - } catch (InterruptedException | ExecutionException e) { 129 + // TODO refactor below this line... ----------------------------
113 - // TODO Auto-generated catch block 130 +
114 - e.printStackTrace(); 131 + /**
132 + * Generates the series of MatchActionOperations from the
133 + * {@link FlowBatchOperation}.
134 + * <p>
135 + * FIXME: Currently supporting PacketPathFlow and SingleDstTreeFlow only.
136 + * <p>
137 + * FIXME: MatchActionOperations should have dependency field to the other
138 + * match action operations, and this method should use this.
139 + *
140 + * @param op the {@link FlowBatchOperation} object
141 + * @return the list of {@link MatchActionOperations} objects
142 + */
143 + /*
144 + private List<MatchActionOperations>
145 + generateMatchActionOperationsList(FlowBatchOperation op) {
146 +
147 + // MatchAction operations at head (ingress) switches.
148 + MatchActionOperations headOps = matchActionService.createOperationsList();
149 +
150 + // MatchAction operations at rest of the switches.
151 + MatchActionOperations tailOps = matchActionService.createOperationsList();
152 +
153 + MatchActionOperations removeOps = matchActionService.createOperationsList();
154 +
155 + for (BatchOperationEntry<Operator, ?> e : op.getOperations()) {
156 +
157 + if (e.getOperator() == FlowBatchOperation.Operator.ADD) {
158 + generateInstallMatchActionOperations(e, tailOps, headOps);
159 + } else if (e.getOperator() == FlowBatchOperation.Operator.REMOVE) {
160 + generateRemoveMatchActionOperations(e, removeOps);
161 + } else {
162 + throw new UnsupportedOperationException(
163 + "FlowManager supports ADD and REMOVE operations only.");
164 + }
165 +
166 + }
167 +
168 + return Arrays.asList(tailOps, headOps, removeOps);
169 + }
170 + */
171 +
172 + /**
173 + * Generates MatchActionOperations for an INSTALL FlowBatchOperation.
174 + * <p/>
175 + * FIXME: Currently only supports flows that generate exactly two match
176 + * action operation sets.
177 + *
178 + * @param e Flow BatchOperationEntry
179 + * @param tailOps MatchActionOperation set that the tail
180 + * MatchActionOperations will be placed in
181 + * @param headOps MatchActionOperation set that the head
182 + * MatchActionOperations will be placed in
183 + */
184 + /*
185 + private void generateInstallMatchActionOperations(
186 + BatchOperationEntry<Operator, ?> e,
187 + MatchActionOperations tailOps,
188 + MatchActionOperations headOps) {
189 +
190 + if (!(e.getTarget() instanceof Flow)) {
191 + throw new IllegalStateException(
192 + "The target is not Flow object: " + e.getTarget());
193 + }
194 +
195 + // Compile flows to match-actions
196 + Flow flow = (Flow) e.getTarget();
197 + List<MatchActionOperations> maOps = flow.compile(
198 + e.getOperator(), matchActionService);
199 + verifyNotNull(maOps, "Could not compile the flow: " + flow);
200 + verify(maOps.size() == 2,
201 + "The flow generates unspported match-action operations.");
202 +
203 + // Map FlowId to MatchActionIds
204 + for (MatchActionOperations maOp : maOps) {
205 + for (MatchActionOperationEntry entry : maOp.getOperations()) {
206 + flowMatchActionsMap.put(
207 + KryoFactory.serialize(flow.getId()),
208 + KryoFactory.serialize(entry.getTarget()));
209 + }
210 + }
211 +
212 + // Merge match-action operations
213 + for (MatchActionOperationEntry mae : maOps.get(0).getOperations()) {
214 + verify(mae.getOperator() == MatchActionOperations.Operator.INSTALL);
215 + tailOps.addOperation(mae);
216 + }
217 + for (MatchActionOperationEntry mae : maOps.get(1).getOperations()) {
218 + verify(mae.getOperator() == MatchActionOperations.Operator.INSTALL);
219 + headOps.addOperation(mae);
220 + }
221 + }
222 + */
223 + /**
224 + * Generates MatchActionOperations for a REMOVE FlowBatchOperation.
225 + *
226 + * @param e Flow BatchOperationEntry
227 + * @param removeOps MatchActionOperation set that the remove
228 + * MatchActionOperations will be placed in
229 + */
230 + /*
231 + private void generateRemoveMatchActionOperations(
232 + BatchOperationEntry<Operator, ?> e,
233 + MatchActionOperations removeOps) {
234 +
235 + if (!(e.getTarget() instanceof FlowId)) {
236 + throw new IllegalStateException(
237 + "The target is not a FlowId object: " + e.getTarget());
238 + }
239 +
240 + // Compile flows to match-actions
241 + FlowId flowId = (FlowId) e.getTarget();
242 +
243 + for (byte[] matchActionIdBytes :
244 + flowMatchActionsMap.remove(KryoFactory.serialize(flowId))) {
245 + MatchActionId matchActionId = KryoFactory.deserialize(matchActionIdBytes);
246 + removeOps.addOperation(new MatchActionOperationEntry(
247 + MatchActionOperations.Operator.REMOVE, matchActionId));
115 } 248 }
116 } 249 }
250 + */
117 } 251 }
......
...@@ -55,6 +55,7 @@ public class ProxyArpManager implements ProxyArpService { ...@@ -55,6 +55,7 @@ public class ProxyArpManager implements ProxyArpService {
55 private static final String REQUEST_NULL = "Arp request cannot be null."; 55 private static final String REQUEST_NULL = "Arp request cannot be null.";
56 private static final String REQUEST_NOT_ARP = "Ethernet frame does not contain ARP request."; 56 private static final String REQUEST_NOT_ARP = "Ethernet frame does not contain ARP request.";
57 private static final String NOT_ARP_REQUEST = "ARP is not a request."; 57 private static final String NOT_ARP_REQUEST = "ARP is not a request.";
58 + private static final String NOT_ARP_REPLY = "ARP is not a reply.";
58 59
59 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 60 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
60 protected HostService hostService; 61 protected HostService hostService;
...@@ -141,7 +142,7 @@ public class ProxyArpManager implements ProxyArpService { ...@@ -141,7 +142,7 @@ public class ProxyArpManager implements ProxyArpService {
141 checkArgument(eth.getEtherType() == Ethernet.TYPE_ARP, 142 checkArgument(eth.getEtherType() == Ethernet.TYPE_ARP,
142 REQUEST_NOT_ARP); 143 REQUEST_NOT_ARP);
143 ARP arp = (ARP) eth.getPayload(); 144 ARP arp = (ARP) eth.getPayload();
144 - checkArgument(arp.getOpCode() == ARP.OP_REPLY, NOT_ARP_REQUEST); 145 + checkArgument(arp.getOpCode() == ARP.OP_REPLY, NOT_ARP_REPLY);
145 146
146 Host h = hostService.getHost(HostId.hostId(eth.getDestinationMAC(), 147 Host h = hostService.getHost(HostId.hostId(eth.getDestinationMAC(),
147 VlanId.vlanId(eth.getVlanID()))); 148 VlanId.vlanId(eth.getVlanID())));
......
...@@ -22,9 +22,9 @@ import org.onlab.onos.net.Link; ...@@ -22,9 +22,9 @@ import org.onlab.onos.net.Link;
22 import org.onlab.onos.net.Path; 22 import org.onlab.onos.net.Path;
23 import org.onlab.onos.net.PortNumber; 23 import org.onlab.onos.net.PortNumber;
24 import org.onlab.onos.net.host.HostService; 24 import org.onlab.onos.net.host.HostService;
25 -import org.onlab.onos.net.topology.PathService;
26 import org.onlab.onos.net.provider.ProviderId; 25 import org.onlab.onos.net.provider.ProviderId;
27 import org.onlab.onos.net.topology.LinkWeight; 26 import org.onlab.onos.net.topology.LinkWeight;
27 +import org.onlab.onos.net.topology.PathService;
28 import org.onlab.onos.net.topology.Topology; 28 import org.onlab.onos.net.topology.Topology;
29 import org.onlab.onos.net.topology.TopologyService; 29 import org.onlab.onos.net.topology.TopologyService;
30 import org.slf4j.Logger; 30 import org.slf4j.Logger;
...@@ -33,7 +33,6 @@ import java.util.List; ...@@ -33,7 +33,6 @@ import java.util.List;
33 import java.util.Set; 33 import java.util.Set;
34 34
35 import static com.google.common.base.Preconditions.checkNotNull; 35 import static com.google.common.base.Preconditions.checkNotNull;
36 -import static org.onlab.onos.net.DeviceId.deviceId;
37 import static org.slf4j.LoggerFactory.getLogger; 36 import static org.slf4j.LoggerFactory.getLogger;
38 37
39 /** 38 /**
...@@ -162,8 +161,8 @@ public class PathManager implements PathService { ...@@ -162,8 +161,8 @@ public class PathManager implements PathService {
162 // edge link since the src or dst are really an infrastructure device. 161 // edge link since the src or dst are really an infrastructure device.
163 private static class NotHost extends DefaultEdgeLink implements EdgeLink { 162 private static class NotHost extends DefaultEdgeLink implements EdgeLink {
164 NotHost() { 163 NotHost() {
165 - super(PID, new ConnectPoint(HostId.hostId("nic:none"), P0), 164 + super(PID, new ConnectPoint(HostId.NONE, P0),
166 - new HostLocation(deviceId("none:none"), P0, 0L), false); 165 + new HostLocation(DeviceId.NONE, P0, 0L), false);
167 } 166 }
168 } 167 }
169 } 168 }
......
...@@ -19,6 +19,7 @@ import org.junit.Before; ...@@ -19,6 +19,7 @@ import org.junit.Before;
19 import org.junit.Test; 19 import org.junit.Test;
20 import org.onlab.onos.ApplicationId; 20 import org.onlab.onos.ApplicationId;
21 import org.onlab.onos.event.impl.TestEventDispatcher; 21 import org.onlab.onos.event.impl.TestEventDispatcher;
22 +import org.onlab.onos.impl.DefaultApplicationId;
22 import org.onlab.onos.net.DefaultDevice; 23 import org.onlab.onos.net.DefaultDevice;
23 import org.onlab.onos.net.Device; 24 import org.onlab.onos.net.Device;
24 import org.onlab.onos.net.Device.Type; 25 import org.onlab.onos.net.Device.Type;
...@@ -28,6 +29,7 @@ import org.onlab.onos.net.Port; ...@@ -28,6 +29,7 @@ import org.onlab.onos.net.Port;
28 import org.onlab.onos.net.PortNumber; 29 import org.onlab.onos.net.PortNumber;
29 import org.onlab.onos.net.device.DeviceListener; 30 import org.onlab.onos.net.device.DeviceListener;
30 import org.onlab.onos.net.device.DeviceService; 31 import org.onlab.onos.net.device.DeviceService;
32 +import org.onlab.onos.net.flow.CompletedBatchOperation;
31 import org.onlab.onos.net.flow.DefaultFlowEntry; 33 import org.onlab.onos.net.flow.DefaultFlowEntry;
32 import org.onlab.onos.net.flow.DefaultFlowRule; 34 import org.onlab.onos.net.flow.DefaultFlowRule;
33 import org.onlab.onos.net.flow.FlowEntry; 35 import org.onlab.onos.net.flow.FlowEntry;
...@@ -58,6 +60,8 @@ import com.google.common.collect.Sets; ...@@ -58,6 +60,8 @@ import com.google.common.collect.Sets;
58 */ 60 */
59 public class FlowRuleManagerTest { 61 public class FlowRuleManagerTest {
60 62
63 +
64 +
61 private static final ProviderId PID = new ProviderId("of", "foo"); 65 private static final ProviderId PID = new ProviderId("of", "foo");
62 private static final DeviceId DID = DeviceId.deviceId("of:001"); 66 private static final DeviceId DID = DeviceId.deviceId("of:001");
63 private static final int TIMEOUT = 10; 67 private static final int TIMEOUT = 10;
...@@ -86,7 +90,7 @@ public class FlowRuleManagerTest { ...@@ -86,7 +90,7 @@ public class FlowRuleManagerTest {
86 mgr.addListener(listener); 90 mgr.addListener(listener);
87 provider = new TestProvider(PID); 91 provider = new TestProvider(PID);
88 providerService = registry.register(provider); 92 providerService = registry.register(provider);
89 - appId = ApplicationId.getAppId(); 93 + appId = new TestApplicationId((short) 0, "FlowRuleManagerTest");
90 assertTrue("provider should be registered", 94 assertTrue("provider should be registered",
91 registry.getProviders().contains(provider.id())); 95 registry.getProviders().contains(provider.id()));
92 } 96 }
...@@ -408,7 +412,7 @@ public class FlowRuleManagerTest { ...@@ -408,7 +412,7 @@ public class FlowRuleManagerTest {
408 } 412 }
409 413
410 @Override 414 @Override
411 - public Future<Void> executeBatch( 415 + public Future<CompletedBatchOperation> executeBatch(
412 BatchOperation<FlowRuleBatchEntry> batch) { 416 BatchOperation<FlowRuleBatchEntry> batch) {
413 // TODO Auto-generated method stub 417 // TODO Auto-generated method stub
414 return null; 418 return null;
...@@ -474,4 +478,11 @@ public class FlowRuleManagerTest { ...@@ -474,4 +478,11 @@ public class FlowRuleManagerTest {
474 478
475 } 479 }
476 480
481 + public class TestApplicationId extends DefaultApplicationId {
482 +
483 + public TestApplicationId(short id, String name) {
484 + super(id, name);
485 + }
486 + }
487 +
477 } 488 }
......
...@@ -58,8 +58,6 @@ public class HostManagerTest { ...@@ -58,8 +58,6 @@ public class HostManagerTest {
58 58
59 private static final IpPrefix IP1 = IpPrefix.valueOf("10.0.0.1"); 59 private static final IpPrefix IP1 = IpPrefix.valueOf("10.0.0.1");
60 private static final IpPrefix IP2 = IpPrefix.valueOf("10.0.0.2"); 60 private static final IpPrefix IP2 = IpPrefix.valueOf("10.0.0.2");
61 - private static final Set<IpPrefix> IPSET1 = Sets.newHashSet(IP1);
62 - private static final Set<IpPrefix> IPSET2 = Sets.newHashSet(IP2);
63 61
64 private static final DeviceId DID1 = DeviceId.deviceId("of:001"); 62 private static final DeviceId DID1 = DeviceId.deviceId("of:001");
65 private static final DeviceId DID2 = DeviceId.deviceId("of:002"); 63 private static final DeviceId DID2 = DeviceId.deviceId("of:002");
...@@ -94,14 +92,14 @@ public class HostManagerTest { ...@@ -94,14 +92,14 @@ public class HostManagerTest {
94 provider = new TestHostProvider(); 92 provider = new TestHostProvider();
95 providerService = registry.register(provider); 93 providerService = registry.register(provider);
96 assertTrue("provider should be registered", 94 assertTrue("provider should be registered",
97 - registry.getProviders().contains(provider.id())); 95 + registry.getProviders().contains(provider.id()));
98 } 96 }
99 97
100 @After 98 @After
101 public void tearDown() { 99 public void tearDown() {
102 registry.unregister(provider); 100 registry.unregister(provider);
103 assertFalse("provider should not be registered", 101 assertFalse("provider should not be registered",
104 - registry.getProviders().contains(provider.id())); 102 + registry.getProviders().contains(provider.id()));
105 103
106 mgr.removeListener(listener); 104 mgr.removeListener(listener);
107 mgr.deactivate(); 105 mgr.deactivate();
...@@ -109,8 +107,8 @@ public class HostManagerTest { ...@@ -109,8 +107,8 @@ public class HostManagerTest {
109 } 107 }
110 108
111 private void detect(HostId hid, MacAddress mac, VlanId vlan, 109 private void detect(HostId hid, MacAddress mac, VlanId vlan,
112 - HostLocation loc, Set<IpPrefix> ips) { 110 + HostLocation loc, IpPrefix ip) {
113 - HostDescription descr = new DefaultHostDescription(mac, vlan, loc, ips); 111 + HostDescription descr = new DefaultHostDescription(mac, vlan, loc, ip);
114 providerService.hostDetected(hid, descr); 112 providerService.hostDetected(hid, descr);
115 assertNotNull("host should be found", mgr.getHost(hid)); 113 assertNotNull("host should be found", mgr.getHost(hid));
116 } 114 }
...@@ -130,26 +128,26 @@ public class HostManagerTest { ...@@ -130,26 +128,26 @@ public class HostManagerTest {
130 assertNull("host shouldn't be found", mgr.getHost(HID1)); 128 assertNull("host shouldn't be found", mgr.getHost(HID1));
131 129
132 // host addition 130 // host addition
133 - detect(HID1, MAC1, VLAN1, LOC1, IPSET1); 131 + detect(HID1, MAC1, VLAN1, LOC1, IP1);
134 assertEquals("exactly one should be found", 1, mgr.getHostCount()); 132 assertEquals("exactly one should be found", 1, mgr.getHostCount());
135 - detect(HID2, MAC2, VLAN2, LOC2, IPSET1); 133 + detect(HID2, MAC2, VLAN2, LOC2, IP1);
136 assertEquals("two hosts should be found", 2, mgr.getHostCount()); 134 assertEquals("two hosts should be found", 2, mgr.getHostCount());
137 validateEvents(HOST_ADDED, HOST_ADDED); 135 validateEvents(HOST_ADDED, HOST_ADDED);
138 136
139 // host motion 137 // host motion
140 - detect(HID1, MAC1, VLAN1, LOC2, IPSET1); 138 + detect(HID1, MAC1, VLAN1, LOC2, IP1);
141 validateEvents(HOST_MOVED); 139 validateEvents(HOST_MOVED);
142 assertEquals("only two hosts should be found", 2, mgr.getHostCount()); 140 assertEquals("only two hosts should be found", 2, mgr.getHostCount());
143 141
144 // host update 142 // host update
145 - detect(HID1, MAC1, VLAN1, LOC2, IPSET2); 143 + detect(HID1, MAC1, VLAN1, LOC2, IP2);
146 validateEvents(HOST_UPDATED); 144 validateEvents(HOST_UPDATED);
147 assertEquals("only two hosts should be found", 2, mgr.getHostCount()); 145 assertEquals("only two hosts should be found", 2, mgr.getHostCount());
148 } 146 }
149 147
150 @Test 148 @Test
151 public void hostVanished() { 149 public void hostVanished() {
152 - detect(HID1, MAC1, VLAN1, LOC1, IPSET1); 150 + detect(HID1, MAC1, VLAN1, LOC1, IP1);
153 providerService.hostVanished(HID1); 151 providerService.hostVanished(HID1);
154 validateEvents(HOST_ADDED, HOST_REMOVED); 152 validateEvents(HOST_ADDED, HOST_REMOVED);
155 153
...@@ -157,7 +155,7 @@ public class HostManagerTest { ...@@ -157,7 +155,7 @@ public class HostManagerTest {
157 } 155 }
158 156
159 private void validateHosts( 157 private void validateHosts(
160 - String msg, Iterable<Host> hosts, HostId ... ids) { 158 + String msg, Iterable<Host> hosts, HostId... ids) {
161 Set<HostId> hids = Sets.newHashSet(ids); 159 Set<HostId> hids = Sets.newHashSet(ids);
162 for (Host h : hosts) { 160 for (Host h : hosts) {
163 assertTrue(msg, hids.remove(h.id())); 161 assertTrue(msg, hids.remove(h.id()));
...@@ -167,8 +165,8 @@ public class HostManagerTest { ...@@ -167,8 +165,8 @@ public class HostManagerTest {
167 165
168 @Test 166 @Test
169 public void getHosts() { 167 public void getHosts() {
170 - detect(HID1, MAC1, VLAN1, LOC1, IPSET1); 168 + detect(HID1, MAC1, VLAN1, LOC1, IP1);
171 - detect(HID2, MAC2, VLAN1, LOC2, IPSET2); 169 + detect(HID2, MAC2, VLAN1, LOC2, IP2);
172 170
173 validateHosts("host not properly stored", mgr.getHosts(), HID1, HID2); 171 validateHosts("host not properly stored", mgr.getHosts(), HID1, HID2);
174 validateHosts("can't get hosts by VLAN", mgr.getHostsByVlan(VLAN1), HID1, HID2); 172 validateHosts("can't get hosts by VLAN", mgr.getHostsByVlan(VLAN1), HID1, HID2);
...@@ -210,7 +208,7 @@ public class HostManagerTest { ...@@ -210,7 +208,7 @@ public class HostManagerTest {
210 @Test 208 @Test
211 public void bindAddressesToPort() { 209 public void bindAddressesToPort() {
212 PortAddresses add1 = new PortAddresses(CP1, 210 PortAddresses add1 = new PortAddresses(CP1,
213 - Sets.newHashSet(PREFIX1, PREFIX2), MAC1); 211 + Sets.newHashSet(PREFIX1, PREFIX2), MAC1);
214 212
215 mgr.bindAddressesToPort(add1); 213 mgr.bindAddressesToPort(add1);
216 PortAddresses storedAddresses = mgr.getAddressBindingsForPort(CP1); 214 PortAddresses storedAddresses = mgr.getAddressBindingsForPort(CP1);
...@@ -241,7 +239,7 @@ public class HostManagerTest { ...@@ -241,7 +239,7 @@ public class HostManagerTest {
241 @Test 239 @Test
242 public void unbindAddressesFromPort() { 240 public void unbindAddressesFromPort() {
243 PortAddresses add1 = new PortAddresses(CP1, 241 PortAddresses add1 = new PortAddresses(CP1,
244 - Sets.newHashSet(PREFIX1, PREFIX2), MAC1); 242 + Sets.newHashSet(PREFIX1, PREFIX2), MAC1);
245 243
246 mgr.bindAddressesToPort(add1); 244 mgr.bindAddressesToPort(add1);
247 PortAddresses storedAddresses = mgr.getAddressBindingsForPort(CP1); 245 PortAddresses storedAddresses = mgr.getAddressBindingsForPort(CP1);
...@@ -250,7 +248,7 @@ public class HostManagerTest { ...@@ -250,7 +248,7 @@ public class HostManagerTest {
250 assertNotNull(storedAddresses.mac()); 248 assertNotNull(storedAddresses.mac());
251 249
252 PortAddresses rem1 = new PortAddresses(CP1, 250 PortAddresses rem1 = new PortAddresses(CP1,
253 - Sets.newHashSet(PREFIX1), null); 251 + Sets.newHashSet(PREFIX1), null);
254 252
255 mgr.unbindAddressesFromPort(rem1); 253 mgr.unbindAddressesFromPort(rem1);
256 storedAddresses = mgr.getAddressBindingsForPort(CP1); 254 storedAddresses = mgr.getAddressBindingsForPort(CP1);
...@@ -267,7 +265,7 @@ public class HostManagerTest { ...@@ -267,7 +265,7 @@ public class HostManagerTest {
267 assertNull(storedAddresses.mac()); 265 assertNull(storedAddresses.mac());
268 266
269 PortAddresses rem3 = new PortAddresses(CP1, 267 PortAddresses rem3 = new PortAddresses(CP1,
270 - Sets.newHashSet(PREFIX2), MAC1); 268 + Sets.newHashSet(PREFIX2), MAC1);
271 269
272 mgr.unbindAddressesFromPort(rem3); 270 mgr.unbindAddressesFromPort(rem3);
273 storedAddresses = mgr.getAddressBindingsForPort(CP1); 271 storedAddresses = mgr.getAddressBindingsForPort(CP1);
...@@ -279,7 +277,7 @@ public class HostManagerTest { ...@@ -279,7 +277,7 @@ public class HostManagerTest {
279 @Test 277 @Test
280 public void clearAddresses() { 278 public void clearAddresses() {
281 PortAddresses add1 = new PortAddresses(CP1, 279 PortAddresses add1 = new PortAddresses(CP1,
282 - Sets.newHashSet(PREFIX1, PREFIX2), MAC1); 280 + Sets.newHashSet(PREFIX1, PREFIX2), MAC1);
283 281
284 mgr.bindAddressesToPort(add1); 282 mgr.bindAddressesToPort(add1);
285 PortAddresses storedAddresses = mgr.getAddressBindingsForPort(CP1); 283 PortAddresses storedAddresses = mgr.getAddressBindingsForPort(CP1);
...@@ -297,7 +295,7 @@ public class HostManagerTest { ...@@ -297,7 +295,7 @@ public class HostManagerTest {
297 @Test 295 @Test
298 public void getAddressBindingsForPort() { 296 public void getAddressBindingsForPort() {
299 PortAddresses add1 = new PortAddresses(CP1, 297 PortAddresses add1 = new PortAddresses(CP1,
300 - Sets.newHashSet(PREFIX1, PREFIX2), MAC1); 298 + Sets.newHashSet(PREFIX1, PREFIX2), MAC1);
301 299
302 mgr.bindAddressesToPort(add1); 300 mgr.bindAddressesToPort(add1);
303 PortAddresses storedAddresses = mgr.getAddressBindingsForPort(CP1); 301 PortAddresses storedAddresses = mgr.getAddressBindingsForPort(CP1);
...@@ -314,7 +312,7 @@ public class HostManagerTest { ...@@ -314,7 +312,7 @@ public class HostManagerTest {
314 assertTrue(storedAddresses.isEmpty()); 312 assertTrue(storedAddresses.isEmpty());
315 313
316 PortAddresses add1 = new PortAddresses(CP1, 314 PortAddresses add1 = new PortAddresses(CP1,
317 - Sets.newHashSet(PREFIX1, PREFIX2), MAC1); 315 + Sets.newHashSet(PREFIX1, PREFIX2), MAC1);
318 316
319 mgr.bindAddressesToPort(add1); 317 mgr.bindAddressesToPort(add1);
320 318
...@@ -323,7 +321,7 @@ public class HostManagerTest { ...@@ -323,7 +321,7 @@ public class HostManagerTest {
323 assertTrue(storedAddresses.size() == 1); 321 assertTrue(storedAddresses.size() == 1);
324 322
325 PortAddresses add2 = new PortAddresses(CP2, 323 PortAddresses add2 = new PortAddresses(CP2,
326 - Sets.newHashSet(PREFIX3), MAC2); 324 + Sets.newHashSet(PREFIX3), MAC2);
327 325
328 mgr.bindAddressesToPort(add2); 326 mgr.bindAddressesToPort(add2);
329 327
......
1 +package org.onlab.onos.net.proxyarp.impl;
2 +
3 +import static org.easymock.EasyMock.anyObject;
4 +import static org.easymock.EasyMock.createMock;
5 +import static org.easymock.EasyMock.expect;
6 +import static org.easymock.EasyMock.replay;
7 +import static org.junit.Assert.assertEquals;
8 +import static org.junit.Assert.assertFalse;
9 +import static org.junit.Assert.assertTrue;
10 +
11 +import java.util.ArrayList;
12 +import java.util.Arrays;
13 +import java.util.Collections;
14 +import java.util.Comparator;
15 +import java.util.List;
16 +
17 +import org.junit.Before;
18 +import org.junit.Test;
19 +import org.onlab.onos.net.ConnectPoint;
20 +import org.onlab.onos.net.DefaultHost;
21 +import org.onlab.onos.net.Device;
22 +import org.onlab.onos.net.DeviceId;
23 +import org.onlab.onos.net.Host;
24 +import org.onlab.onos.net.HostId;
25 +import org.onlab.onos.net.HostLocation;
26 +import org.onlab.onos.net.Link;
27 +import org.onlab.onos.net.Port;
28 +import org.onlab.onos.net.PortNumber;
29 +import org.onlab.onos.net.device.DeviceListener;
30 +import org.onlab.onos.net.device.DeviceService;
31 +import org.onlab.onos.net.flow.instructions.Instruction;
32 +import org.onlab.onos.net.flow.instructions.Instructions.OutputInstruction;
33 +import org.onlab.onos.net.host.HostService;
34 +import org.onlab.onos.net.link.LinkListener;
35 +import org.onlab.onos.net.link.LinkService;
36 +import org.onlab.onos.net.packet.OutboundPacket;
37 +import org.onlab.onos.net.packet.PacketProcessor;
38 +import org.onlab.onos.net.packet.PacketService;
39 +import org.onlab.onos.net.provider.ProviderId;
40 +import org.onlab.packet.ARP;
41 +import org.onlab.packet.Ethernet;
42 +import org.onlab.packet.IpPrefix;
43 +import org.onlab.packet.MacAddress;
44 +import org.onlab.packet.VlanId;
45 +
46 +import com.google.common.collect.Sets;
47 +
48 +/**
49 + * Tests for the {@link ProxyArpManager} class.
50 + */
51 +public class ProxyArpManagerTest {
52 +
53 + private static final int NUM_DEVICES = 4;
54 + private static final int NUM_PORTS_PER_DEVICE = 3;
55 + private static final int NUM_FLOOD_PORTS = 4;
56 +
57 + private static final IpPrefix IP1 = IpPrefix.valueOf("10.0.0.1/24");
58 + private static final IpPrefix IP2 = IpPrefix.valueOf("10.0.0.2/24");
59 +
60 + private static final ProviderId PID = new ProviderId("of", "foo");
61 +
62 + private static final VlanId VLAN1 = VlanId.vlanId((short) 1);
63 + private static final VlanId VLAN2 = VlanId.vlanId((short) 2);
64 + private static final MacAddress MAC1 = MacAddress.valueOf("00:00:11:00:00:01");
65 + private static final MacAddress MAC2 = MacAddress.valueOf("00:00:22:00:00:02");
66 + private static final HostId HID1 = HostId.hostId(MAC1, VLAN1);
67 + private static final HostId HID2 = HostId.hostId(MAC2, VLAN1);
68 +
69 + private static final DeviceId DID1 = getDeviceId(1);
70 + private static final DeviceId DID2 = getDeviceId(2);
71 + private static final PortNumber P1 = PortNumber.portNumber(1);
72 + private static final HostLocation LOC1 = new HostLocation(DID1, P1, 123L);
73 + private static final HostLocation LOC2 = new HostLocation(DID2, P1, 123L);
74 +
75 + private ProxyArpManager proxyArp;
76 +
77 + private TestPacketService packetService;
78 +
79 + private DeviceService deviceService;
80 + private LinkService linkService;
81 + private HostService hostService;
82 +
83 + @Before
84 + public void setUp() throws Exception {
85 + proxyArp = new ProxyArpManager();
86 + packetService = new TestPacketService();
87 + proxyArp.packetService = packetService;
88 +
89 + // Create a host service mock here. Must be replayed by tests once the
90 + // expectations have been set up
91 + hostService = createMock(HostService.class);
92 + proxyArp.hostService = hostService;
93 +
94 + createTopology();
95 + proxyArp.deviceService = deviceService;
96 + proxyArp.linkService = linkService;
97 +
98 + proxyArp.activate();
99 + }
100 +
101 + /**
102 + * Creates a fake topology to feed into the ARP module.
103 + * <p/>
104 + * The default topology is a unidirectional ring topology. Each switch has
105 + * 3 ports. Ports 2 and 3 have the links to neighbor switches, and port 1
106 + * is free (edge port).
107 + */
108 + private void createTopology() {
109 + deviceService = createMock(DeviceService.class);
110 + linkService = createMock(LinkService.class);
111 +
112 + deviceService.addListener(anyObject(DeviceListener.class));
113 + linkService.addListener(anyObject(LinkListener.class));
114 +
115 + createDevices(NUM_DEVICES, NUM_PORTS_PER_DEVICE);
116 + createLinks(NUM_DEVICES);
117 + }
118 +
119 + /**
120 + * Creates the devices for the fake topology.
121 + */
122 + private void createDevices(int numDevices, int numPorts) {
123 + List<Device> devices = new ArrayList<>();
124 +
125 + for (int i = 1; i <= numDevices; i++) {
126 + DeviceId devId = getDeviceId(i);
127 + Device device = createMock(Device.class);
128 + expect(device.id()).andReturn(devId).anyTimes();
129 + replay(device);
130 +
131 + devices.add(device);
132 +
133 + List<Port> ports = new ArrayList<>();
134 + for (int j = 1; j <= numPorts; j++) {
135 + Port port = createMock(Port.class);
136 + expect(port.number()).andReturn(PortNumber.portNumber(j)).anyTimes();
137 + replay(port);
138 + ports.add(port);
139 + }
140 +
141 + expect(deviceService.getPorts(devId)).andReturn(ports);
142 + }
143 +
144 + expect(deviceService.getDevices()).andReturn(devices);
145 + replay(deviceService);
146 + }
147 +
148 + /**
149 + * Creates the links for the fake topology.
150 + * NB: Only unidirectional links are created, as for this purpose all we
151 + * need is to occupy the ports with some link.
152 + */
153 + private void createLinks(int numDevices) {
154 + List<Link> links = new ArrayList<Link>();
155 +
156 + for (int i = 1; i <= numDevices; i++) {
157 + ConnectPoint src = new ConnectPoint(
158 + getDeviceId(i),
159 + PortNumber.portNumber(2));
160 + ConnectPoint dst = new ConnectPoint(
161 + getDeviceId((i + 1 > numDevices) ? 1 : i + 1),
162 + PortNumber.portNumber(3));
163 +
164 + Link link = createMock(Link.class);
165 + expect(link.src()).andReturn(src).anyTimes();
166 + expect(link.dst()).andReturn(dst).anyTimes();
167 + replay(link);
168 +
169 + links.add(link);
170 + }
171 +
172 + expect(linkService.getLinks()).andReturn(links).anyTimes();
173 + replay(linkService);
174 + }
175 +
176 + /**
177 + * Tests {@link ProxyArpManager#known(IpPrefix)} in the case where the
178 + * IP address is not known.
179 + * Verifies the method returns false.
180 + */
181 + @Test
182 + public void testNotKnown() {
183 + expect(hostService.getHostsByIp(IP1)).andReturn(Collections.<Host>emptySet());
184 + replay(hostService);
185 +
186 + assertFalse(proxyArp.known(IP1));
187 + }
188 +
189 + /**
190 + * Tests {@link ProxyArpManager#known(IpPrefix)} in the case where the
191 + * IP address is known.
192 + * Verifies the method returns true.
193 + */
194 + @Test
195 + public void testKnown() {
196 + Host host1 = createMock(Host.class);
197 + Host host2 = createMock(Host.class);
198 +
199 + expect(hostService.getHostsByIp(IP1))
200 + .andReturn(Sets.newHashSet(host1, host2));
201 + replay(hostService);
202 +
203 + assertTrue(proxyArp.known(IP1));
204 + }
205 +
206 + /**
207 + * Tests {@link ProxyArpManager#reply(Ethernet)} in the case where the
208 + * destination host is known.
209 + * Verifies the correct ARP reply is sent out the correct port.
210 + */
211 + @Test
212 + public void testReplyKnown() {
213 + Host replyer = new DefaultHost(PID, HID1, MAC1, VLAN1, LOC2,
214 + Collections.singleton(IP1));
215 +
216 + Host requestor = new DefaultHost(PID, HID2, MAC2, VLAN1, LOC1,
217 + Collections.singleton(IP2));
218 +
219 + expect(hostService.getHostsByIp(IpPrefix.valueOf(IP1.toOctets())))
220 + .andReturn(Collections.singleton(replyer));
221 + expect(hostService.getHost(HID2)).andReturn(requestor);
222 +
223 + replay(hostService);
224 +
225 + Ethernet arpRequest = buildArp(ARP.OP_REQUEST, MAC2, null, IP2, IP1);
226 +
227 + proxyArp.reply(arpRequest);
228 +
229 + assertEquals(1, packetService.packets.size());
230 + Ethernet arpReply = buildArp(ARP.OP_REPLY, MAC1, MAC2, IP1, IP2);
231 + verifyPacketOut(arpReply, LOC1, packetService.packets.get(0));
232 + }
233 +
234 + /**
235 + * Tests {@link ProxyArpManager#reply(Ethernet)} in the case where the
236 + * destination host is not known.
237 + * Verifies the ARP request is flooded out the correct edge ports.
238 + */
239 + @Test
240 + public void testReplyUnknown() {
241 + Host requestor = new DefaultHost(PID, HID2, MAC2, VLAN1, LOC1,
242 + Collections.singleton(IP2));
243 +
244 + expect(hostService.getHostsByIp(IpPrefix.valueOf(IP1.toOctets())))
245 + .andReturn(Collections.<Host>emptySet());
246 + expect(hostService.getHost(HID2)).andReturn(requestor);
247 +
248 + replay(hostService);
249 +
250 + Ethernet arpRequest = buildArp(ARP.OP_REQUEST, MAC2, null, IP2, IP1);
251 +
252 + proxyArp.reply(arpRequest);
253 +
254 + verifyFlood(arpRequest);
255 + }
256 +
257 + /**
258 + * Tests {@link ProxyArpManager#reply(Ethernet)} in the case where the
259 + * destination host is known for that IP address, but is not on the same
260 + * VLAN as the source host.
261 + * Verifies the ARP request is flooded out the correct edge ports.
262 + */
263 + @Test
264 + public void testReplyDifferentVlan() {
265 + Host replyer = new DefaultHost(PID, HID1, MAC1, VLAN2, LOC2,
266 + Collections.singleton(IP1));
267 +
268 + Host requestor = new DefaultHost(PID, HID2, MAC2, VLAN1, LOC1,
269 + Collections.singleton(IP2));
270 +
271 + expect(hostService.getHostsByIp(IpPrefix.valueOf(IP1.toOctets())))
272 + .andReturn(Collections.singleton(replyer));
273 + expect(hostService.getHost(HID2)).andReturn(requestor);
274 +
275 + replay(hostService);
276 +
277 + Ethernet arpRequest = buildArp(ARP.OP_REQUEST, MAC2, null, IP2, IP1);
278 +
279 + proxyArp.reply(arpRequest);
280 +
281 + verifyFlood(arpRequest);
282 + }
283 +
284 + /**
285 + * Tests {@link ProxyArpManager#forward(Ethernet)} in the case where the
286 + * destination host is known.
287 + * Verifies the correct ARP request is sent out the correct port.
288 + */
289 + @Test
290 + public void testForwardToHost() {
291 + Host host1 = new DefaultHost(PID, HID1, MAC1, VLAN1, LOC1,
292 + Collections.singleton(IP1));
293 +
294 + expect(hostService.getHost(HID1)).andReturn(host1);
295 + replay(hostService);
296 +
297 + Ethernet arpRequest = buildArp(ARP.OP_REPLY, MAC2, MAC1, IP2, IP1);
298 +
299 + proxyArp.forward(arpRequest);
300 +
301 + assertEquals(1, packetService.packets.size());
302 + OutboundPacket packet = packetService.packets.get(0);
303 +
304 + verifyPacketOut(arpRequest, LOC1, packet);
305 + }
306 +
307 + /**
308 + * Tests {@link ProxyArpManager#forward(Ethernet)} in the case where the
309 + * destination host is not known.
310 + * Verifies the correct ARP request is flooded out the correct edge ports.
311 + */
312 + @Test
313 + public void testForwardFlood() {
314 + expect(hostService.getHost(HID1)).andReturn(null);
315 + replay(hostService);
316 +
317 + Ethernet arpRequest = buildArp(ARP.OP_REPLY, MAC2, MAC1, IP2, IP1);
318 +
319 + proxyArp.forward(arpRequest);
320 +
321 + verifyFlood(arpRequest);
322 + }
323 +
324 + /**
325 + * Verifies that the given packet was flooded out all available edge ports.
326 + *
327 + * @param packet the packet that was expected to be flooded
328 + */
329 + private void verifyFlood(Ethernet packet) {
330 + assertEquals(NUM_FLOOD_PORTS, packetService.packets.size());
331 +
332 + Collections.sort(packetService.packets,
333 + new Comparator<OutboundPacket>() {
334 + @Override
335 + public int compare(OutboundPacket o1, OutboundPacket o2) {
336 + return o1.sendThrough().uri().compareTo(o2.sendThrough().uri());
337 + }
338 + });
339 +
340 + for (int i = 0; i < NUM_FLOOD_PORTS; i++) {
341 + ConnectPoint cp = new ConnectPoint(getDeviceId(i + 1), PortNumber.portNumber(1));
342 +
343 + OutboundPacket outboundPacket = packetService.packets.get(i);
344 + verifyPacketOut(packet, cp, outboundPacket);
345 + }
346 + }
347 +
348 + /**
349 + * Verifies the given packet was sent out the given port.
350 + *
351 + * @param expected the packet that was expected to be sent
352 + * @param outPort the port the packet was expected to be sent out
353 + * @param actual the actual OutboundPacket to verify
354 + */
355 + private void verifyPacketOut(Ethernet expected, ConnectPoint outPort,
356 + OutboundPacket actual) {
357 + assertTrue(Arrays.equals(expected.serialize(), actual.data().array()));
358 + assertEquals(1, actual.treatment().instructions().size());
359 + assertEquals(outPort.deviceId(), actual.sendThrough());
360 + Instruction instruction = actual.treatment().instructions().get(0);
361 + assertTrue(instruction instanceof OutputInstruction);
362 + assertEquals(outPort.port(), ((OutputInstruction) instruction).port());
363 + }
364 +
365 + /**
366 + * Returns the device ID of the ith device.
367 + *
368 + * @param i device to get the ID of
369 + * @return the device ID
370 + */
371 + private static DeviceId getDeviceId(int i) {
372 + return DeviceId.deviceId("" + i);
373 + }
374 +
375 + /**
376 + * Builds an ARP packet with the given parameters.
377 + *
378 + * @param opcode opcode of the ARP packet
379 + * @param srcMac source MAC address
380 + * @param dstMac destination MAC address, or null if this is a request
381 + * @param srcIp source IP address
382 + * @param dstIp destination IP address
383 + * @return the ARP packet
384 + */
385 + private Ethernet buildArp(short opcode, MacAddress srcMac, MacAddress dstMac,
386 + IpPrefix srcIp, IpPrefix dstIp) {
387 + Ethernet eth = new Ethernet();
388 +
389 + if (dstMac == null) {
390 + eth.setDestinationMACAddress(MacAddress.BROADCAST_MAC);
391 + } else {
392 + eth.setDestinationMACAddress(dstMac.getAddress());
393 + }
394 +
395 + eth.setSourceMACAddress(srcMac.getAddress());
396 + eth.setEtherType(Ethernet.TYPE_ARP);
397 + eth.setVlanID(VLAN1.toShort());
398 +
399 + ARP arp = new ARP();
400 + arp.setOpCode(opcode);
401 + arp.setProtocolType(ARP.PROTO_TYPE_IP);
402 + arp.setHardwareType(ARP.HW_TYPE_ETHERNET);
403 +
404 + arp.setProtocolAddressLength((byte) IpPrefix.INET_LEN);
405 + arp.setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH);
406 + arp.setSenderHardwareAddress(srcMac.getAddress());
407 +
408 + if (dstMac == null) {
409 + arp.setTargetHardwareAddress(MacAddress.ZERO_MAC_ADDRESS);
410 + } else {
411 + arp.setTargetHardwareAddress(dstMac.getAddress());
412 + }
413 +
414 + arp.setSenderProtocolAddress(srcIp.toOctets());
415 + arp.setTargetProtocolAddress(dstIp.toOctets());
416 +
417 + eth.setPayload(arp);
418 + return eth;
419 + }
420 +
421 + /**
422 + * Test PacketService implementation that simply stores OutboundPackets
423 + * passed to {@link #emit(OutboundPacket)} for later verification.
424 + */
425 + class TestPacketService implements PacketService {
426 +
427 + List<OutboundPacket> packets = new ArrayList<>();
428 +
429 + @Override
430 + public void addProcessor(PacketProcessor processor, int priority) {
431 + }
432 +
433 + @Override
434 + public void removeProcessor(PacketProcessor processor) {
435 + }
436 +
437 + @Override
438 + public void emit(OutboundPacket packet) {
439 + packets.add(packet);
440 + }
441 + }
442 +}
...@@ -65,47 +65,48 @@ public class PathManagerTest { ...@@ -65,47 +65,48 @@ public class PathManagerTest {
65 @Test 65 @Test
66 public void infraToEdge() { 66 public void infraToEdge() {
67 DeviceId src = did("src"); 67 DeviceId src = did("src");
68 - HostId dst = hid("dst"); 68 + HostId dst = hid("12:34:56:78:90:ab/1");
69 fakeTopoMgr.paths.add(createPath("src", "middle", "edge")); 69 fakeTopoMgr.paths.add(createPath("src", "middle", "edge"));
70 - fakeHostMgr.hosts.put(dst, host("dst", "edge")); 70 + fakeHostMgr.hosts.put(dst, host("12:34:56:78:90:ab/1", "edge"));
71 Set<Path> paths = service.getPaths(src, dst); 71 Set<Path> paths = service.getPaths(src, dst);
72 validatePaths(paths, 1, 3, src, dst); 72 validatePaths(paths, 1, 3, src, dst);
73 } 73 }
74 74
75 @Test 75 @Test
76 public void edgeToInfra() { 76 public void edgeToInfra() {
77 - HostId src = hid("src"); 77 + HostId src = hid("12:34:56:78:90:ab/1");
78 DeviceId dst = did("dst"); 78 DeviceId dst = did("dst");
79 fakeTopoMgr.paths.add(createPath("edge", "middle", "dst")); 79 fakeTopoMgr.paths.add(createPath("edge", "middle", "dst"));
80 - fakeHostMgr.hosts.put(src, host("src", "edge")); 80 + fakeHostMgr.hosts.put(src, host("12:34:56:78:90:ab/1", "edge"));
81 Set<Path> paths = service.getPaths(src, dst); 81 Set<Path> paths = service.getPaths(src, dst);
82 validatePaths(paths, 1, 3, src, dst); 82 validatePaths(paths, 1, 3, src, dst);
83 } 83 }
84 84
85 @Test 85 @Test
86 public void edgeToEdge() { 86 public void edgeToEdge() {
87 - HostId src = hid("src"); 87 + HostId src = hid("12:34:56:78:90:ab/1");
88 - HostId dst = hid("dst"); 88 + HostId dst = hid("12:34:56:78:90:ef/1");
89 fakeTopoMgr.paths.add(createPath("srcEdge", "middle", "dstEdge")); 89 fakeTopoMgr.paths.add(createPath("srcEdge", "middle", "dstEdge"));
90 - fakeHostMgr.hosts.put(src, host("src", "srcEdge")); 90 + fakeHostMgr.hosts.put(src, host("12:34:56:78:90:ab/1", "srcEdge"));
91 - fakeHostMgr.hosts.put(dst, host("dst", "dstEdge")); 91 + fakeHostMgr.hosts.put(dst, host("12:34:56:78:90:ef/1", "dstEdge"));
92 Set<Path> paths = service.getPaths(src, dst); 92 Set<Path> paths = service.getPaths(src, dst);
93 validatePaths(paths, 1, 4, src, dst); 93 validatePaths(paths, 1, 4, src, dst);
94 } 94 }
95 95
96 @Test 96 @Test
97 public void edgeToEdgeDirect() { 97 public void edgeToEdgeDirect() {
98 - HostId src = hid("src"); 98 + HostId src = hid("12:34:56:78:90:ab/1");
99 - HostId dst = hid("dst"); 99 + HostId dst = hid("12:34:56:78:90:ef/1");
100 - fakeHostMgr.hosts.put(src, host("src", "edge")); 100 + fakeHostMgr.hosts.put(src, host("12:34:56:78:90:ab/1", "edge"));
101 - fakeHostMgr.hosts.put(dst, host("dst", "edge")); 101 + fakeHostMgr.hosts.put(dst, host("12:34:56:78:90:ef/1", "edge"));
102 Set<Path> paths = service.getPaths(src, dst); 102 Set<Path> paths = service.getPaths(src, dst);
103 validatePaths(paths, 1, 2, src, dst); 103 validatePaths(paths, 1, 2, src, dst);
104 } 104 }
105 105
106 @Test 106 @Test
107 public void noEdge() { 107 public void noEdge() {
108 - Set<Path> paths = service.getPaths(hid("src"), hid("dst")); 108 + Set<Path> paths = service.getPaths(hid("12:34:56:78:90:ab/1"),
109 + hid("12:34:56:78:90:ef/1"));
109 assertTrue("there should be no paths", paths.isEmpty()); 110 assertTrue("there should be no paths", paths.isEmpty());
110 } 111 }
111 112
......
...@@ -134,11 +134,11 @@ public class TopologyManagerTest { ...@@ -134,11 +134,11 @@ public class TopologyManagerTest {
134 service.isInfrastructure(topology, new ConnectPoint(did("a"), portNumber(3)))); 134 service.isInfrastructure(topology, new ConnectPoint(did("a"), portNumber(3))));
135 135
136 // One of these cannot be a broadcast point... or we have a loop... 136 // One of these cannot be a broadcast point... or we have a loop...
137 - assertFalse("should not be broadcast point", 137 +// assertFalse("should not be broadcast point",
138 - service.isBroadcastPoint(topology, new ConnectPoint(did("a"), portNumber(1))) && 138 +// service.isBroadcastPoint(topology, new ConnectPoint(did("a"), portNumber(1))) &&
139 - service.isBroadcastPoint(topology, new ConnectPoint(did("b"), portNumber(1))) && 139 +// service.isBroadcastPoint(topology, new ConnectPoint(did("b"), portNumber(1))) &&
140 - service.isBroadcastPoint(topology, new ConnectPoint(did("c"), portNumber(1))) && 140 +// service.isBroadcastPoint(topology, new ConnectPoint(did("c"), portNumber(1))) &&
141 - service.isBroadcastPoint(topology, new ConnectPoint(did("d"), portNumber(1)))); 141 +// service.isBroadcastPoint(topology, new ConnectPoint(did("d"), portNumber(1))));
142 assertTrue("should be broadcast point", 142 assertTrue("should be broadcast point",
143 service.isBroadcastPoint(topology, new ConnectPoint(did("a"), portNumber(3)))); 143 service.isBroadcastPoint(topology, new ConnectPoint(did("a"), portNumber(3))));
144 } 144 }
......
...@@ -54,8 +54,18 @@ ...@@ -54,8 +54,18 @@
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>
64 + </dependency>
65 + <dependency>
66 + <groupId>org.easymock</groupId>
67 + <artifactId>easymock</artifactId>
68 + <scope>test</scope>
59 </dependency> 69 </dependency>
60 </dependencies> 70 </dependencies>
61 71
......
1 -package org.onlab.onos.store.common.impl;
2 -
3 -import java.util.Map;
4 -
5 -import org.onlab.onos.cluster.NodeId;
6 -import org.onlab.onos.store.Timestamp;
7 -
8 -import com.google.common.collect.ImmutableMap;
9 -
10 -/**
11 - * Anti-Entropy advertisement message.
12 - * <p>
13 - * Message to advertise the information this node holds.
14 - *
15 - * @param <ID> ID type
16 - */
17 -public class AntiEntropyAdvertisement<ID> {
18 -
19 - private final NodeId sender;
20 - private final ImmutableMap<ID, Timestamp> advertisement;
21 -
22 - /**
23 - * Creates anti-entropy advertisement message.
24 - *
25 - * @param sender sender of this message
26 - * @param advertisement timestamp information of the data sender holds
27 - */
28 - public AntiEntropyAdvertisement(NodeId sender, Map<ID, Timestamp> advertisement) {
29 - this.sender = sender;
30 - this.advertisement = ImmutableMap.copyOf(advertisement);
31 - }
32 -
33 - public NodeId sender() {
34 - return sender;
35 - }
36 -
37 - public ImmutableMap<ID, Timestamp> advertisement() {
38 - return advertisement;
39 - }
40 -
41 - // Default constructor for serializer
42 - protected AntiEntropyAdvertisement() {
43 - this.sender = null;
44 - this.advertisement = null;
45 - }
46 -}
1 -package org.onlab.onos.store.common.impl;
2 -
3 -import java.util.Map;
4 -import java.util.Set;
5 -
6 -import org.onlab.onos.cluster.NodeId;
7 -import org.onlab.onos.store.device.impl.VersionedValue;
8 -
9 -import com.google.common.collect.ImmutableMap;
10 -import com.google.common.collect.ImmutableSet;
11 -
12 -/**
13 - * Anti-Entropy reply message.
14 - * <p>
15 - * Message to send in reply to advertisement or another reply.
16 - * Suggest to the sender about the more up-to-date data this node has,
17 - * and request for more recent data that the receiver has.
18 - */
19 -public class AntiEntropyReply<ID, V extends VersionedValue<?>> {
20 -
21 - private final NodeId sender;
22 - private final ImmutableMap<ID, V> suggestion;
23 - private final ImmutableSet<ID> request;
24 -
25 - /**
26 - * Creates a reply to anti-entropy message.
27 - *
28 - * @param sender sender of this message
29 - * @param suggestion collection of more recent values, sender had
30 - * @param request Collection of identifiers
31 - */
32 - public AntiEntropyReply(NodeId sender,
33 - Map<ID, V> suggestion,
34 - Set<ID> request) {
35 - this.sender = sender;
36 - this.suggestion = ImmutableMap.copyOf(suggestion);
37 - this.request = ImmutableSet.copyOf(request);
38 - }
39 -
40 - public NodeId sender() {
41 - return sender;
42 - }
43 -
44 - /**
45 - * Returns collection of values, which the recipient of this reply is likely
46 - * to be missing or has outdated version.
47 - *
48 - * @return
49 - */
50 - public ImmutableMap<ID, V> suggestion() {
51 - return suggestion;
52 - }
53 -
54 - /**
55 - * Returns collection of identifier to request.
56 - *
57 - * @return collection of identifier to request
58 - */
59 - public ImmutableSet<ID> request() {
60 - return request;
61 - }
62 -
63 - /**
64 - * Checks if reply contains any suggestion or request.
65 - *
66 - * @return true if nothing is suggested and requested
67 - */
68 - public boolean isEmpty() {
69 - return suggestion.isEmpty() && request.isEmpty();
70 - }
71 -
72 - // Default constructor for serializer
73 - protected AntiEntropyReply() {
74 - this.sender = null;
75 - this.suggestion = null;
76 - this.request = null;
77 - }
78 -}
...@@ -30,6 +30,7 @@ public final class Timestamped<T> { ...@@ -30,6 +30,7 @@ public final class Timestamped<T> {
30 30
31 /** 31 /**
32 * Returns the value. 32 * Returns the value.
33 + *
33 * @return value 34 * @return value
34 */ 35 */
35 public T value() { 36 public T value() {
...@@ -38,6 +39,7 @@ public final class Timestamped<T> { ...@@ -38,6 +39,7 @@ public final class Timestamped<T> {
38 39
39 /** 40 /**
40 * Returns the time stamp. 41 * Returns the time stamp.
42 + *
41 * @return time stamp 43 * @return time stamp
42 */ 44 */
43 public Timestamp timestamp() { 45 public Timestamp timestamp() {
...@@ -51,7 +53,16 @@ public final class Timestamped<T> { ...@@ -51,7 +53,16 @@ public final class Timestamped<T> {
51 * @return true if this instance is newer. 53 * @return true if this instance is newer.
52 */ 54 */
53 public boolean isNewer(Timestamped<T> other) { 55 public boolean isNewer(Timestamped<T> other) {
54 - return this.timestamp.compareTo(checkNotNull(other).timestamp()) > 0; 56 + return isNewer(checkNotNull(other).timestamp());
57 + }
58 +
59 + /**
60 + * Tests if this timestamp is newer thatn the specified timestamp.
61 + * @param timestamp to compare agains
62 + * @return true if this instance is newer
63 + */
64 + public boolean isNewer(Timestamp timestamp) {
65 + return this.timestamp.compareTo(checkNotNull(timestamp)) > 0;
55 } 66 }
56 67
57 @Override 68 @Override
......
1 -package org.onlab.onos.store.device.impl;
2 -
3 -import java.util.Collection;
4 -import java.util.HashMap;
5 -import java.util.Map;
6 -
7 -import org.onlab.onos.cluster.NodeId;
8 -import org.onlab.onos.net.Device;
9 -import org.onlab.onos.net.DeviceId;
10 -import org.onlab.onos.store.Timestamp;
11 -import org.onlab.onos.store.common.impl.AntiEntropyAdvertisement;
12 -
13 -// TODO DeviceID needs to be changed to something like (ProviderID, DeviceID)
14 -// TODO: Handle Port as part of these messages, or separate messages for Ports?
15 -
16 -public class DeviceAntiEntropyAdvertisement
17 - extends AntiEntropyAdvertisement<DeviceId> {
18 -
19 -
20 - public DeviceAntiEntropyAdvertisement(NodeId sender,
21 - Map<DeviceId, Timestamp> advertisement) {
22 - super(sender, advertisement);
23 - }
24 -
25 - // May need to add ProviderID, etc.
26 - public static DeviceAntiEntropyAdvertisement create(
27 - NodeId self,
28 - Collection<VersionedValue<Device>> localValues) {
29 -
30 - Map<DeviceId, Timestamp> ads = new HashMap<>(localValues.size());
31 - for (VersionedValue<Device> e : localValues) {
32 - ads.put(e.entity().id(), e.timestamp());
33 - }
34 - return new DeviceAntiEntropyAdvertisement(self, ads);
35 - }
36 -
37 - // For serializer
38 - protected DeviceAntiEntropyAdvertisement() {}
39 -}
1 -package org.onlab.onos.store.device.impl;
2 -
3 -import java.util.Collection;
4 -import java.util.HashMap;
5 -import java.util.HashSet;
6 -import java.util.Map;
7 -import java.util.Set;
8 -
9 -import org.onlab.onos.cluster.NodeId;
10 -import org.onlab.onos.net.Device;
11 -import org.onlab.onos.net.DeviceId;
12 -import org.onlab.onos.store.Timestamp;
13 -import org.onlab.onos.store.common.impl.AntiEntropyReply;
14 -
15 -import com.google.common.collect.ImmutableMap;
16 -import com.google.common.collect.ImmutableSet;
17 -
18 -public class DeviceAntiEntropyReply
19 - extends AntiEntropyReply<DeviceId, VersionedValue<Device>> {
20 -
21 -
22 - public DeviceAntiEntropyReply(NodeId sender,
23 - Map<DeviceId, VersionedValue<Device>> suggestion,
24 - Set<DeviceId> request) {
25 - super(sender, suggestion, request);
26 - }
27 -
28 - /**
29 - * Creates a reply to Anti-Entropy advertisement.
30 - *
31 - * @param advertisement to respond to
32 - * @param self node identifier representing local node
33 - * @param localValues local values held on this node
34 - * @return reply message
35 - */
36 - public static DeviceAntiEntropyReply reply(
37 - DeviceAntiEntropyAdvertisement advertisement,
38 - NodeId self,
39 - Collection<VersionedValue<Device>> localValues
40 - ) {
41 -
42 - ImmutableMap<DeviceId, Timestamp> ads = advertisement.advertisement();
43 -
44 - ImmutableMap.Builder<DeviceId, VersionedValue<Device>>
45 - sug = ImmutableMap.builder();
46 -
47 - Set<DeviceId> req = new HashSet<>(ads.keySet());
48 -
49 - for (VersionedValue<Device> e : localValues) {
50 - final DeviceId id = e.entity().id();
51 - final Timestamp local = e.timestamp();
52 - final Timestamp theirs = ads.get(id);
53 - if (theirs == null) {
54 - // they don't have it, suggest
55 - sug.put(id, e);
56 - // don't need theirs
57 - req.remove(id);
58 - } else if (local.compareTo(theirs) < 0) {
59 - // they got older one, suggest
60 - sug.put(id, e);
61 - // don't need theirs
62 - req.remove(id);
63 - } else if (local.equals(theirs)) {
64 - // same, don't need theirs
65 - req.remove(id);
66 - }
67 - }
68 -
69 - return new DeviceAntiEntropyReply(self, sug.build(), req);
70 - }
71 -
72 - /**
73 - * Creates a reply to request for values held locally.
74 - *
75 - * @param requests message containing the request
76 - * @param self node identifier representing local node
77 - * @param localValues local valeds held on this node
78 - * @return reply message
79 - */
80 - public static DeviceAntiEntropyReply reply(
81 - DeviceAntiEntropyReply requests,
82 - NodeId self,
83 - Map<DeviceId, VersionedValue<Device>> localValues
84 - ) {
85 -
86 - Set<DeviceId> reqs = requests.request();
87 -
88 - Map<DeviceId, VersionedValue<Device>> requested = new HashMap<>(reqs.size());
89 - for (DeviceId id : reqs) {
90 - final VersionedValue<Device> value = localValues.get(id);
91 - if (value != null) {
92 - requested.put(id, value);
93 - }
94 - }
95 -
96 - Set<DeviceId> empty = ImmutableSet.of();
97 - return new DeviceAntiEntropyReply(self, requested, empty);
98 - }
99 -
100 - // For serializer
101 - protected DeviceAntiEntropyReply() {}
102 -}
1 +package org.onlab.onos.store.device.impl;
2 +
3 +import static com.google.common.base.Preconditions.checkNotNull;
4 +import static org.onlab.onos.net.DefaultAnnotations.union;
5 +
6 +import java.util.Collections;
7 +import java.util.Map;
8 +import java.util.concurrent.ConcurrentHashMap;
9 +import java.util.concurrent.ConcurrentMap;
10 +
11 +import org.onlab.onos.net.PortNumber;
12 +import org.onlab.onos.net.SparseAnnotations;
13 +import org.onlab.onos.net.device.DefaultDeviceDescription;
14 +import org.onlab.onos.net.device.DefaultPortDescription;
15 +import org.onlab.onos.net.device.DeviceDescription;
16 +import org.onlab.onos.net.device.PortDescription;
17 +import org.onlab.onos.store.Timestamp;
18 +import org.onlab.onos.store.common.impl.Timestamped;
19 +
20 +/*
21 + * Collection of Description of a Device and Ports, given from a Provider.
22 + */
23 +class DeviceDescriptions {
24 +
25 + private volatile Timestamped<DeviceDescription> deviceDesc;
26 +
27 + private final ConcurrentMap<PortNumber, Timestamped<PortDescription>> portDescs;
28 +
29 + public DeviceDescriptions(Timestamped<DeviceDescription> desc) {
30 + this.deviceDesc = checkNotNull(desc);
31 + this.portDescs = new ConcurrentHashMap<>();
32 + }
33 +
34 + public Timestamp getLatestTimestamp() {
35 + Timestamp latest = deviceDesc.timestamp();
36 + for (Timestamped<PortDescription> desc : portDescs.values()) {
37 + if (desc.timestamp().compareTo(latest) > 0) {
38 + latest = desc.timestamp();
39 + }
40 + }
41 + return latest;
42 + }
43 +
44 + public Timestamped<DeviceDescription> getDeviceDesc() {
45 + return deviceDesc;
46 + }
47 +
48 + public Timestamped<PortDescription> getPortDesc(PortNumber number) {
49 + return portDescs.get(number);
50 + }
51 +
52 + public Map<PortNumber, Timestamped<PortDescription>> getPortDescs() {
53 + return Collections.unmodifiableMap(portDescs);
54 + }
55 +
56 + /**
57 + * Puts DeviceDescription, merging annotations as necessary.
58 + *
59 + * @param newDesc new DeviceDescription
60 + */
61 + public void putDeviceDesc(Timestamped<DeviceDescription> newDesc) {
62 + Timestamped<DeviceDescription> oldOne = deviceDesc;
63 + Timestamped<DeviceDescription> newOne = newDesc;
64 + if (oldOne != null) {
65 + SparseAnnotations merged = union(oldOne.value().annotations(),
66 + newDesc.value().annotations());
67 + newOne = new Timestamped<DeviceDescription>(
68 + new DefaultDeviceDescription(newDesc.value(), merged),
69 + newDesc.timestamp());
70 + }
71 + deviceDesc = newOne;
72 + }
73 +
74 + /**
75 + * Puts PortDescription, merging annotations as necessary.
76 + *
77 + * @param newDesc new PortDescription
78 + */
79 + public void putPortDesc(Timestamped<PortDescription> newDesc) {
80 + Timestamped<PortDescription> oldOne = portDescs.get(newDesc.value().portNumber());
81 + Timestamped<PortDescription> newOne = newDesc;
82 + if (oldOne != null) {
83 + SparseAnnotations merged = union(oldOne.value().annotations(),
84 + newDesc.value().annotations());
85 + newOne = new Timestamped<PortDescription>(
86 + new DefaultPortDescription(newDesc.value(), merged),
87 + newDesc.timestamp());
88 + }
89 + portDescs.put(newOne.value().portNumber(), newOne);
90 + }
91 +}
1 package org.onlab.onos.store.device.impl; 1 package org.onlab.onos.store.device.impl;
2 2
3 +import com.google.common.base.Function;
3 import com.google.common.collect.FluentIterable; 4 import com.google.common.collect.FluentIterable;
4 import com.google.common.collect.ImmutableList; 5 import com.google.common.collect.ImmutableList;
5 import com.google.common.collect.Maps; 6 import com.google.common.collect.Maps;
6 import com.google.common.collect.Sets; 7 import com.google.common.collect.Sets;
7 8
8 -import org.apache.commons.lang3.concurrent.ConcurrentException; 9 +import org.apache.commons.lang3.RandomUtils;
9 -import org.apache.commons.lang3.concurrent.ConcurrentInitializer;
10 import org.apache.felix.scr.annotations.Activate; 10 import org.apache.felix.scr.annotations.Activate;
11 import org.apache.felix.scr.annotations.Component; 11 import org.apache.felix.scr.annotations.Component;
12 import org.apache.felix.scr.annotations.Deactivate; 12 import org.apache.felix.scr.annotations.Deactivate;
...@@ -14,6 +14,8 @@ import org.apache.felix.scr.annotations.Reference; ...@@ -14,6 +14,8 @@ import org.apache.felix.scr.annotations.Reference;
14 import org.apache.felix.scr.annotations.ReferenceCardinality; 14 import org.apache.felix.scr.annotations.ReferenceCardinality;
15 import org.apache.felix.scr.annotations.Service; 15 import org.apache.felix.scr.annotations.Service;
16 import org.onlab.onos.cluster.ClusterService; 16 import org.onlab.onos.cluster.ClusterService;
17 +import org.onlab.onos.cluster.ControllerNode;
18 +import org.onlab.onos.cluster.NodeId;
17 import org.onlab.onos.net.AnnotationsUtil; 19 import org.onlab.onos.net.AnnotationsUtil;
18 import org.onlab.onos.net.DefaultAnnotations; 20 import org.onlab.onos.net.DefaultAnnotations;
19 import org.onlab.onos.net.DefaultDevice; 21 import org.onlab.onos.net.DefaultDevice;
...@@ -23,9 +25,6 @@ import org.onlab.onos.net.Device.Type; ...@@ -23,9 +25,6 @@ import org.onlab.onos.net.Device.Type;
23 import org.onlab.onos.net.DeviceId; 25 import org.onlab.onos.net.DeviceId;
24 import org.onlab.onos.net.Port; 26 import org.onlab.onos.net.Port;
25 import org.onlab.onos.net.PortNumber; 27 import org.onlab.onos.net.PortNumber;
26 -import org.onlab.onos.net.SparseAnnotations;
27 -import org.onlab.onos.net.device.DefaultDeviceDescription;
28 -import org.onlab.onos.net.device.DefaultPortDescription;
29 import org.onlab.onos.net.device.DeviceDescription; 28 import org.onlab.onos.net.device.DeviceDescription;
30 import org.onlab.onos.net.device.DeviceEvent; 29 import org.onlab.onos.net.device.DeviceEvent;
31 import org.onlab.onos.net.device.DeviceStore; 30 import org.onlab.onos.net.device.DeviceStore;
...@@ -38,18 +37,22 @@ import org.onlab.onos.store.Timestamp; ...@@ -38,18 +37,22 @@ import org.onlab.onos.store.Timestamp;
38 import org.onlab.onos.store.cluster.messaging.ClusterCommunicationService; 37 import org.onlab.onos.store.cluster.messaging.ClusterCommunicationService;
39 import org.onlab.onos.store.cluster.messaging.ClusterMessage; 38 import org.onlab.onos.store.cluster.messaging.ClusterMessage;
40 import org.onlab.onos.store.cluster.messaging.ClusterMessageHandler; 39 import org.onlab.onos.store.cluster.messaging.ClusterMessageHandler;
41 -import org.onlab.onos.store.common.impl.MastershipBasedTimestamp; 40 +import org.onlab.onos.store.cluster.messaging.MessageSubject;
42 import org.onlab.onos.store.common.impl.Timestamped; 41 import org.onlab.onos.store.common.impl.Timestamped;
43 -import org.onlab.onos.store.serializers.KryoPoolUtil; 42 +import org.onlab.onos.store.device.impl.peermsg.DeviceAntiEntropyAdvertisement;
43 +import org.onlab.onos.store.device.impl.peermsg.DeviceFragmentId;
44 +import org.onlab.onos.store.device.impl.peermsg.PortFragmentId;
44 import org.onlab.onos.store.serializers.KryoSerializer; 45 import org.onlab.onos.store.serializers.KryoSerializer;
45 -import org.onlab.onos.store.serializers.MastershipBasedTimestampSerializer; 46 +import org.onlab.onos.store.serializers.DistributedStoreSerializers;
46 import org.onlab.util.KryoPool; 47 import org.onlab.util.KryoPool;
47 import org.onlab.util.NewConcurrentHashMap; 48 import org.onlab.util.NewConcurrentHashMap;
48 import org.slf4j.Logger; 49 import org.slf4j.Logger;
49 50
50 import java.io.IOException; 51 import java.io.IOException;
51 import java.util.ArrayList; 52 import java.util.ArrayList;
53 +import java.util.Collection;
52 import java.util.Collections; 54 import java.util.Collections;
55 +import java.util.HashMap;
53 import java.util.HashSet; 56 import java.util.HashSet;
54 import java.util.Iterator; 57 import java.util.Iterator;
55 import java.util.List; 58 import java.util.List;
...@@ -57,19 +60,21 @@ import java.util.Map; ...@@ -57,19 +60,21 @@ import java.util.Map;
57 import java.util.Map.Entry; 60 import java.util.Map.Entry;
58 import java.util.Objects; 61 import java.util.Objects;
59 import java.util.Set; 62 import java.util.Set;
60 -import java.util.concurrent.ConcurrentHashMap;
61 import java.util.concurrent.ConcurrentMap; 63 import java.util.concurrent.ConcurrentMap;
62 -import java.util.concurrent.atomic.AtomicReference; 64 +import java.util.concurrent.ScheduledExecutorService;
65 +import java.util.concurrent.TimeUnit;
63 66
64 import static com.google.common.base.Preconditions.checkArgument; 67 import static com.google.common.base.Preconditions.checkArgument;
65 -import static com.google.common.base.Preconditions.checkNotNull;
66 import static com.google.common.base.Predicates.notNull; 68 import static com.google.common.base.Predicates.notNull;
69 +import static org.onlab.onos.cluster.ControllerNodeToNodeId.toNodeId;
67 import static org.onlab.onos.net.device.DeviceEvent.Type.*; 70 import static org.onlab.onos.net.device.DeviceEvent.Type.*;
68 import static org.slf4j.LoggerFactory.getLogger; 71 import static org.slf4j.LoggerFactory.getLogger;
69 import static org.apache.commons.lang3.concurrent.ConcurrentUtils.createIfAbsentUnchecked; 72 import static org.apache.commons.lang3.concurrent.ConcurrentUtils.createIfAbsentUnchecked;
70 import static org.onlab.onos.net.DefaultAnnotations.merge; 73 import static org.onlab.onos.net.DefaultAnnotations.merge;
71 -import static org.onlab.onos.net.DefaultAnnotations.union;
72 import static com.google.common.base.Verify.verify; 74 import static com.google.common.base.Verify.verify;
75 +import static org.onlab.util.Tools.namedThreads;
76 +import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
77 +import static org.onlab.onos.store.device.impl.GossipDeviceStoreMessageSubjects.DEVICE_ADVERTISE;
73 78
74 // TODO: give me a better name 79 // TODO: give me a better name
75 /** 80 /**
...@@ -86,8 +91,9 @@ public class GossipDeviceStore ...@@ -86,8 +91,9 @@ public class GossipDeviceStore
86 91
87 public static final String DEVICE_NOT_FOUND = "Device with ID %s not found"; 92 public static final String DEVICE_NOT_FOUND = "Device with ID %s not found";
88 93
89 - // TODO: Check if inner Map can be replaced with plain Map 94 + // TODO: Check if inner Map can be replaced with plain Map.
90 // innerMap is used to lock a Device, thus instance should never be replaced. 95 // innerMap is used to lock a Device, thus instance should never be replaced.
96 +
91 // collection of Description given from various providers 97 // collection of Description given from various providers
92 private final ConcurrentMap<DeviceId, 98 private final ConcurrentMap<DeviceId,
93 ConcurrentMap<ProviderId, DeviceDescriptions>> 99 ConcurrentMap<ProviderId, DeviceDescriptions>>
...@@ -113,25 +119,27 @@ public class GossipDeviceStore ...@@ -113,25 +119,27 @@ public class GossipDeviceStore
113 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 119 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
114 protected ClusterService clusterService; 120 protected ClusterService clusterService;
115 121
116 - private static final KryoSerializer SERIALIZER = new KryoSerializer() { 122 + protected static final KryoSerializer SERIALIZER = new KryoSerializer() {
117 @Override 123 @Override
118 protected void setupKryoPool() { 124 protected void setupKryoPool() {
119 serializerPool = KryoPool.newBuilder() 125 serializerPool = KryoPool.newBuilder()
120 - .register(KryoPoolUtil.API) 126 + .register(DistributedStoreSerializers.COMMON)
127 +
121 .register(InternalDeviceEvent.class, new InternalDeviceEventSerializer()) 128 .register(InternalDeviceEvent.class, new InternalDeviceEventSerializer())
122 .register(InternalDeviceOfflineEvent.class, new InternalDeviceOfflineEventSerializer()) 129 .register(InternalDeviceOfflineEvent.class, new InternalDeviceOfflineEventSerializer())
123 .register(InternalDeviceRemovedEvent.class) 130 .register(InternalDeviceRemovedEvent.class)
124 .register(InternalPortEvent.class, new InternalPortEventSerializer()) 131 .register(InternalPortEvent.class, new InternalPortEventSerializer())
125 .register(InternalPortStatusEvent.class, new InternalPortStatusEventSerializer()) 132 .register(InternalPortStatusEvent.class, new InternalPortStatusEventSerializer())
126 - .register(Timestamp.class) 133 + .register(DeviceAntiEntropyAdvertisement.class)
127 - .register(Timestamped.class) 134 + .register(DeviceFragmentId.class)
128 - .register(MastershipBasedTimestamp.class, new MastershipBasedTimestampSerializer()) 135 + .register(PortFragmentId.class)
129 .build() 136 .build()
130 .populate(1); 137 .populate(1);
131 } 138 }
132 -
133 }; 139 };
134 140
141 + private ScheduledExecutorService executor;
142 +
135 @Activate 143 @Activate
136 public void activate() { 144 public void activate() {
137 clusterCommunicator.addSubscriber( 145 clusterCommunicator.addSubscriber(
...@@ -144,11 +152,35 @@ public class GossipDeviceStore ...@@ -144,11 +152,35 @@ public class GossipDeviceStore
144 GossipDeviceStoreMessageSubjects.PORT_UPDATE, new InternalPortEventListener()); 152 GossipDeviceStoreMessageSubjects.PORT_UPDATE, new InternalPortEventListener());
145 clusterCommunicator.addSubscriber( 153 clusterCommunicator.addSubscriber(
146 GossipDeviceStoreMessageSubjects.PORT_STATUS_UPDATE, new InternalPortStatusEventListener()); 154 GossipDeviceStoreMessageSubjects.PORT_STATUS_UPDATE, new InternalPortStatusEventListener());
155 + clusterCommunicator.addSubscriber(
156 + GossipDeviceStoreMessageSubjects.DEVICE_ADVERTISE, new InternalDeviceAdvertisementListener());
157 +
158 + executor =
159 + newSingleThreadScheduledExecutor(namedThreads("anti-entropy-%d"));
160 +
161 + // TODO: Make these configurable
162 + long initialDelaySec = 5;
163 + long periodSec = 5;
164 + // start anti-entropy thread
165 + executor.scheduleAtFixedRate(new SendAdvertisementTask(),
166 + initialDelaySec, periodSec, TimeUnit.SECONDS);
167 +
147 log.info("Started"); 168 log.info("Started");
148 } 169 }
149 170
150 @Deactivate 171 @Deactivate
151 public void deactivate() { 172 public void deactivate() {
173 +
174 + executor.shutdownNow();
175 + try {
176 + boolean timedout = executor.awaitTermination(5, TimeUnit.SECONDS);
177 + if (timedout) {
178 + log.error("Timeout during executor shutdown");
179 + }
180 + } catch (InterruptedException e) {
181 + log.error("Error during executor shutdown", e);
182 + }
183 +
152 deviceDescs.clear(); 184 deviceDescs.clear();
153 devices.clear(); 185 devices.clear();
154 devicePorts.clear(); 186 devicePorts.clear();
...@@ -175,14 +207,19 @@ public class GossipDeviceStore ...@@ -175,14 +207,19 @@ public class GossipDeviceStore
175 public synchronized DeviceEvent createOrUpdateDevice(ProviderId providerId, 207 public synchronized DeviceEvent createOrUpdateDevice(ProviderId providerId,
176 DeviceId deviceId, 208 DeviceId deviceId,
177 DeviceDescription deviceDescription) { 209 DeviceDescription deviceDescription) {
178 - Timestamp newTimestamp = clockService.getTimestamp(deviceId); 210 + final Timestamp newTimestamp = clockService.getTimestamp(deviceId);
179 final Timestamped<DeviceDescription> deltaDesc = new Timestamped<>(deviceDescription, newTimestamp); 211 final Timestamped<DeviceDescription> deltaDesc = new Timestamped<>(deviceDescription, newTimestamp);
180 - DeviceEvent event = createOrUpdateDeviceInternal(providerId, deviceId, deltaDesc); 212 + final DeviceEvent event;
213 + final Timestamped<DeviceDescription> mergedDesc;
214 + synchronized (getDeviceDescriptions(deviceId)) {
215 + event = createOrUpdateDeviceInternal(providerId, deviceId, deltaDesc);
216 + mergedDesc = getDeviceDescriptions(deviceId).get(providerId).getDeviceDesc();
217 + }
181 if (event != null) { 218 if (event != null) {
182 log.info("Notifying peers of a device update topology event for providerId: {} and deviceId: {}", 219 log.info("Notifying peers of a device update topology event for providerId: {} and deviceId: {}",
183 providerId, deviceId); 220 providerId, deviceId);
184 try { 221 try {
185 - notifyPeers(new InternalDeviceEvent(providerId, deviceId, deltaDesc)); 222 + notifyPeers(new InternalDeviceEvent(providerId, deviceId, mergedDesc));
186 } catch (IOException e) { 223 } catch (IOException e) {
187 log.error("Failed to notify peers of a device update topology event for providerId: " 224 log.error("Failed to notify peers of a device update topology event for providerId: "
188 + providerId + " and deviceId: " + deviceId, e); 225 + providerId + " and deviceId: " + deviceId, e);
...@@ -286,8 +323,8 @@ public class GossipDeviceStore ...@@ -286,8 +323,8 @@ public class GossipDeviceStore
286 323
287 @Override 324 @Override
288 public DeviceEvent markOffline(DeviceId deviceId) { 325 public DeviceEvent markOffline(DeviceId deviceId) {
289 - Timestamp timestamp = clockService.getTimestamp(deviceId); 326 + final Timestamp timestamp = clockService.getTimestamp(deviceId);
290 - DeviceEvent event = markOfflineInternal(deviceId, timestamp); 327 + final DeviceEvent event = markOfflineInternal(deviceId, timestamp);
291 if (event != null) { 328 if (event != null) {
292 log.info("Notifying peers of a device offline topology event for deviceId: {}", 329 log.info("Notifying peers of a device offline topology event for deviceId: {}",
293 deviceId); 330 deviceId);
...@@ -359,17 +396,33 @@ public class GossipDeviceStore ...@@ -359,17 +396,33 @@ public class GossipDeviceStore
359 public synchronized List<DeviceEvent> updatePorts(ProviderId providerId, 396 public synchronized List<DeviceEvent> updatePorts(ProviderId providerId,
360 DeviceId deviceId, 397 DeviceId deviceId,
361 List<PortDescription> portDescriptions) { 398 List<PortDescription> portDescriptions) {
362 - Timestamp newTimestamp = clockService.getTimestamp(deviceId);
363 -
364 - Timestamped<List<PortDescription>> timestampedPortDescriptions =
365 - new Timestamped<>(portDescriptions, newTimestamp);
366 399
367 - List<DeviceEvent> events = updatePortsInternal(providerId, deviceId, timestampedPortDescriptions); 400 + final Timestamp newTimestamp = clockService.getTimestamp(deviceId);
401 +
402 + final Timestamped<List<PortDescription>> timestampedInput
403 + = new Timestamped<>(portDescriptions, newTimestamp);
404 + final List<DeviceEvent> events;
405 + final Timestamped<List<PortDescription>> merged;
406 +
407 + synchronized (getDeviceDescriptions(deviceId)) {
408 + events = updatePortsInternal(providerId, deviceId, timestampedInput);
409 + final DeviceDescriptions descs = getDeviceDescriptions(deviceId).get(providerId);
410 + List<PortDescription> mergedList =
411 + FluentIterable.from(portDescriptions)
412 + .transform(new Function<PortDescription, PortDescription>() {
413 + @Override
414 + public PortDescription apply(PortDescription input) {
415 + // lookup merged port description
416 + return descs.getPortDesc(input.portNumber()).value();
417 + }
418 + }).toList();
419 + merged = new Timestamped<List<PortDescription>>(mergedList, newTimestamp);
420 + }
368 if (!events.isEmpty()) { 421 if (!events.isEmpty()) {
369 log.info("Notifying peers of a port update topology event for providerId: {} and deviceId: {}", 422 log.info("Notifying peers of a port update topology event for providerId: {} and deviceId: {}",
370 providerId, deviceId); 423 providerId, deviceId);
371 try { 424 try {
372 - notifyPeers(new InternalPortEvent(providerId, deviceId, timestampedPortDescriptions)); 425 + notifyPeers(new InternalPortEvent(providerId, deviceId, merged));
373 } catch (IOException e) { 426 } catch (IOException e) {
374 log.error("Failed to notify peers of a port update topology event or providerId: " 427 log.error("Failed to notify peers of a port update topology event or providerId: "
375 + providerId + " and deviceId: " + deviceId, e); 428 + providerId + " and deviceId: " + deviceId, e);
...@@ -496,16 +549,25 @@ public class GossipDeviceStore ...@@ -496,16 +549,25 @@ public class GossipDeviceStore
496 } 549 }
497 550
498 @Override 551 @Override
499 - public synchronized DeviceEvent updatePortStatus(ProviderId providerId, DeviceId deviceId, 552 + public synchronized DeviceEvent updatePortStatus(ProviderId providerId,
500 - PortDescription portDescription) { 553 + DeviceId deviceId,
501 - Timestamp newTimestamp = clockService.getTimestamp(deviceId); 554 + PortDescription portDescription) {
502 - final Timestamped<PortDescription> deltaDesc = new Timestamped<>(portDescription, newTimestamp); 555 +
503 - DeviceEvent event = updatePortStatusInternal(providerId, deviceId, deltaDesc); 556 + final Timestamp newTimestamp = clockService.getTimestamp(deviceId);
557 + final Timestamped<PortDescription> deltaDesc
558 + = new Timestamped<>(portDescription, newTimestamp);
559 + final DeviceEvent event;
560 + final Timestamped<PortDescription> mergedDesc;
561 + synchronized (getDeviceDescriptions(deviceId)) {
562 + event = updatePortStatusInternal(providerId, deviceId, deltaDesc);
563 + mergedDesc = getDeviceDescriptions(deviceId).get(providerId)
564 + .getPortDesc(portDescription.portNumber());
565 + }
504 if (event != null) { 566 if (event != null) {
505 log.info("Notifying peers of a port status update topology event for providerId: {} and deviceId: {}", 567 log.info("Notifying peers of a port status update topology event for providerId: {} and deviceId: {}",
506 providerId, deviceId); 568 providerId, deviceId);
507 try { 569 try {
508 - notifyPeers(new InternalPortStatusEvent(providerId, deviceId, deltaDesc)); 570 + notifyPeers(new InternalPortStatusEvent(providerId, deviceId, mergedDesc));
509 } catch (IOException e) { 571 } catch (IOException e) {
510 log.error("Failed to notify peers of a port status update topology event or providerId: " 572 log.error("Failed to notify peers of a port status update topology event or providerId: "
511 + providerId + " and deviceId: " + deviceId, e); 573 + providerId + " and deviceId: " + deviceId, e);
...@@ -543,14 +605,14 @@ public class GossipDeviceStore ...@@ -543,14 +605,14 @@ public class GossipDeviceStore
543 605
544 final Timestamped<PortDescription> existingPortDesc = descs.getPortDesc(number); 606 final Timestamped<PortDescription> existingPortDesc = descs.getPortDesc(number);
545 if (existingPortDesc == null || 607 if (existingPortDesc == null ||
546 - deltaDesc == existingPortDesc ||
547 deltaDesc.isNewer(existingPortDesc)) { 608 deltaDesc.isNewer(existingPortDesc)) {
548 // on new port or valid update 609 // on new port or valid update
549 // update description 610 // update description
550 descs.putPortDesc(deltaDesc); 611 descs.putPortDesc(deltaDesc);
551 newPort = composePort(device, number, descsMap); 612 newPort = composePort(device, number, descsMap);
552 } else { 613 } else {
553 - // outdated event, ignored. 614 + // same or outdated event, ignored.
615 + log.trace("ignore same or outdated {} >= {}", existingPortDesc, deltaDesc);
554 return null; 616 return null;
555 } 617 }
556 618
...@@ -627,6 +689,14 @@ public class GossipDeviceStore ...@@ -627,6 +689,14 @@ public class GossipDeviceStore
627 } 689 }
628 } 690 }
629 691
692 + /**
693 + * Checks if given timestamp is superseded by removal request
694 + * with more recent timestamp.
695 + *
696 + * @param deviceId identifier of a device
697 + * @param timestampToCheck timestamp of an event to check
698 + * @return true if device is already removed
699 + */
630 private boolean isDeviceRemoved(DeviceId deviceId, Timestamp timestampToCheck) { 700 private boolean isDeviceRemoved(DeviceId deviceId, Timestamp timestampToCheck) {
631 Timestamp removalTimestamp = removalRequest.get(deviceId); 701 Timestamp removalTimestamp = removalRequest.get(deviceId);
632 if (removalTimestamp != null && 702 if (removalTimestamp != null &&
...@@ -645,7 +715,7 @@ public class GossipDeviceStore ...@@ -645,7 +715,7 @@ public class GossipDeviceStore
645 * @return Device instance 715 * @return Device instance
646 */ 716 */
647 private Device composeDevice(DeviceId deviceId, 717 private Device composeDevice(DeviceId deviceId,
648 - ConcurrentMap<ProviderId, DeviceDescriptions> providerDescs) { 718 + Map<ProviderId, DeviceDescriptions> providerDescs) {
649 719
650 checkArgument(!providerDescs.isEmpty(), "No Device descriptions supplied"); 720 checkArgument(!providerDescs.isEmpty(), "No Device descriptions supplied");
651 721
...@@ -667,7 +737,7 @@ public class GossipDeviceStore ...@@ -667,7 +737,7 @@ public class GossipDeviceStore
667 continue; 737 continue;
668 } 738 }
669 // TODO: should keep track of Description timestamp 739 // TODO: should keep track of Description timestamp
670 - // and only merge conflicting keys when timestamp is newer 740 + // and only merge conflicting keys when timestamp is newer.
671 // Currently assuming there will never be a key conflict between 741 // Currently assuming there will never be a key conflict between
672 // providers 742 // providers
673 743
...@@ -708,7 +778,7 @@ public class GossipDeviceStore ...@@ -708,7 +778,7 @@ public class GossipDeviceStore
708 continue; 778 continue;
709 } 779 }
710 // TODO: should keep track of Description timestamp 780 // TODO: should keep track of Description timestamp
711 - // and only merge conflicting keys when timestamp is newer 781 + // and only merge conflicting keys when timestamp is newer.
712 // Currently assuming there will never be a key conflict between 782 // Currently assuming there will never be a key conflict between
713 // providers 783 // providers
714 784
...@@ -745,129 +815,312 @@ public class GossipDeviceStore ...@@ -745,129 +815,312 @@ public class GossipDeviceStore
745 return providerDescs.get(pid); 815 return providerDescs.get(pid);
746 } 816 }
747 817
748 - public static final class InitDeviceDescs 818 + // TODO: should we be throwing exception?
749 - implements ConcurrentInitializer<DeviceDescriptions> { 819 + private void unicastMessage(NodeId recipient, MessageSubject subject, Object event) throws IOException {
820 + ClusterMessage message = new ClusterMessage(
821 + clusterService.getLocalNode().id(),
822 + subject,
823 + SERIALIZER.encode(event));
824 + clusterCommunicator.unicast(message, recipient);
825 + }
750 826
751 - private final Timestamped<DeviceDescription> deviceDesc; 827 + // TODO: should we be throwing exception?
828 + private void broadcastMessage(MessageSubject subject, Object event) throws IOException {
829 + ClusterMessage message = new ClusterMessage(
830 + clusterService.getLocalNode().id(),
831 + subject,
832 + SERIALIZER.encode(event));
833 + clusterCommunicator.broadcast(message);
834 + }
752 835
753 - public InitDeviceDescs(Timestamped<DeviceDescription> deviceDesc) { 836 + private void notifyPeers(InternalDeviceEvent event) throws IOException {
754 - this.deviceDesc = checkNotNull(deviceDesc); 837 + broadcastMessage(GossipDeviceStoreMessageSubjects.DEVICE_UPDATE, event);
755 - }
756 - @Override
757 - public DeviceDescriptions get() throws ConcurrentException {
758 - return new DeviceDescriptions(deviceDesc);
759 - }
760 } 838 }
761 839
840 + private void notifyPeers(InternalDeviceOfflineEvent event) throws IOException {
841 + broadcastMessage(GossipDeviceStoreMessageSubjects.DEVICE_OFFLINE, event);
842 + }
762 843
763 - /** 844 + private void notifyPeers(InternalDeviceRemovedEvent event) throws IOException {
764 - * Collection of Description of a Device and it's Ports given from a Provider. 845 + broadcastMessage(GossipDeviceStoreMessageSubjects.DEVICE_REMOVED, event);
765 - */ 846 + }
766 - public static class DeviceDescriptions {
767 847
768 - private final AtomicReference<Timestamped<DeviceDescription>> deviceDesc; 848 + private void notifyPeers(InternalPortEvent event) throws IOException {
769 - private final ConcurrentMap<PortNumber, Timestamped<PortDescription>> portDescs; 849 + broadcastMessage(GossipDeviceStoreMessageSubjects.PORT_UPDATE, event);
850 + }
770 851
771 - public DeviceDescriptions(Timestamped<DeviceDescription> desc) { 852 + private void notifyPeers(InternalPortStatusEvent event) throws IOException {
772 - this.deviceDesc = new AtomicReference<>(checkNotNull(desc)); 853 + broadcastMessage(GossipDeviceStoreMessageSubjects.PORT_STATUS_UPDATE, event);
773 - this.portDescs = new ConcurrentHashMap<>(); 854 + }
774 - }
775 855
776 - Timestamp getLatestTimestamp() { 856 + private void notifyPeer(NodeId recipient, InternalDeviceEvent event) {
777 - Timestamp latest = deviceDesc.get().timestamp(); 857 + try {
778 - for (Timestamped<PortDescription> desc : portDescs.values()) { 858 + unicastMessage(recipient, GossipDeviceStoreMessageSubjects.DEVICE_UPDATE, event);
779 - if (desc.timestamp().compareTo(latest) > 0) { 859 + } catch (IOException e) {
780 - latest = desc.timestamp(); 860 + log.error("Failed to send" + event + " to " + recipient, e);
781 - }
782 - }
783 - return latest;
784 } 861 }
862 + }
785 863
786 - public Timestamped<DeviceDescription> getDeviceDesc() { 864 + private void notifyPeer(NodeId recipient, InternalDeviceOfflineEvent event) {
787 - return deviceDesc.get(); 865 + try {
866 + unicastMessage(recipient, GossipDeviceStoreMessageSubjects.DEVICE_OFFLINE, event);
867 + } catch (IOException e) {
868 + log.error("Failed to send" + event + " to " + recipient, e);
788 } 869 }
870 + }
789 871
790 - public Timestamped<PortDescription> getPortDesc(PortNumber number) { 872 + private void notifyPeer(NodeId recipient, InternalDeviceRemovedEvent event) {
791 - return portDescs.get(number); 873 + try {
874 + unicastMessage(recipient, GossipDeviceStoreMessageSubjects.DEVICE_REMOVED, event);
875 + } catch (IOException e) {
876 + log.error("Failed to send" + event + " to " + recipient, e);
792 } 877 }
878 + }
793 879
794 - /** 880 + private void notifyPeer(NodeId recipient, InternalPortEvent event) {
795 - * Puts DeviceDescription, merging annotations as necessary. 881 + try {
796 - * 882 + unicastMessage(recipient, GossipDeviceStoreMessageSubjects.PORT_UPDATE, event);
797 - * @param newDesc new DeviceDescription 883 + } catch (IOException e) {
798 - * @return previous DeviceDescription 884 + log.error("Failed to send" + event + " to " + recipient, e);
799 - */
800 - public synchronized Timestamped<DeviceDescription> putDeviceDesc(Timestamped<DeviceDescription> newDesc) {
801 - Timestamped<DeviceDescription> oldOne = deviceDesc.get();
802 - Timestamped<DeviceDescription> newOne = newDesc;
803 - if (oldOne != null) {
804 - SparseAnnotations merged = union(oldOne.value().annotations(),
805 - newDesc.value().annotations());
806 - newOne = new Timestamped<DeviceDescription>(
807 - new DefaultDeviceDescription(newDesc.value(), merged),
808 - newDesc.timestamp());
809 - }
810 - return deviceDesc.getAndSet(newOne);
811 - }
812 -
813 - /**
814 - * Puts PortDescription, merging annotations as necessary.
815 - *
816 - * @param newDesc new PortDescription
817 - * @return previous PortDescription
818 - */
819 - public synchronized Timestamped<PortDescription> putPortDesc(Timestamped<PortDescription> newDesc) {
820 - Timestamped<PortDescription> oldOne = portDescs.get(newDesc.value().portNumber());
821 - Timestamped<PortDescription> newOne = newDesc;
822 - if (oldOne != null) {
823 - SparseAnnotations merged = union(oldOne.value().annotations(),
824 - newDesc.value().annotations());
825 - newOne = new Timestamped<PortDescription>(
826 - new DefaultPortDescription(newDesc.value(), merged),
827 - newDesc.timestamp());
828 - }
829 - return portDescs.put(newOne.value().portNumber(), newOne);
830 } 885 }
831 } 886 }
832 887
833 - private void notifyPeers(InternalDeviceEvent event) throws IOException { 888 + private void notifyPeer(NodeId recipient, InternalPortStatusEvent event) {
834 - ClusterMessage message = new ClusterMessage( 889 + try {
835 - clusterService.getLocalNode().id(), 890 + unicastMessage(recipient, GossipDeviceStoreMessageSubjects.PORT_STATUS_UPDATE, event);
836 - GossipDeviceStoreMessageSubjects.DEVICE_UPDATE, 891 + } catch (IOException e) {
837 - SERIALIZER.encode(event)); 892 + log.error("Failed to send" + event + " to " + recipient, e);
838 - clusterCommunicator.broadcast(message); 893 + }
839 } 894 }
840 895
841 - private void notifyPeers(InternalDeviceOfflineEvent event) throws IOException { 896 + private DeviceAntiEntropyAdvertisement createAdvertisement() {
842 - ClusterMessage message = new ClusterMessage( 897 + final NodeId self = clusterService.getLocalNode().id();
843 - clusterService.getLocalNode().id(), 898 +
844 - GossipDeviceStoreMessageSubjects.DEVICE_OFFLINE, 899 + Map<DeviceFragmentId, Timestamp> devices = new HashMap<>(deviceDescs.size());
845 - SERIALIZER.encode(event)); 900 + final int portsPerDevice = 8; // random guess to minimize reallocation
846 - clusterCommunicator.broadcast(message); 901 + Map<PortFragmentId, Timestamp> ports = new HashMap<>(devices.size() * portsPerDevice);
902 + Map<DeviceId, Timestamp> offline = new HashMap<>(devices.size());
903 +
904 + for (Entry<DeviceId, ConcurrentMap<ProviderId, DeviceDescriptions>>
905 + provs : deviceDescs.entrySet()) {
906 +
907 + final DeviceId deviceId = provs.getKey();
908 + final ConcurrentMap<ProviderId, DeviceDescriptions> devDescs = provs.getValue();
909 + synchronized (devDescs) {
910 +
911 + offline.put(deviceId, this.offline.get(deviceId));
912 +
913 + for (Entry<ProviderId, DeviceDescriptions>
914 + prov : devDescs.entrySet()) {
915 +
916 + final ProviderId provId = prov.getKey();
917 + final DeviceDescriptions descs = prov.getValue();
918 +
919 + devices.put(new DeviceFragmentId(deviceId, provId),
920 + descs.getDeviceDesc().timestamp());
921 +
922 + for (Entry<PortNumber, Timestamped<PortDescription>>
923 + portDesc : descs.getPortDescs().entrySet()) {
924 +
925 + final PortNumber number = portDesc.getKey();
926 + ports.put(new PortFragmentId(deviceId, provId, number),
927 + portDesc.getValue().timestamp());
928 + }
929 + }
930 + }
931 + }
932 +
933 + return new DeviceAntiEntropyAdvertisement(self, devices, ports, offline);
847 } 934 }
848 935
849 - private void notifyPeers(InternalDeviceRemovedEvent event) throws IOException { 936 + /**
850 - ClusterMessage message = new ClusterMessage( 937 + * Responds to anti-entropy advertisement message.
851 - clusterService.getLocalNode().id(), 938 + * <P>
852 - GossipDeviceStoreMessageSubjects.DEVICE_REMOVED, 939 + * Notify sender about out-dated information using regular replication message.
853 - SERIALIZER.encode(event)); 940 + * Send back advertisement to sender if not in sync.
854 - clusterCommunicator.broadcast(message); 941 + *
942 + * @param advertisement to respond to
943 + */
944 + private void handleAdvertisement(DeviceAntiEntropyAdvertisement advertisement) {
945 +
946 + final NodeId sender = advertisement.sender();
947 +
948 + Map<DeviceFragmentId, Timestamp> devAds = new HashMap<>(advertisement.deviceFingerPrints());
949 + Map<PortFragmentId, Timestamp> portAds = new HashMap<>(advertisement.ports());
950 + Map<DeviceId, Timestamp> offlineAds = new HashMap<>(advertisement.offline());
951 +
952 + // Fragments to request
953 + Collection<DeviceFragmentId> reqDevices = new ArrayList<>();
954 + Collection<PortFragmentId> reqPorts = new ArrayList<>();
955 +
956 + for (Entry<DeviceId, ConcurrentMap<ProviderId, DeviceDescriptions>> de : deviceDescs.entrySet()) {
957 + final DeviceId deviceId = de.getKey();
958 + final Map<ProviderId, DeviceDescriptions> lDevice = de.getValue();
959 +
960 + synchronized (lDevice) {
961 + // latestTimestamp across provider
962 + // Note: can be null initially
963 + Timestamp localLatest = offline.get(deviceId);
964 +
965 + // handle device Ads
966 + for (Entry<ProviderId, DeviceDescriptions> prov : lDevice.entrySet()) {
967 + final ProviderId provId = prov.getKey();
968 + final DeviceDescriptions lDeviceDescs = prov.getValue();
969 +
970 + final DeviceFragmentId devFragId = new DeviceFragmentId(deviceId, provId);
971 +
972 +
973 + Timestamped<DeviceDescription> lProvDevice = lDeviceDescs.getDeviceDesc();
974 + Timestamp advDevTimestamp = devAds.get(devFragId);
975 +
976 + if (advDevTimestamp == null || lProvDevice.isNewer(advDevTimestamp)) {
977 + // remote does not have it or outdated, suggest
978 + notifyPeer(sender, new InternalDeviceEvent(provId, deviceId, lProvDevice));
979 + } else if (!lProvDevice.timestamp().equals(advDevTimestamp)) {
980 + // local is outdated, request
981 + reqDevices.add(devFragId);
982 + }
983 +
984 + // handle port Ads
985 + for (Entry<PortNumber, Timestamped<PortDescription>>
986 + pe : lDeviceDescs.getPortDescs().entrySet()) {
987 +
988 + final PortNumber num = pe.getKey();
989 + final Timestamped<PortDescription> lPort = pe.getValue();
990 +
991 + final PortFragmentId portFragId = new PortFragmentId(deviceId, provId, num);
992 +
993 + Timestamp advPortTimestamp = portAds.get(portFragId);
994 + if (advPortTimestamp == null || lPort.isNewer(advPortTimestamp)) {
995 + // remote does not have it or outdated, suggest
996 + notifyPeer(sender, new InternalPortStatusEvent(provId, deviceId, lPort));
997 + } else if (!lPort.timestamp().equals(advPortTimestamp)) {
998 + // local is outdated, request
999 + log.trace("need update {} < {}", lPort.timestamp(), advPortTimestamp);
1000 + reqPorts.add(portFragId);
1001 + }
1002 +
1003 + // remove port Ad already processed
1004 + portAds.remove(portFragId);
1005 + } // end local port loop
1006 +
1007 + // remove device Ad already processed
1008 + devAds.remove(devFragId);
1009 +
1010 + // find latest and update
1011 + final Timestamp providerLatest = lDeviceDescs.getLatestTimestamp();
1012 + if (localLatest == null ||
1013 + providerLatest.compareTo(localLatest) > 0) {
1014 + localLatest = providerLatest;
1015 + }
1016 + } // end local provider loop
1017 +
1018 + // checking if remote timestamp is more recent.
1019 + Timestamp rOffline = offlineAds.get(deviceId);
1020 + if (rOffline != null &&
1021 + rOffline.compareTo(localLatest) > 0) {
1022 + // remote offline timestamp suggests that the
1023 + // device is off-line
1024 + markOfflineInternal(deviceId, rOffline);
1025 + }
1026 +
1027 + Timestamp lOffline = offline.get(deviceId);
1028 + if (lOffline != null && rOffline == null) {
1029 + // locally offline, but remote is online, suggest offline
1030 + notifyPeer(sender, new InternalDeviceOfflineEvent(deviceId, lOffline));
1031 + }
1032 +
1033 + // remove device offline Ad already processed
1034 + offlineAds.remove(deviceId);
1035 + } // end local device loop
1036 + } // device lock
1037 +
1038 + // If there is any Ads left, request them
1039 + log.trace("Ads left {}, {}", devAds, portAds);
1040 + reqDevices.addAll(devAds.keySet());
1041 + reqPorts.addAll(portAds.keySet());
1042 +
1043 + if (reqDevices.isEmpty() && reqPorts.isEmpty()) {
1044 + log.trace("Nothing to request to remote peer {}", sender);
1045 + return;
1046 + }
1047 +
1048 + log.info("Need to sync {} {}", reqDevices, reqPorts);
1049 +
1050 + // 2-way Anti-Entropy for now
1051 + try {
1052 + unicastMessage(sender, DEVICE_ADVERTISE, createAdvertisement());
1053 + } catch (IOException e) {
1054 + log.error("Failed to send response advertisement to " + sender, e);
1055 + }
1056 +
1057 +// Sketch of 3-way Anti-Entropy
1058 +// DeviceAntiEntropyRequest request = new DeviceAntiEntropyRequest(self, reqDevices, reqPorts);
1059 +// ClusterMessage message = new ClusterMessage(
1060 +// clusterService.getLocalNode().id(),
1061 +// GossipDeviceStoreMessageSubjects.DEVICE_REQUEST,
1062 +// SERIALIZER.encode(request));
1063 +//
1064 +// try {
1065 +// clusterCommunicator.unicast(message, advertisement.sender());
1066 +// } catch (IOException e) {
1067 +// log.error("Failed to send advertisement reply to "
1068 +// + advertisement.sender(), e);
1069 +// }
855 } 1070 }
856 1071
857 - private void notifyPeers(InternalPortEvent event) throws IOException { 1072 + private void notifyDelegateIfNotNull(DeviceEvent event) {
858 - ClusterMessage message = new ClusterMessage( 1073 + if (event != null) {
859 - clusterService.getLocalNode().id(), 1074 + notifyDelegate(event);
860 - GossipDeviceStoreMessageSubjects.PORT_UPDATE, 1075 + }
861 - SERIALIZER.encode(event));
862 - clusterCommunicator.broadcast(message);
863 } 1076 }
864 1077
865 - private void notifyPeers(InternalPortStatusEvent event) throws IOException { 1078 + private final class SendAdvertisementTask implements Runnable {
866 - ClusterMessage message = new ClusterMessage( 1079 +
867 - clusterService.getLocalNode().id(), 1080 + @Override
868 - GossipDeviceStoreMessageSubjects.PORT_STATUS_UPDATE, 1081 + public void run() {
869 - SERIALIZER.encode(event)); 1082 + if (Thread.currentThread().isInterrupted()) {
870 - clusterCommunicator.broadcast(message); 1083 + log.info("Interrupted, quitting");
1084 + return;
1085 + }
1086 +
1087 + try {
1088 + final NodeId self = clusterService.getLocalNode().id();
1089 + Set<ControllerNode> nodes = clusterService.getNodes();
1090 +
1091 + ImmutableList<NodeId> nodeIds = FluentIterable.from(nodes)
1092 + .transform(toNodeId())
1093 + .toList();
1094 +
1095 + if (nodeIds.size() == 1 && nodeIds.get(0).equals(self)) {
1096 + log.info("No other peers in the cluster.");
1097 + return;
1098 + }
1099 +
1100 + NodeId peer;
1101 + do {
1102 + int idx = RandomUtils.nextInt(0, nodeIds.size());
1103 + peer = nodeIds.get(idx);
1104 + } while (peer.equals(self));
1105 +
1106 + DeviceAntiEntropyAdvertisement ad = createAdvertisement();
1107 +
1108 + if (Thread.currentThread().isInterrupted()) {
1109 + log.info("Interrupted, quitting");
1110 + return;
1111 + }
1112 +
1113 + try {
1114 + unicastMessage(peer, DEVICE_ADVERTISE, ad);
1115 + } catch (IOException e) {
1116 + log.error("Failed to send anti-entropy advertisement", e);
1117 + return;
1118 + }
1119 + } catch (Exception e) {
1120 + // catch all Exception to avoid Scheduled task being suppressed.
1121 + log.error("Exception thrown while sending advertisement", e);
1122 + }
1123 + }
871 } 1124 }
872 1125
873 private class InternalDeviceEventListener implements ClusterMessageHandler { 1126 private class InternalDeviceEventListener implements ClusterMessageHandler {
...@@ -881,7 +1134,7 @@ public class GossipDeviceStore ...@@ -881,7 +1134,7 @@ public class GossipDeviceStore
881 DeviceId deviceId = event.deviceId(); 1134 DeviceId deviceId = event.deviceId();
882 Timestamped<DeviceDescription> deviceDescription = event.deviceDescription(); 1135 Timestamped<DeviceDescription> deviceDescription = event.deviceDescription();
883 1136
884 - createOrUpdateDeviceInternal(providerId, deviceId, deviceDescription); 1137 + notifyDelegateIfNotNull(createOrUpdateDeviceInternal(providerId, deviceId, deviceDescription));
885 } 1138 }
886 } 1139 }
887 1140
...@@ -895,7 +1148,7 @@ public class GossipDeviceStore ...@@ -895,7 +1148,7 @@ public class GossipDeviceStore
895 DeviceId deviceId = event.deviceId(); 1148 DeviceId deviceId = event.deviceId();
896 Timestamp timestamp = event.timestamp(); 1149 Timestamp timestamp = event.timestamp();
897 1150
898 - markOfflineInternal(deviceId, timestamp); 1151 + notifyDelegateIfNotNull(markOfflineInternal(deviceId, timestamp));
899 } 1152 }
900 } 1153 }
901 1154
...@@ -909,7 +1162,7 @@ public class GossipDeviceStore ...@@ -909,7 +1162,7 @@ public class GossipDeviceStore
909 DeviceId deviceId = event.deviceId(); 1162 DeviceId deviceId = event.deviceId();
910 Timestamp timestamp = event.timestamp(); 1163 Timestamp timestamp = event.timestamp();
911 1164
912 - removeDeviceInternal(deviceId, timestamp); 1165 + notifyDelegateIfNotNull(removeDeviceInternal(deviceId, timestamp));
913 } 1166 }
914 } 1167 }
915 1168
...@@ -924,7 +1177,7 @@ public class GossipDeviceStore ...@@ -924,7 +1177,7 @@ public class GossipDeviceStore
924 DeviceId deviceId = event.deviceId(); 1177 DeviceId deviceId = event.deviceId();
925 Timestamped<List<PortDescription>> portDescriptions = event.portDescriptions(); 1178 Timestamped<List<PortDescription>> portDescriptions = event.portDescriptions();
926 1179
927 - updatePortsInternal(providerId, deviceId, portDescriptions); 1180 + notifyDelegate(updatePortsInternal(providerId, deviceId, portDescriptions));
928 } 1181 }
929 } 1182 }
930 1183
...@@ -934,12 +1187,24 @@ public class GossipDeviceStore ...@@ -934,12 +1187,24 @@ public class GossipDeviceStore
934 1187
935 log.info("Received port status update event from peer: {}", message.sender()); 1188 log.info("Received port status update event from peer: {}", message.sender());
936 InternalPortStatusEvent event = (InternalPortStatusEvent) SERIALIZER.decode(message.payload()); 1189 InternalPortStatusEvent event = (InternalPortStatusEvent) SERIALIZER.decode(message.payload());
1190 + log.info("{}", event);
937 1191
938 ProviderId providerId = event.providerId(); 1192 ProviderId providerId = event.providerId();
939 DeviceId deviceId = event.deviceId(); 1193 DeviceId deviceId = event.deviceId();
940 Timestamped<PortDescription> portDescription = event.portDescription(); 1194 Timestamped<PortDescription> portDescription = event.portDescription();
941 1195
942 - updatePortStatusInternal(providerId, deviceId, portDescription); 1196 + notifyDelegateIfNotNull(updatePortStatusInternal(providerId, deviceId, portDescription));
1197 + }
1198 + }
1199 +
1200 + private final class InternalDeviceAdvertisementListener
1201 + implements ClusterMessageHandler {
1202 +
1203 + @Override
1204 + public void handle(ClusterMessage message) {
1205 + log.info("Received Device advertisement from peer: {}", message.sender());
1206 + DeviceAntiEntropyAdvertisement advertisement = SERIALIZER.decode(message.payload());
1207 + handleAdvertisement(advertisement);
943 } 1208 }
944 } 1209 }
945 } 1210 }
......
...@@ -2,6 +2,7 @@ package org.onlab.onos.store.device.impl; ...@@ -2,6 +2,7 @@ package org.onlab.onos.store.device.impl;
2 2
3 import org.onlab.onos.store.cluster.messaging.MessageSubject; 3 import org.onlab.onos.store.cluster.messaging.MessageSubject;
4 4
5 +// TODO: add prefix to assure uniqueness.
5 /** 6 /**
6 * MessageSubjects used by GossipDeviceStore peer-peer communication. 7 * MessageSubjects used by GossipDeviceStore peer-peer communication.
7 */ 8 */
...@@ -14,4 +15,8 @@ public final class GossipDeviceStoreMessageSubjects { ...@@ -14,4 +15,8 @@ public final class GossipDeviceStoreMessageSubjects {
14 public static final MessageSubject DEVICE_REMOVED = new MessageSubject("peer-device-removed"); 15 public static final MessageSubject DEVICE_REMOVED = new MessageSubject("peer-device-removed");
15 public static final MessageSubject PORT_UPDATE = new MessageSubject("peer-port-update"); 16 public static final MessageSubject PORT_UPDATE = new MessageSubject("peer-port-update");
16 public static final MessageSubject PORT_STATUS_UPDATE = new MessageSubject("peer-port-status-update"); 17 public static final MessageSubject PORT_STATUS_UPDATE = new MessageSubject("peer-port-status-update");
18 +
19 + public static final MessageSubject DEVICE_ADVERTISE = new MessageSubject("peer-device-advertisements");
20 + // to be used with 3-way anti-entropy process
21 + public static final MessageSubject DEVICE_REQUEST = new MessageSubject("peer-device-request");
17 } 22 }
......
1 +package org.onlab.onos.store.device.impl;
2 +
3 +import static com.google.common.base.Preconditions.checkNotNull;
4 +
5 +import org.apache.commons.lang3.concurrent.ConcurrentException;
6 +import org.apache.commons.lang3.concurrent.ConcurrentInitializer;
7 +import org.onlab.onos.net.device.DeviceDescription;
8 +import org.onlab.onos.store.common.impl.Timestamped;
9 +
10 +// FIXME: consider removing this class
11 +public final class InitDeviceDescs
12 + implements ConcurrentInitializer<DeviceDescriptions> {
13 +
14 + private final Timestamped<DeviceDescription> deviceDesc;
15 +
16 + public InitDeviceDescs(Timestamped<DeviceDescription> deviceDesc) {
17 + this.deviceDesc = checkNotNull(deviceDesc);
18 + }
19 + @Override
20 + public DeviceDescriptions get() throws ConcurrentException {
21 + return new DeviceDescriptions(deviceDesc);
22 + }
23 +}
...\ No newline at end of file ...\ No newline at end of file
...@@ -5,6 +5,8 @@ import org.onlab.onos.net.device.DeviceDescription; ...@@ -5,6 +5,8 @@ import org.onlab.onos.net.device.DeviceDescription;
5 import org.onlab.onos.net.provider.ProviderId; 5 import org.onlab.onos.net.provider.ProviderId;
6 import org.onlab.onos.store.common.impl.Timestamped; 6 import org.onlab.onos.store.common.impl.Timestamped;
7 7
8 +import com.google.common.base.MoreObjects;
9 +
8 /** 10 /**
9 * Information published by GossipDeviceStore to notify peers of a device 11 * Information published by GossipDeviceStore to notify peers of a device
10 * change event. 12 * change event.
...@@ -36,6 +38,15 @@ public class InternalDeviceEvent { ...@@ -36,6 +38,15 @@ public class InternalDeviceEvent {
36 return deviceDescription; 38 return deviceDescription;
37 } 39 }
38 40
41 + @Override
42 + public String toString() {
43 + return MoreObjects.toStringHelper(getClass())
44 + .add("providerId", providerId)
45 + .add("deviceId", deviceId)
46 + .add("deviceDescription", deviceDescription)
47 + .toString();
48 + }
49 +
39 // for serializer 50 // for serializer
40 protected InternalDeviceEvent() { 51 protected InternalDeviceEvent() {
41 this.providerId = null; 52 this.providerId = null;
......
...@@ -3,6 +3,8 @@ package org.onlab.onos.store.device.impl; ...@@ -3,6 +3,8 @@ package org.onlab.onos.store.device.impl;
3 import org.onlab.onos.net.DeviceId; 3 import org.onlab.onos.net.DeviceId;
4 import org.onlab.onos.store.Timestamp; 4 import org.onlab.onos.store.Timestamp;
5 5
6 +import com.google.common.base.MoreObjects;
7 +
6 /** 8 /**
7 * Information published by GossipDeviceStore to notify peers of a device 9 * Information published by GossipDeviceStore to notify peers of a device
8 * going offline. 10 * going offline.
...@@ -30,6 +32,14 @@ public class InternalDeviceOfflineEvent { ...@@ -30,6 +32,14 @@ public class InternalDeviceOfflineEvent {
30 return timestamp; 32 return timestamp;
31 } 33 }
32 34
35 + @Override
36 + public String toString() {
37 + return MoreObjects.toStringHelper(getClass())
38 + .add("deviceId", deviceId)
39 + .add("timestamp", timestamp)
40 + .toString();
41 + }
42 +
33 // for serializer 43 // for serializer
34 @SuppressWarnings("unused") 44 @SuppressWarnings("unused")
35 private InternalDeviceOfflineEvent() { 45 private InternalDeviceOfflineEvent() {
......
...@@ -3,6 +3,8 @@ package org.onlab.onos.store.device.impl; ...@@ -3,6 +3,8 @@ package org.onlab.onos.store.device.impl;
3 import org.onlab.onos.net.DeviceId; 3 import org.onlab.onos.net.DeviceId;
4 import org.onlab.onos.store.Timestamp; 4 import org.onlab.onos.store.Timestamp;
5 5
6 +import com.google.common.base.MoreObjects;
7 +
6 /** 8 /**
7 * Information published by GossipDeviceStore to notify peers of a device 9 * Information published by GossipDeviceStore to notify peers of a device
8 * being administratively removed. 10 * being administratively removed.
...@@ -30,6 +32,14 @@ public class InternalDeviceRemovedEvent { ...@@ -30,6 +32,14 @@ public class InternalDeviceRemovedEvent {
30 return timestamp; 32 return timestamp;
31 } 33 }
32 34
35 + @Override
36 + public String toString() {
37 + return MoreObjects.toStringHelper(getClass())
38 + .add("deviceId", deviceId)
39 + .add("timestamp", timestamp)
40 + .toString();
41 + }
42 +
33 // for serializer 43 // for serializer
34 @SuppressWarnings("unused") 44 @SuppressWarnings("unused")
35 private InternalDeviceRemovedEvent() { 45 private InternalDeviceRemovedEvent() {
......
...@@ -7,6 +7,8 @@ import org.onlab.onos.net.device.PortDescription; ...@@ -7,6 +7,8 @@ import org.onlab.onos.net.device.PortDescription;
7 import org.onlab.onos.net.provider.ProviderId; 7 import org.onlab.onos.net.provider.ProviderId;
8 import org.onlab.onos.store.common.impl.Timestamped; 8 import org.onlab.onos.store.common.impl.Timestamped;
9 9
10 +import com.google.common.base.MoreObjects;
11 +
10 /** 12 /**
11 * Information published by GossipDeviceStore to notify peers of a port 13 * Information published by GossipDeviceStore to notify peers of a port
12 * change event. 14 * change event.
...@@ -38,6 +40,15 @@ public class InternalPortEvent { ...@@ -38,6 +40,15 @@ public class InternalPortEvent {
38 return portDescriptions; 40 return portDescriptions;
39 } 41 }
40 42
43 + @Override
44 + public String toString() {
45 + return MoreObjects.toStringHelper(getClass())
46 + .add("providerId", providerId)
47 + .add("deviceId", deviceId)
48 + .add("portDescriptions", portDescriptions)
49 + .toString();
50 + }
51 +
41 // for serializer 52 // for serializer
42 protected InternalPortEvent() { 53 protected InternalPortEvent() {
43 this.providerId = null; 54 this.providerId = null;
......
...@@ -5,6 +5,8 @@ import org.onlab.onos.net.device.PortDescription; ...@@ -5,6 +5,8 @@ import org.onlab.onos.net.device.PortDescription;
5 import org.onlab.onos.net.provider.ProviderId; 5 import org.onlab.onos.net.provider.ProviderId;
6 import org.onlab.onos.store.common.impl.Timestamped; 6 import org.onlab.onos.store.common.impl.Timestamped;
7 7
8 +import com.google.common.base.MoreObjects;
9 +
8 /** 10 /**
9 * Information published by GossipDeviceStore to notify peers of a port 11 * Information published by GossipDeviceStore to notify peers of a port
10 * status change event. 12 * status change event.
...@@ -36,6 +38,15 @@ public class InternalPortStatusEvent { ...@@ -36,6 +38,15 @@ public class InternalPortStatusEvent {
36 return portDescription; 38 return portDescription;
37 } 39 }
38 40
41 + @Override
42 + public String toString() {
43 + return MoreObjects.toStringHelper(getClass())
44 + .add("providerId", providerId)
45 + .add("deviceId", deviceId)
46 + .add("portDescription", portDescription)
47 + .toString();
48 + }
49 +
39 // for serializer 50 // for serializer
40 protected InternalPortStatusEvent() { 51 protected InternalPortStatusEvent() {
41 this.providerId = null; 52 this.providerId = null;
......
...@@ -35,6 +35,7 @@ public class InternalPortStatusEventSerializer extends Serializer<InternalPortSt ...@@ -35,6 +35,7 @@ public class InternalPortStatusEventSerializer extends Serializer<InternalPortSt
35 Class<InternalPortStatusEvent> type) { 35 Class<InternalPortStatusEvent> type) {
36 ProviderId providerId = (ProviderId) kryo.readClassAndObject(input); 36 ProviderId providerId = (ProviderId) kryo.readClassAndObject(input);
37 DeviceId deviceId = (DeviceId) kryo.readClassAndObject(input); 37 DeviceId deviceId = (DeviceId) kryo.readClassAndObject(input);
38 + @SuppressWarnings("unchecked")
38 Timestamped<PortDescription> portDescription = (Timestamped<PortDescription>) kryo.readClassAndObject(input); 39 Timestamped<PortDescription> portDescription = (Timestamped<PortDescription>) kryo.readClassAndObject(input);
39 40
40 return new InternalPortStatusEvent(providerId, deviceId, portDescription); 41 return new InternalPortStatusEvent(providerId, deviceId, portDescription);
......
1 -package org.onlab.onos.store.device.impl;
2 -
3 -import java.util.Objects;
4 -
5 -import org.onlab.onos.store.Timestamp;
6 -
7 -/**
8 - * Wrapper class for a entity that is versioned
9 - * and can either be up or down.
10 - *
11 - * @param <T> type of the value.
12 - */
13 -public class VersionedValue<T> {
14 - private final T entity;
15 - private final Timestamp timestamp;
16 - private final boolean isUp;
17 -
18 - public VersionedValue(T entity, boolean isUp, Timestamp timestamp) {
19 - this.entity = entity;
20 - this.isUp = isUp;
21 - this.timestamp = timestamp;
22 - }
23 -
24 - /**
25 - * Returns the value.
26 - * @return value.
27 - */
28 - public T entity() {
29 - return entity;
30 - }
31 -
32 - /**
33 - * Tells whether the entity is up or down.
34 - * @return true if up, false otherwise.
35 - */
36 - public boolean isUp() {
37 - return isUp;
38 - }
39 -
40 - /**
41 - * Returns the timestamp (version) associated with this entity.
42 - * @return timestamp.
43 - */
44 - public Timestamp timestamp() {
45 - return timestamp;
46 - }
47 -
48 -
49 - @Override
50 - public int hashCode() {
51 - return Objects.hash(entity, timestamp, isUp);
52 - }
53 -
54 - @Override
55 - public boolean equals(Object obj) {
56 - if (this == obj) {
57 - return true;
58 - }
59 - if (obj == null) {
60 - return false;
61 - }
62 - if (getClass() != obj.getClass()) {
63 - return false;
64 - }
65 - @SuppressWarnings("unchecked")
66 - VersionedValue<T> that = (VersionedValue<T>) obj;
67 - return Objects.equals(this.entity, that.entity) &&
68 - Objects.equals(this.timestamp, that.timestamp) &&
69 - Objects.equals(this.isUp, that.isUp);
70 - }
71 -
72 - // Default constructor for serializer
73 - protected VersionedValue() {
74 - this.entity = null;
75 - this.isUp = false;
76 - this.timestamp = null;
77 - }
78 -}
1 +package org.onlab.onos.store.device.impl.peermsg;
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.DeviceId;
9 +import org.onlab.onos.store.Timestamp;
10 +
11 +
12 +/**
13 + * Device Advertisement message.
14 + */
15 +public class DeviceAntiEntropyAdvertisement {
16 +
17 + private final NodeId sender;
18 + private final Map<DeviceFragmentId, Timestamp> deviceFingerPrints;
19 + private final Map<PortFragmentId, Timestamp> portFingerPrints;
20 + private final Map<DeviceId, Timestamp> offline;
21 +
22 +
23 + public DeviceAntiEntropyAdvertisement(NodeId sender,
24 + Map<DeviceFragmentId, Timestamp> devices,
25 + Map<PortFragmentId, Timestamp> ports,
26 + Map<DeviceId, Timestamp> offline) {
27 + this.sender = checkNotNull(sender);
28 + this.deviceFingerPrints = checkNotNull(devices);
29 + this.portFingerPrints = checkNotNull(ports);
30 + this.offline = checkNotNull(offline);
31 + }
32 +
33 + public NodeId sender() {
34 + return sender;
35 + }
36 +
37 + public Map<DeviceFragmentId, Timestamp> deviceFingerPrints() {
38 + return deviceFingerPrints;
39 + }
40 +
41 + public Map<PortFragmentId, Timestamp> ports() {
42 + return portFingerPrints;
43 + }
44 +
45 + public Map<DeviceId, Timestamp> offline() {
46 + return offline;
47 + }
48 +
49 + // For serializer
50 + @SuppressWarnings("unused")
51 + private DeviceAntiEntropyAdvertisement() {
52 + this.sender = null;
53 + this.deviceFingerPrints = null;
54 + this.portFingerPrints = null;
55 + this.offline = null;
56 + }
57 +}
1 +package org.onlab.onos.store.device.impl.peermsg;
2 +
3 +import static com.google.common.base.Preconditions.checkNotNull;
4 +
5 +import java.util.Collection;
6 +
7 +import org.onlab.onos.cluster.NodeId;
8 +
9 +/**
10 + * Message to request for other peers information.
11 + */
12 +public class DeviceAntiEntropyRequest {
13 +
14 + private final NodeId sender;
15 + private final Collection<DeviceFragmentId> devices;
16 + private final Collection<PortFragmentId> ports;
17 +
18 + public DeviceAntiEntropyRequest(NodeId sender,
19 + Collection<DeviceFragmentId> devices,
20 + Collection<PortFragmentId> ports) {
21 +
22 + this.sender = checkNotNull(sender);
23 + this.devices = checkNotNull(devices);
24 + this.ports = checkNotNull(ports);
25 + }
26 +
27 + public NodeId sender() {
28 + return sender;
29 + }
30 +
31 + public Collection<DeviceFragmentId> devices() {
32 + return devices;
33 + }
34 +
35 + public Collection<PortFragmentId> ports() {
36 + return ports;
37 + }
38 +
39 + // For serializer
40 + @SuppressWarnings("unused")
41 + private DeviceAntiEntropyRequest() {
42 + this.sender = null;
43 + this.devices = null;
44 + this.ports = null;
45 + }
46 +}
1 +package org.onlab.onos.store.device.impl.peermsg;
2 +
3 +import java.util.Objects;
4 +
5 +import org.onlab.onos.net.DeviceId;
6 +import org.onlab.onos.net.provider.ProviderId;
7 +
8 +import com.google.common.base.MoreObjects;
9 +
10 +/**
11 + * Identifier for DeviceDesctiption from a Provider.
12 + */
13 +public final class DeviceFragmentId {
14 + public final ProviderId providerId;
15 + public final DeviceId deviceId;
16 +
17 + public DeviceFragmentId(DeviceId deviceId, ProviderId providerId) {
18 + this.providerId = providerId;
19 + this.deviceId = deviceId;
20 + }
21 +
22 + @Override
23 + public int hashCode() {
24 + return Objects.hash(providerId, deviceId);
25 + }
26 +
27 + @Override
28 + public boolean equals(Object obj) {
29 + if (this == obj) {
30 + return true;
31 + }
32 + if (!(obj instanceof DeviceFragmentId)) {
33 + return false;
34 + }
35 + DeviceFragmentId that = (DeviceFragmentId) obj;
36 + return Objects.equals(this.deviceId, that.deviceId) &&
37 + Objects.equals(this.providerId, that.providerId);
38 + }
39 +
40 + @Override
41 + public String toString() {
42 + return MoreObjects.toStringHelper(getClass())
43 + .add("providerId", providerId)
44 + .add("deviceId", deviceId)
45 + .toString();
46 + }
47 +
48 + // for serializer
49 + @SuppressWarnings("unused")
50 + private DeviceFragmentId() {
51 + this.providerId = null;
52 + this.deviceId = null;
53 + }
54 +}
...\ No newline at end of file ...\ No newline at end of file
1 +package org.onlab.onos.store.device.impl.peermsg;
2 +
3 +import java.util.Objects;
4 +
5 +import org.onlab.onos.net.DeviceId;
6 +import org.onlab.onos.net.PortNumber;
7 +import org.onlab.onos.net.provider.ProviderId;
8 +
9 +import com.google.common.base.MoreObjects;
10 +
11 +/**
12 + * Identifier for PortDescription from a Provider.
13 + */
14 +public final class PortFragmentId {
15 + public final ProviderId providerId;
16 + public final DeviceId deviceId;
17 + public final PortNumber portNumber;
18 +
19 + public PortFragmentId(DeviceId deviceId, ProviderId providerId,
20 + PortNumber portNumber) {
21 + this.providerId = providerId;
22 + this.deviceId = deviceId;
23 + this.portNumber = portNumber;
24 + }
25 +
26 + @Override
27 + public int hashCode() {
28 + return Objects.hash(providerId, deviceId, portNumber);
29 + };
30 +
31 + @Override
32 + public boolean equals(Object obj) {
33 + if (this == obj) {
34 + return true;
35 + }
36 + if (!(obj instanceof PortFragmentId)) {
37 + return false;
38 + }
39 + PortFragmentId that = (PortFragmentId) obj;
40 + return Objects.equals(this.deviceId, that.deviceId) &&
41 + Objects.equals(this.portNumber, that.portNumber) &&
42 + Objects.equals(this.providerId, that.providerId);
43 + }
44 +
45 + @Override
46 + public String toString() {
47 + return MoreObjects.toStringHelper(getClass())
48 + .add("providerId", providerId)
49 + .add("deviceId", deviceId)
50 + .add("portNumber", portNumber)
51 + .toString();
52 + }
53 +
54 + // for serializer
55 + @SuppressWarnings("unused")
56 + private PortFragmentId() {
57 + this.providerId = null;
58 + this.deviceId = null;
59 + this.portNumber = null;
60 + }
61 +}
...\ No newline at end of file ...\ No newline at end of file
1 +/**
2 + * Structure and utilities used for inter-Node messaging.
3 + */
4 +package org.onlab.onos.store.device.impl.peermsg;
...@@ -43,8 +43,8 @@ public class DistributedFlowRuleStore ...@@ -43,8 +43,8 @@ public class DistributedFlowRuleStore
43 private final Multimap<DeviceId, FlowEntry> flowEntries = 43 private final Multimap<DeviceId, FlowEntry> flowEntries =
44 ArrayListMultimap.<DeviceId, FlowEntry>create(); 44 ArrayListMultimap.<DeviceId, FlowEntry>create();
45 45
46 - private final Multimap<ApplicationId, FlowRule> flowEntriesById = 46 + private final Multimap<Short, FlowRule> flowEntriesById =
47 - ArrayListMultimap.<ApplicationId, FlowRule>create(); 47 + ArrayListMultimap.<Short, FlowRule>create();
48 48
49 @Activate 49 @Activate
50 public void activate() { 50 public void activate() {
...@@ -83,7 +83,7 @@ public class DistributedFlowRuleStore ...@@ -83,7 +83,7 @@ public class DistributedFlowRuleStore
83 83
84 @Override 84 @Override
85 public synchronized Iterable<FlowRule> getFlowRulesByAppId(ApplicationId appId) { 85 public synchronized Iterable<FlowRule> getFlowRulesByAppId(ApplicationId appId) {
86 - Collection<FlowRule> rules = flowEntriesById.get(appId); 86 + Collection<FlowRule> rules = flowEntriesById.get(appId.id());
87 if (rules == null) { 87 if (rules == null) {
88 return Collections.emptyList(); 88 return Collections.emptyList();
89 } 89 }
......
1 package org.onlab.onos.store.host.impl; 1 package org.onlab.onos.store.host.impl;
2 2
3 -import static org.onlab.onos.net.host.HostEvent.Type.HOST_ADDED; 3 +import com.google.common.collect.HashMultimap;
4 -import static org.onlab.onos.net.host.HostEvent.Type.HOST_MOVED; 4 +import com.google.common.collect.ImmutableSet;
5 -import static org.onlab.onos.net.host.HostEvent.Type.HOST_REMOVED; 5 +import com.google.common.collect.Multimap;
6 -import static org.onlab.onos.net.host.HostEvent.Type.HOST_UPDATED; 6 +import com.google.common.collect.Sets;
7 -import static org.slf4j.LoggerFactory.getLogger;
8 -
9 -import java.util.Collections;
10 -import java.util.HashSet;
11 -import java.util.Map;
12 -import java.util.Set;
13 -import java.util.concurrent.ConcurrentHashMap;
14 -
15 import org.apache.felix.scr.annotations.Activate; 7 import org.apache.felix.scr.annotations.Activate;
16 import org.apache.felix.scr.annotations.Component; 8 import org.apache.felix.scr.annotations.Component;
17 import org.apache.felix.scr.annotations.Deactivate; 9 import org.apache.felix.scr.annotations.Deactivate;
18 import org.apache.felix.scr.annotations.Service; 10 import org.apache.felix.scr.annotations.Service;
11 +import org.onlab.onos.net.Annotations;
19 import org.onlab.onos.net.ConnectPoint; 12 import org.onlab.onos.net.ConnectPoint;
20 import org.onlab.onos.net.DefaultHost; 13 import org.onlab.onos.net.DefaultHost;
21 import org.onlab.onos.net.DeviceId; 14 import org.onlab.onos.net.DeviceId;
22 import org.onlab.onos.net.Host; 15 import org.onlab.onos.net.Host;
23 import org.onlab.onos.net.HostId; 16 import org.onlab.onos.net.HostId;
17 +import org.onlab.onos.net.HostLocation;
24 import org.onlab.onos.net.host.HostDescription; 18 import org.onlab.onos.net.host.HostDescription;
25 import org.onlab.onos.net.host.HostEvent; 19 import org.onlab.onos.net.host.HostEvent;
26 import org.onlab.onos.net.host.HostStore; 20 import org.onlab.onos.net.host.HostStore;
...@@ -33,10 +27,13 @@ import org.onlab.packet.MacAddress; ...@@ -33,10 +27,13 @@ import org.onlab.packet.MacAddress;
33 import org.onlab.packet.VlanId; 27 import org.onlab.packet.VlanId;
34 import org.slf4j.Logger; 28 import org.slf4j.Logger;
35 29
36 -import com.google.common.collect.HashMultimap; 30 +import java.util.HashSet;
37 -import com.google.common.collect.ImmutableSet; 31 +import java.util.Map;
38 -import com.google.common.collect.Multimap; 32 +import java.util.Set;
39 -import com.google.common.collect.Sets; 33 +import java.util.concurrent.ConcurrentHashMap;
34 +
35 +import static org.onlab.onos.net.host.HostEvent.Type.*;
36 +import static org.slf4j.LoggerFactory.getLogger;
40 37
41 /** 38 /**
42 * Manages inventory of end-station hosts using trivial in-memory 39 * Manages inventory of end-station hosts using trivial in-memory
...@@ -46,13 +43,13 @@ import com.google.common.collect.Sets; ...@@ -46,13 +43,13 @@ import com.google.common.collect.Sets;
46 @Component(immediate = true) 43 @Component(immediate = true)
47 @Service 44 @Service
48 public class DistributedHostStore 45 public class DistributedHostStore
49 -extends AbstractStore<HostEvent, HostStoreDelegate> 46 + extends AbstractStore<HostEvent, HostStoreDelegate>
50 -implements HostStore { 47 + implements HostStore {
51 48
52 private final Logger log = getLogger(getClass()); 49 private final Logger log = getLogger(getClass());
53 50
54 // Host inventory 51 // Host inventory
55 - private final Map<HostId, Host> hosts = new ConcurrentHashMap<>(); 52 + private final Map<HostId, StoredHost> hosts = new ConcurrentHashMap<>(2000000, 0.75f, 16);
56 53
57 // Hosts tracked by their location 54 // Hosts tracked by their location
58 private final Multimap<ConnectPoint, Host> locations = HashMultimap.create(); 55 private final Multimap<ConnectPoint, Host> locations = HashMultimap.create();
...@@ -72,8 +69,8 @@ implements HostStore { ...@@ -72,8 +69,8 @@ implements HostStore {
72 69
73 @Override 70 @Override
74 public HostEvent createOrUpdateHost(ProviderId providerId, HostId hostId, 71 public HostEvent createOrUpdateHost(ProviderId providerId, HostId hostId,
75 - HostDescription hostDescription) { 72 + HostDescription hostDescription) {
76 - Host host = hosts.get(hostId); 73 + StoredHost host = hosts.get(hostId);
77 if (host == null) { 74 if (host == null) {
78 return createHost(providerId, hostId, hostDescription); 75 return createHost(providerId, hostId, hostDescription);
79 } 76 }
...@@ -82,12 +79,12 @@ implements HostStore { ...@@ -82,12 +79,12 @@ implements HostStore {
82 79
83 // creates a new host and sends HOST_ADDED 80 // creates a new host and sends HOST_ADDED
84 private HostEvent createHost(ProviderId providerId, HostId hostId, 81 private HostEvent createHost(ProviderId providerId, HostId hostId,
85 - HostDescription descr) { 82 + HostDescription descr) {
86 - DefaultHost newhost = new DefaultHost(providerId, hostId, 83 + StoredHost newhost = new StoredHost(providerId, hostId,
87 - descr.hwAddress(), 84 + descr.hwAddress(),
88 - descr.vlan(), 85 + descr.vlan(),
89 - descr.location(), 86 + descr.location(),
90 - descr.ipAddresses()); 87 + ImmutableSet.of(descr.ipAddress()));
91 synchronized (this) { 88 synchronized (this) {
92 hosts.put(hostId, newhost); 89 hosts.put(hostId, newhost);
93 locations.put(descr.location(), newhost); 90 locations.put(descr.location(), newhost);
...@@ -96,28 +93,24 @@ implements HostStore { ...@@ -96,28 +93,24 @@ implements HostStore {
96 } 93 }
97 94
98 // checks for type of update to host, sends appropriate event 95 // checks for type of update to host, sends appropriate event
99 - private HostEvent updateHost(ProviderId providerId, Host host, 96 + private HostEvent updateHost(ProviderId providerId, StoredHost host,
100 - HostDescription descr) { 97 + HostDescription descr) {
101 - DefaultHost updated;
102 HostEvent event; 98 HostEvent event;
103 if (!host.location().equals(descr.location())) { 99 if (!host.location().equals(descr.location())) {
104 - updated = new DefaultHost(providerId, host.id(), 100 + host.setLocation(descr.location());
105 - host.mac(), 101 + return new HostEvent(HOST_MOVED, host);
106 - host.vlan(), 102 + }
107 - descr.location(), 103 +
108 - host.ipAddresses()); 104 + if (host.ipAddresses().contains(descr.ipAddress())) {
109 - event = new HostEvent(HOST_MOVED, updated);
110 -
111 - } else if (!(host.ipAddresses().equals(descr.ipAddresses()))) {
112 - updated = new DefaultHost(providerId, host.id(),
113 - host.mac(),
114 - host.vlan(),
115 - descr.location(),
116 - descr.ipAddresses());
117 - event = new HostEvent(HOST_UPDATED, updated);
118 - } else {
119 return null; 105 return null;
120 } 106 }
107 +
108 + Set<IpPrefix> addresses = new HashSet<>(host.ipAddresses());
109 + addresses.add(descr.ipAddress());
110 + StoredHost updated = new StoredHost(providerId, host.id(),
111 + host.mac(), host.vlan(),
112 + descr.location(), addresses);
113 + event = new HostEvent(HOST_UPDATED, updated);
121 synchronized (this) { 114 synchronized (this) {
122 hosts.put(host.id(), updated); 115 hosts.put(host.id(), updated);
123 locations.remove(host.location(), host); 116 locations.remove(host.location(), host);
...@@ -145,7 +138,7 @@ implements HostStore { ...@@ -145,7 +138,7 @@ implements HostStore {
145 138
146 @Override 139 @Override
147 public Iterable<Host> getHosts() { 140 public Iterable<Host> getHosts() {
148 - return Collections.unmodifiableSet(new HashSet<>(hosts.values())); 141 + return ImmutableSet.<Host>copyOf(hosts.values());
149 } 142 }
150 143
151 @Override 144 @Override
...@@ -275,4 +268,35 @@ implements HostStore { ...@@ -275,4 +268,35 @@ implements HostStore {
275 return addresses; 268 return addresses;
276 } 269 }
277 270
271 + // Auxiliary extension to allow location to mutate.
272 + private class StoredHost extends DefaultHost {
273 + private HostLocation location;
274 +
275 + /**
276 + * Creates an end-station host using the supplied information.
277 + *
278 + * @param providerId provider identity
279 + * @param id host identifier
280 + * @param mac host MAC address
281 + * @param vlan host VLAN identifier
282 + * @param location host location
283 + * @param ips host IP addresses
284 + * @param annotations optional key/value annotations
285 + */
286 + public StoredHost(ProviderId providerId, HostId id,
287 + MacAddress mac, VlanId vlan, HostLocation location,
288 + Set<IpPrefix> ips, Annotations... annotations) {
289 + super(providerId, id, mac, vlan, location, ips, annotations);
290 + this.location = location;
291 + }
292 +
293 + void setLocation(HostLocation location) {
294 + this.location = location;
295 + }
296 +
297 + @Override
298 + public HostLocation location() {
299 + return location;
300 + }
301 + }
278 } 302 }
......
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.onlab.onos.store.device.impl.VersionedValue;
35 -import org.slf4j.Logger;
36 -
37 -import com.google.common.collect.HashMultimap;
38 -import com.google.common.collect.ImmutableSet;
39 -import com.google.common.collect.Multimap;
40 -import com.google.common.collect.ImmutableSet.Builder;
41 -
42 -import static com.google.common.base.Preconditions.checkArgument;
43 -import static com.google.common.base.Preconditions.checkState;
44 -
45 -//TODO: Add support for multiple provider and annotations
46 -/**
47 - * Manages inventory of infrastructure links using a protocol that takes into consideration
48 - * the order in which events occur.
49 - */
50 -// FIXME: This does not yet implement the full protocol.
51 -// The full protocol requires the sender of LLDP message to include the
52 -// version information of src device/port and the receiver to
53 -// take that into account when figuring out if a more recent src
54 -// device/port down event renders the link discovery obsolete.
55 -@Component(immediate = true)
56 -@Service
57 -public class OnosDistributedLinkStore
58 - extends AbstractStore<LinkEvent, LinkStoreDelegate>
59 - implements LinkStore {
60 -
61 - private final Logger log = getLogger(getClass());
62 -
63 - // Link inventory
64 - private ConcurrentMap<LinkKey, VersionedValue<Link>> links;
65 -
66 - public static final String LINK_NOT_FOUND = "Link between %s and %s not found";
67 -
68 - // TODO synchronize?
69 - // Egress and ingress link sets
70 - private final Multimap<DeviceId, VersionedValue<Link>> srcLinks = HashMultimap.create();
71 - private final Multimap<DeviceId, VersionedValue<Link>> dstLinks = HashMultimap.create();
72 -
73 - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
74 - protected ClockService clockService;
75 -
76 - @Activate
77 - public void activate() {
78 -
79 - links = new ConcurrentHashMap<>();
80 -
81 - log.info("Started");
82 - }
83 -
84 - @Deactivate
85 - public void deactivate() {
86 - log.info("Stopped");
87 - }
88 -
89 - @Override
90 - public int getLinkCount() {
91 - return links.size();
92 - }
93 -
94 - @Override
95 - public Iterable<Link> getLinks() {
96 - Builder<Link> builder = ImmutableSet.builder();
97 - synchronized (this) {
98 - for (VersionedValue<Link> link : links.values()) {
99 - builder.add(link.entity());
100 - }
101 - return builder.build();
102 - }
103 - }
104 -
105 - @Override
106 - public Set<Link> getDeviceEgressLinks(DeviceId deviceId) {
107 - Set<VersionedValue<Link>> egressLinks = ImmutableSet.copyOf(srcLinks.get(deviceId));
108 - Set<Link> rawEgressLinks = new HashSet<>();
109 - for (VersionedValue<Link> link : egressLinks) {
110 - rawEgressLinks.add(link.entity());
111 - }
112 - return rawEgressLinks;
113 - }
114 -
115 - @Override
116 - public Set<Link> getDeviceIngressLinks(DeviceId deviceId) {
117 - Set<VersionedValue<Link>> ingressLinks = ImmutableSet.copyOf(dstLinks.get(deviceId));
118 - Set<Link> rawIngressLinks = new HashSet<>();
119 - for (VersionedValue<Link> link : ingressLinks) {
120 - rawIngressLinks.add(link.entity());
121 - }
122 - return rawIngressLinks;
123 - }
124 -
125 - @Override
126 - public Link getLink(ConnectPoint src, ConnectPoint dst) {
127 - VersionedValue<Link> link = links.get(new LinkKey(src, dst));
128 - checkArgument(link != null, "LINK_NOT_FOUND", src, dst);
129 - return link.entity();
130 - }
131 -
132 - @Override
133 - public Set<Link> getEgressLinks(ConnectPoint src) {
134 - Set<Link> egressLinks = new HashSet<>();
135 - for (VersionedValue<Link> link : srcLinks.get(src.deviceId())) {
136 - if (link.entity().src().equals(src)) {
137 - egressLinks.add(link.entity());
138 - }
139 - }
140 - return egressLinks;
141 - }
142 -
143 - @Override
144 - public Set<Link> getIngressLinks(ConnectPoint dst) {
145 - Set<Link> ingressLinks = new HashSet<>();
146 - for (VersionedValue<Link> link : dstLinks.get(dst.deviceId())) {
147 - if (link.entity().dst().equals(dst)) {
148 - ingressLinks.add(link.entity());
149 - }
150 - }
151 - return ingressLinks;
152 - }
153 -
154 - @Override
155 - public LinkEvent createOrUpdateLink(ProviderId providerId,
156 - LinkDescription linkDescription) {
157 -
158 - final DeviceId destinationDeviceId = linkDescription.dst().deviceId();
159 - final Timestamp newTimestamp = clockService.getTimestamp(destinationDeviceId);
160 -
161 - LinkKey key = new LinkKey(linkDescription.src(), linkDescription.dst());
162 - VersionedValue<Link> link = links.get(key);
163 - if (link == null) {
164 - return createLink(providerId, key, linkDescription, newTimestamp);
165 - }
166 -
167 - checkState(newTimestamp.compareTo(link.timestamp()) > 0,
168 - "Existing Link has a timestamp in the future!");
169 -
170 - return updateLink(providerId, link, key, linkDescription, newTimestamp);
171 - }
172 -
173 - // Creates and stores the link and returns the appropriate event.
174 - private LinkEvent createLink(ProviderId providerId, LinkKey key,
175 - LinkDescription linkDescription, Timestamp timestamp) {
176 - VersionedValue<Link> link = new VersionedValue<Link>(new DefaultLink(providerId, key.src(), key.dst(),
177 - linkDescription.type()), true, timestamp);
178 - synchronized (this) {
179 - links.put(key, link);
180 - addNewLink(link, timestamp);
181 - }
182 - // FIXME: notify peers.
183 - return new LinkEvent(LINK_ADDED, link.entity());
184 - }
185 -
186 - // update Egress and ingress link sets
187 - private void addNewLink(VersionedValue<Link> link, Timestamp timestamp) {
188 - Link rawLink = link.entity();
189 - synchronized (this) {
190 - srcLinks.put(rawLink.src().deviceId(), link);
191 - dstLinks.put(rawLink.dst().deviceId(), link);
192 - }
193 - }
194 -
195 - // Updates, if necessary the specified link and returns the appropriate event.
196 - private LinkEvent updateLink(ProviderId providerId, VersionedValue<Link> existingLink,
197 - LinkKey key, LinkDescription linkDescription, Timestamp timestamp) {
198 - // FIXME confirm Link update condition is OK
199 - if (existingLink.entity().type() == INDIRECT && linkDescription.type() == DIRECT) {
200 - synchronized (this) {
201 -
202 - VersionedValue<Link> updatedLink = new VersionedValue<Link>(
203 - new DefaultLink(providerId, existingLink.entity().src(), existingLink.entity().dst(),
204 - linkDescription.type()), true, timestamp);
205 - links.replace(key, existingLink, updatedLink);
206 -
207 - replaceLink(existingLink, updatedLink);
208 - // FIXME: notify peers.
209 - return new LinkEvent(LINK_UPDATED, updatedLink.entity());
210 - }
211 - }
212 - return null;
213 - }
214 -
215 - // update Egress and ingress link sets
216 - private void replaceLink(VersionedValue<Link> current, VersionedValue<Link> updated) {
217 - synchronized (this) {
218 - srcLinks.remove(current.entity().src().deviceId(), current);
219 - dstLinks.remove(current.entity().dst().deviceId(), current);
220 -
221 - srcLinks.put(current.entity().src().deviceId(), updated);
222 - dstLinks.put(current.entity().dst().deviceId(), updated);
223 - }
224 - }
225 -
226 - @Override
227 - public LinkEvent removeLink(ConnectPoint src, ConnectPoint dst) {
228 - synchronized (this) {
229 - LinkKey key = new LinkKey(src, dst);
230 - VersionedValue<Link> link = links.remove(key);
231 - if (link != null) {
232 - removeLink(link);
233 - // notify peers
234 - return new LinkEvent(LINK_REMOVED, link.entity());
235 - }
236 - return null;
237 - }
238 - }
239 -
240 - // update Egress and ingress link sets
241 - private void removeLink(VersionedValue<Link> link) {
242 - synchronized (this) {
243 - srcLinks.remove(link.entity().src().deviceId(), link);
244 - dstLinks.remove(link.entity().dst().deviceId(), link);
245 - }
246 - }
247 -}
...@@ -35,4 +35,4 @@ public final class ClusterMessageSerializer extends Serializer<ClusterMessage> { ...@@ -35,4 +35,4 @@ public final class ClusterMessageSerializer extends Serializer<ClusterMessage> {
35 byte[] payload = input.readBytes(payloadSize); 35 byte[] payload = input.readBytes(payloadSize);
36 return new ClusterMessage(sender, subject, payload); 36 return new ClusterMessage(sender, subject, payload);
37 } 37 }
38 -}
...\ No newline at end of file ...\ No newline at end of file
38 +}
......
1 +package org.onlab.onos.store.serializers;
2 +
3 +import org.onlab.onos.store.common.impl.MastershipBasedTimestamp;
4 +import org.onlab.onos.store.common.impl.Timestamped;
5 +import org.onlab.util.KryoPool;
6 +
7 +public final class DistributedStoreSerializers {
8 +
9 + /**
10 + * KryoPool which can serialize ON.lab misc classes.
11 + */
12 + public static final KryoPool COMMON = KryoPool.newBuilder()
13 + .register(KryoPoolUtil.API)
14 + .register(Timestamped.class)
15 + .register(MastershipBasedTimestamp.class, new MastershipBasedTimestampSerializer())
16 + .build();
17 +
18 + // avoid instantiation
19 + private DistributedStoreSerializers() {}
20 +}
1 package org.onlab.onos.store.device.impl; 1 package org.onlab.onos.store.device.impl;
2 2
3 +import static org.easymock.EasyMock.*;
3 import static org.junit.Assert.*; 4 import static org.junit.Assert.*;
4 import static org.onlab.onos.net.Device.Type.SWITCH; 5 import static org.onlab.onos.net.Device.Type.SWITCH;
5 import static org.onlab.onos.net.DeviceId.deviceId; 6 import static org.onlab.onos.net.DeviceId.deviceId;
6 import static org.onlab.onos.net.device.DeviceEvent.Type.*; 7 import static org.onlab.onos.net.device.DeviceEvent.Type.*;
7 - 8 +import static org.onlab.onos.cluster.ControllerNode.State.*;
9 +import static org.onlab.onos.net.DefaultAnnotations.union;
10 +import static java.util.Arrays.asList;
8 import java.io.IOException; 11 import java.io.IOException;
9 import java.util.Arrays; 12 import java.util.Arrays;
13 +import java.util.Collections;
10 import java.util.HashMap; 14 import java.util.HashMap;
11 import java.util.List; 15 import java.util.List;
12 import java.util.Map; 16 import java.util.Map;
...@@ -14,6 +18,7 @@ import java.util.Set; ...@@ -14,6 +18,7 @@ import java.util.Set;
14 import java.util.concurrent.CountDownLatch; 18 import java.util.concurrent.CountDownLatch;
15 import java.util.concurrent.TimeUnit; 19 import java.util.concurrent.TimeUnit;
16 20
21 +import org.easymock.Capture;
17 import org.junit.After; 22 import org.junit.After;
18 import org.junit.AfterClass; 23 import org.junit.AfterClass;
19 import org.junit.Before; 24 import org.junit.Before;
...@@ -90,14 +95,25 @@ public class GossipDeviceStoreTest { ...@@ -90,14 +95,25 @@ public class GossipDeviceStoreTest {
90 .set("B4", "b4") 95 .set("B4", "b4")
91 .build(); 96 .build();
92 97
93 - private static final NodeId MYSELF = new NodeId("myself"); 98 + // local node
99 + private static final NodeId NID1 = new NodeId("local");
100 + private static final ControllerNode ONOS1 =
101 + new DefaultControllerNode(NID1, IpPrefix.valueOf("127.0.0.1"));
102 +
103 + // remote node
104 + private static final NodeId NID2 = new NodeId("remote");
105 + private static final ControllerNode ONOS2 =
106 + new DefaultControllerNode(NID2, IpPrefix.valueOf("127.0.0.2"));
107 + private static final List<SparseAnnotations> NO_ANNOTATION = Collections.<SparseAnnotations>emptyList();
94 108
109 +
110 + private TestGossipDeviceStore testGossipDeviceStore;
95 private GossipDeviceStore gossipDeviceStore; 111 private GossipDeviceStore gossipDeviceStore;
96 private DeviceStore deviceStore; 112 private DeviceStore deviceStore;
97 113
98 private DeviceClockManager deviceClockManager; 114 private DeviceClockManager deviceClockManager;
99 private ClockService clockService; 115 private ClockService clockService;
100 - 116 + private ClusterCommunicationService clusterCommunicator;
101 @BeforeClass 117 @BeforeClass
102 public static void setUpBeforeClass() throws Exception { 118 public static void setUpBeforeClass() throws Exception {
103 } 119 }
...@@ -113,15 +129,22 @@ public class GossipDeviceStoreTest { ...@@ -113,15 +129,22 @@ public class GossipDeviceStoreTest {
113 deviceClockManager.activate(); 129 deviceClockManager.activate();
114 clockService = deviceClockManager; 130 clockService = deviceClockManager;
115 131
116 - deviceClockManager.setMastershipTerm(DID1, MastershipTerm.of(MYSELF, 1)); 132 + deviceClockManager.setMastershipTerm(DID1, MastershipTerm.of(NID1, 1));
117 - deviceClockManager.setMastershipTerm(DID2, MastershipTerm.of(MYSELF, 2)); 133 + deviceClockManager.setMastershipTerm(DID2, MastershipTerm.of(NID1, 2));
118 134
119 - ClusterCommunicationService clusterCommunicator = new TestClusterCommunicationService(); 135 + clusterCommunicator = createNiceMock(ClusterCommunicationService.class);
136 + clusterCommunicator.addSubscriber(anyObject(MessageSubject.class),
137 + anyObject(ClusterMessageHandler.class));
138 + expectLastCall().anyTimes();
139 + replay(clusterCommunicator);
120 ClusterService clusterService = new TestClusterService(); 140 ClusterService clusterService = new TestClusterService();
121 141
122 - gossipDeviceStore = new TestGossipDeviceStore(clockService, clusterService, clusterCommunicator); 142 + testGossipDeviceStore = new TestGossipDeviceStore(clockService, clusterService, clusterCommunicator);
143 + gossipDeviceStore = testGossipDeviceStore;
123 gossipDeviceStore.activate(); 144 gossipDeviceStore.activate();
124 deviceStore = gossipDeviceStore; 145 deviceStore = gossipDeviceStore;
146 + verify(clusterCommunicator);
147 + reset(clusterCommunicator);
125 } 148 }
126 149
127 @After 150 @After
...@@ -135,7 +158,16 @@ public class GossipDeviceStoreTest { ...@@ -135,7 +158,16 @@ public class GossipDeviceStoreTest {
135 DeviceDescription description = 158 DeviceDescription description =
136 new DefaultDeviceDescription(deviceId.uri(), SWITCH, MFR, 159 new DefaultDeviceDescription(deviceId.uri(), SWITCH, MFR,
137 HW, swVersion, SN, annotations); 160 HW, swVersion, SN, annotations);
161 + reset(clusterCommunicator);
162 + try {
163 + expect(clusterCommunicator.broadcast(anyObject(ClusterMessage.class)))
164 + .andReturn(true).anyTimes();
165 + } catch (IOException e) {
166 + fail("Should never reach here");
167 + }
168 + replay(clusterCommunicator);
138 deviceStore.createOrUpdateDevice(PID, deviceId, description); 169 deviceStore.createOrUpdateDevice(PID, deviceId, description);
170 + verify(clusterCommunicator);
139 } 171 }
140 172
141 private void putDeviceAncillary(DeviceId deviceId, String swVersion, 173 private void putDeviceAncillary(DeviceId deviceId, String swVersion,
...@@ -163,9 +195,9 @@ public class GossipDeviceStoreTest { ...@@ -163,9 +195,9 @@ public class GossipDeviceStoreTest {
163 * @param annotations 195 * @param annotations
164 */ 196 */
165 private static void assertAnnotationsEquals(Annotations actual, SparseAnnotations... annotations) { 197 private static void assertAnnotationsEquals(Annotations actual, SparseAnnotations... annotations) {
166 - DefaultAnnotations expected = DefaultAnnotations.builder().build(); 198 + SparseAnnotations expected = DefaultAnnotations.builder().build();
167 for (SparseAnnotations a : annotations) { 199 for (SparseAnnotations a : annotations) {
168 - expected = DefaultAnnotations.merge(expected, a); 200 + expected = DefaultAnnotations.union(expected, a);
169 } 201 }
170 assertEquals(expected.keys(), actual.keys()); 202 assertEquals(expected.keys(), actual.keys());
171 for (String key : expected.keys()) { 203 for (String key : expected.keys()) {
...@@ -173,6 +205,36 @@ public class GossipDeviceStoreTest { ...@@ -173,6 +205,36 @@ public class GossipDeviceStoreTest {
173 } 205 }
174 } 206 }
175 207
208 + private static void assertDeviceDescriptionEquals(DeviceDescription expected,
209 + DeviceDescription actual) {
210 + if (expected == actual) {
211 + return;
212 + }
213 + assertEquals(expected.deviceURI(), actual.deviceURI());
214 + assertEquals(expected.hwVersion(), actual.hwVersion());
215 + assertEquals(expected.manufacturer(), actual.manufacturer());
216 + assertEquals(expected.serialNumber(), actual.serialNumber());
217 + assertEquals(expected.swVersion(), actual.swVersion());
218 +
219 + assertAnnotationsEquals(actual.annotations(), expected.annotations());
220 + }
221 +
222 + private static void assertDeviceDescriptionEquals(DeviceDescription expected,
223 + List<SparseAnnotations> expectedAnnotations,
224 + DeviceDescription actual) {
225 + if (expected == actual) {
226 + return;
227 + }
228 + assertEquals(expected.deviceURI(), actual.deviceURI());
229 + assertEquals(expected.hwVersion(), actual.hwVersion());
230 + assertEquals(expected.manufacturer(), actual.manufacturer());
231 + assertEquals(expected.serialNumber(), actual.serialNumber());
232 + assertEquals(expected.swVersion(), actual.swVersion());
233 +
234 + assertAnnotationsEquals(actual.annotations(),
235 + expectedAnnotations.toArray(new SparseAnnotations[0]));
236 + }
237 +
176 @Test 238 @Test
177 public final void testGetDeviceCount() { 239 public final void testGetDeviceCount() {
178 assertEquals("initialy empty", 0, deviceStore.getDeviceCount()); 240 assertEquals("initialy empty", 0, deviceStore.getDeviceCount());
...@@ -215,56 +277,123 @@ public class GossipDeviceStoreTest { ...@@ -215,56 +277,123 @@ public class GossipDeviceStoreTest {
215 assertNull("DID2 shouldn't be there", deviceStore.getDevice(DID2)); 277 assertNull("DID2 shouldn't be there", deviceStore.getDevice(DID2));
216 } 278 }
217 279
280 + private void assertInternalDeviceEvent(NodeId sender,
281 + DeviceId deviceId,
282 + ProviderId providerId,
283 + DeviceDescription expectedDesc,
284 + Capture<ClusterMessage> actualMsg) {
285 + assertTrue(actualMsg.hasCaptured());
286 + assertEquals(sender, actualMsg.getValue().sender());
287 + assertEquals(GossipDeviceStoreMessageSubjects.DEVICE_UPDATE,
288 + actualMsg.getValue().subject());
289 + InternalDeviceEvent addEvent
290 + = testGossipDeviceStore.deserialize(actualMsg.getValue().payload());
291 + assertEquals(deviceId, addEvent.deviceId());
292 + assertEquals(providerId, addEvent.providerId());
293 + assertDeviceDescriptionEquals(expectedDesc, addEvent.deviceDescription().value());
294 + }
295 +
296 + private void assertInternalDeviceEvent(NodeId sender,
297 + DeviceId deviceId,
298 + ProviderId providerId,
299 + DeviceDescription expectedDesc,
300 + List<SparseAnnotations> expectedAnnotations,
301 + Capture<ClusterMessage> actualMsg) {
302 + assertTrue(actualMsg.hasCaptured());
303 + assertEquals(sender, actualMsg.getValue().sender());
304 + assertEquals(GossipDeviceStoreMessageSubjects.DEVICE_UPDATE,
305 + actualMsg.getValue().subject());
306 + InternalDeviceEvent addEvent
307 + = testGossipDeviceStore.deserialize(actualMsg.getValue().payload());
308 + assertEquals(deviceId, addEvent.deviceId());
309 + assertEquals(providerId, addEvent.providerId());
310 + assertDeviceDescriptionEquals(expectedDesc, expectedAnnotations, addEvent.deviceDescription().value());
311 + }
312 +
218 @Test 313 @Test
219 - public final void testCreateOrUpdateDevice() { 314 + public final void testCreateOrUpdateDevice() throws IOException {
220 DeviceDescription description = 315 DeviceDescription description =
221 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, 316 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
222 HW, SW1, SN); 317 HW, SW1, SN);
318 + Capture<ClusterMessage> bcast = new Capture<>();
319 +
320 + resetCommunicatorExpectingSingleBroadcast(bcast);
223 DeviceEvent event = deviceStore.createOrUpdateDevice(PID, DID1, description); 321 DeviceEvent event = deviceStore.createOrUpdateDevice(PID, DID1, description);
224 assertEquals(DEVICE_ADDED, event.type()); 322 assertEquals(DEVICE_ADDED, event.type());
225 assertDevice(DID1, SW1, event.subject()); 323 assertDevice(DID1, SW1, event.subject());
324 + verify(clusterCommunicator);
325 + assertInternalDeviceEvent(NID1, DID1, PID, description, bcast);
326 +
226 327
227 DeviceDescription description2 = 328 DeviceDescription description2 =
228 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, 329 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
229 HW, SW2, SN); 330 HW, SW2, SN);
331 + resetCommunicatorExpectingSingleBroadcast(bcast);
230 DeviceEvent event2 = deviceStore.createOrUpdateDevice(PID, DID1, description2); 332 DeviceEvent event2 = deviceStore.createOrUpdateDevice(PID, DID1, description2);
231 assertEquals(DEVICE_UPDATED, event2.type()); 333 assertEquals(DEVICE_UPDATED, event2.type());
232 assertDevice(DID1, SW2, event2.subject()); 334 assertDevice(DID1, SW2, event2.subject());
233 335
336 + verify(clusterCommunicator);
337 + assertInternalDeviceEvent(NID1, DID1, PID, description2, bcast);
338 + reset(clusterCommunicator);
339 +
234 assertNull("No change expected", deviceStore.createOrUpdateDevice(PID, DID1, description2)); 340 assertNull("No change expected", deviceStore.createOrUpdateDevice(PID, DID1, description2));
235 } 341 }
236 342
237 @Test 343 @Test
238 - public final void testCreateOrUpdateDeviceAncillary() { 344 + public final void testCreateOrUpdateDeviceAncillary() throws IOException {
345 + // add
239 DeviceDescription description = 346 DeviceDescription description =
240 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, 347 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
241 HW, SW1, SN, A2); 348 HW, SW1, SN, A2);
349 + Capture<ClusterMessage> bcast = new Capture<>();
350 +
351 + resetCommunicatorExpectingSingleBroadcast(bcast);
242 DeviceEvent event = deviceStore.createOrUpdateDevice(PIDA, DID1, description); 352 DeviceEvent event = deviceStore.createOrUpdateDevice(PIDA, DID1, description);
243 assertEquals(DEVICE_ADDED, event.type()); 353 assertEquals(DEVICE_ADDED, event.type());
244 assertDevice(DID1, SW1, event.subject()); 354 assertDevice(DID1, SW1, event.subject());
245 assertEquals(PIDA, event.subject().providerId()); 355 assertEquals(PIDA, event.subject().providerId());
246 assertAnnotationsEquals(event.subject().annotations(), A2); 356 assertAnnotationsEquals(event.subject().annotations(), A2);
247 assertFalse("Ancillary will not bring device up", deviceStore.isAvailable(DID1)); 357 assertFalse("Ancillary will not bring device up", deviceStore.isAvailable(DID1));
358 + verify(clusterCommunicator);
359 + assertInternalDeviceEvent(NID1, DID1, PIDA, description, bcast);
248 360
361 + // update from primary
249 DeviceDescription description2 = 362 DeviceDescription description2 =
250 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, 363 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
251 HW, SW2, SN, A1); 364 HW, SW2, SN, A1);
365 + resetCommunicatorExpectingSingleBroadcast(bcast);
366 +
252 DeviceEvent event2 = deviceStore.createOrUpdateDevice(PID, DID1, description2); 367 DeviceEvent event2 = deviceStore.createOrUpdateDevice(PID, DID1, description2);
253 assertEquals(DEVICE_UPDATED, event2.type()); 368 assertEquals(DEVICE_UPDATED, event2.type());
254 assertDevice(DID1, SW2, event2.subject()); 369 assertDevice(DID1, SW2, event2.subject());
255 assertEquals(PID, event2.subject().providerId()); 370 assertEquals(PID, event2.subject().providerId());
256 assertAnnotationsEquals(event2.subject().annotations(), A1, A2); 371 assertAnnotationsEquals(event2.subject().annotations(), A1, A2);
257 assertTrue(deviceStore.isAvailable(DID1)); 372 assertTrue(deviceStore.isAvailable(DID1));
373 + verify(clusterCommunicator);
374 + assertInternalDeviceEvent(NID1, DID1, PID, description2, bcast);
258 375
376 + // no-op update from primary
377 + resetCommunicatorExpectingNoBroadcast(bcast);
259 assertNull("No change expected", deviceStore.createOrUpdateDevice(PID, DID1, description2)); 378 assertNull("No change expected", deviceStore.createOrUpdateDevice(PID, DID1, description2));
260 379
380 + verify(clusterCommunicator);
381 + assertFalse("no broadcast expected", bcast.hasCaptured());
382 +
261 // For now, Ancillary is ignored once primary appears 383 // For now, Ancillary is ignored once primary appears
384 + resetCommunicatorExpectingNoBroadcast(bcast);
385 +
262 assertNull("No change expected", deviceStore.createOrUpdateDevice(PIDA, DID1, description)); 386 assertNull("No change expected", deviceStore.createOrUpdateDevice(PIDA, DID1, description));
263 387
388 + verify(clusterCommunicator);
389 + assertFalse("no broadcast expected", bcast.hasCaptured());
390 +
264 // But, Ancillary annotations will be in effect 391 // But, Ancillary annotations will be in effect
265 DeviceDescription description3 = 392 DeviceDescription description3 =
266 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, 393 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
267 HW, SW1, SN, A2_2); 394 HW, SW1, SN, A2_2);
395 + resetCommunicatorExpectingSingleBroadcast(bcast);
396 +
268 DeviceEvent event3 = deviceStore.createOrUpdateDevice(PIDA, DID1, description3); 397 DeviceEvent event3 = deviceStore.createOrUpdateDevice(PIDA, DID1, description3);
269 assertEquals(DEVICE_UPDATED, event3.type()); 398 assertEquals(DEVICE_UPDATED, event3.type());
270 // basic information will be the one from Primary 399 // basic information will be the one from Primary
...@@ -273,6 +402,11 @@ public class GossipDeviceStoreTest { ...@@ -273,6 +402,11 @@ public class GossipDeviceStoreTest {
273 // but annotation from Ancillary will be merged 402 // but annotation from Ancillary will be merged
274 assertAnnotationsEquals(event3.subject().annotations(), A1, A2, A2_2); 403 assertAnnotationsEquals(event3.subject().annotations(), A1, A2, A2_2);
275 assertTrue(deviceStore.isAvailable(DID1)); 404 assertTrue(deviceStore.isAvailable(DID1));
405 + verify(clusterCommunicator);
406 + // note: only annotation from PIDA is sent over the wire
407 + assertInternalDeviceEvent(NID1, DID1, PIDA, description3,
408 + asList(union(A2, A2_2)), bcast);
409 +
276 } 410 }
277 411
278 412
...@@ -282,14 +416,24 @@ public class GossipDeviceStoreTest { ...@@ -282,14 +416,24 @@ public class GossipDeviceStoreTest {
282 putDevice(DID1, SW1); 416 putDevice(DID1, SW1);
283 assertTrue(deviceStore.isAvailable(DID1)); 417 assertTrue(deviceStore.isAvailable(DID1));
284 418
419 + Capture<ClusterMessage> bcast = new Capture<>();
420 +
421 + resetCommunicatorExpectingSingleBroadcast(bcast);
285 DeviceEvent event = deviceStore.markOffline(DID1); 422 DeviceEvent event = deviceStore.markOffline(DID1);
286 assertEquals(DEVICE_AVAILABILITY_CHANGED, event.type()); 423 assertEquals(DEVICE_AVAILABILITY_CHANGED, event.type());
287 assertDevice(DID1, SW1, event.subject()); 424 assertDevice(DID1, SW1, event.subject());
288 assertFalse(deviceStore.isAvailable(DID1)); 425 assertFalse(deviceStore.isAvailable(DID1));
426 + verify(clusterCommunicator);
427 + // TODO: verify broadcast message
428 + assertTrue(bcast.hasCaptured());
429 +
289 430
431 + resetCommunicatorExpectingNoBroadcast(bcast);
290 DeviceEvent event2 = deviceStore.markOffline(DID1); 432 DeviceEvent event2 = deviceStore.markOffline(DID1);
291 assertNull("No change, no event", event2); 433 assertNull("No change, no event", event2);
292 -} 434 + verify(clusterCommunicator);
435 + assertFalse(bcast.hasCaptured());
436 + }
293 437
294 @Test 438 @Test
295 public final void testUpdatePorts() { 439 public final void testUpdatePorts() {
...@@ -298,8 +442,13 @@ public class GossipDeviceStoreTest { ...@@ -298,8 +442,13 @@ public class GossipDeviceStoreTest {
298 new DefaultPortDescription(P1, true), 442 new DefaultPortDescription(P1, true),
299 new DefaultPortDescription(P2, true) 443 new DefaultPortDescription(P2, true)
300 ); 444 );
445 + Capture<ClusterMessage> bcast = new Capture<>();
301 446
447 + resetCommunicatorExpectingSingleBroadcast(bcast);
302 List<DeviceEvent> events = deviceStore.updatePorts(PID, DID1, pds); 448 List<DeviceEvent> events = deviceStore.updatePorts(PID, DID1, pds);
449 + verify(clusterCommunicator);
450 + // TODO: verify broadcast message
451 + assertTrue(bcast.hasCaptured());
303 452
304 Set<PortNumber> expectedPorts = Sets.newHashSet(P1, P2); 453 Set<PortNumber> expectedPorts = Sets.newHashSet(P1, P2);
305 for (DeviceEvent event : events) { 454 for (DeviceEvent event : events) {
...@@ -318,7 +467,12 @@ public class GossipDeviceStoreTest { ...@@ -318,7 +467,12 @@ public class GossipDeviceStoreTest {
318 new DefaultPortDescription(P3, true) 467 new DefaultPortDescription(P3, true)
319 ); 468 );
320 469
470 + resetCommunicatorExpectingSingleBroadcast(bcast);
321 events = deviceStore.updatePorts(PID, DID1, pds2); 471 events = deviceStore.updatePorts(PID, DID1, pds2);
472 + verify(clusterCommunicator);
473 + // TODO: verify broadcast message
474 + assertTrue(bcast.hasCaptured());
475 +
322 assertFalse("event should be triggered", events.isEmpty()); 476 assertFalse("event should be triggered", events.isEmpty());
323 for (DeviceEvent event : events) { 477 for (DeviceEvent event : events) {
324 PortNumber num = event.port().number(); 478 PortNumber num = event.port().number();
...@@ -341,7 +495,12 @@ public class GossipDeviceStoreTest { ...@@ -341,7 +495,12 @@ public class GossipDeviceStoreTest {
341 new DefaultPortDescription(P1, false), 495 new DefaultPortDescription(P1, false),
342 new DefaultPortDescription(P2, true) 496 new DefaultPortDescription(P2, true)
343 ); 497 );
498 + resetCommunicatorExpectingSingleBroadcast(bcast);
344 events = deviceStore.updatePorts(PID, DID1, pds3); 499 events = deviceStore.updatePorts(PID, DID1, pds3);
500 + verify(clusterCommunicator);
501 + // TODO: verify broadcast message
502 + assertTrue(bcast.hasCaptured());
503 +
345 assertFalse("event should be triggered", events.isEmpty()); 504 assertFalse("event should be triggered", events.isEmpty());
346 for (DeviceEvent event : events) { 505 for (DeviceEvent event : events) {
347 PortNumber num = event.port().number(); 506 PortNumber num = event.port().number();
...@@ -357,7 +516,6 @@ public class GossipDeviceStoreTest { ...@@ -357,7 +516,6 @@ public class GossipDeviceStoreTest {
357 fail("Unknown port number encountered: " + num); 516 fail("Unknown port number encountered: " + num);
358 } 517 }
359 } 518 }
360 -
361 } 519 }
362 520
363 @Test 521 @Test
...@@ -368,16 +526,22 @@ public class GossipDeviceStoreTest { ...@@ -368,16 +526,22 @@ public class GossipDeviceStoreTest {
368 ); 526 );
369 deviceStore.updatePorts(PID, DID1, pds); 527 deviceStore.updatePorts(PID, DID1, pds);
370 528
371 - DeviceEvent event = deviceStore.updatePortStatus(PID, DID1, 529 + Capture<ClusterMessage> bcast = new Capture<>();
372 - new DefaultPortDescription(P1, false)); 530 +
531 + resetCommunicatorExpectingSingleBroadcast(bcast);
532 + final DefaultPortDescription desc = new DefaultPortDescription(P1, false);
533 + DeviceEvent event = deviceStore.updatePortStatus(PID, DID1, desc);
373 assertEquals(PORT_UPDATED, event.type()); 534 assertEquals(PORT_UPDATED, event.type());
374 assertDevice(DID1, SW1, event.subject()); 535 assertDevice(DID1, SW1, event.subject());
375 assertEquals(P1, event.port().number()); 536 assertEquals(P1, event.port().number());
376 assertFalse("Port is disabled", event.port().isEnabled()); 537 assertFalse("Port is disabled", event.port().isEnabled());
377 - 538 + verify(clusterCommunicator);
539 + assertInternalPortStatusEvent(NID1, DID1, PID, desc, NO_ANNOTATION, bcast);
540 + assertTrue(bcast.hasCaptured());
378 } 541 }
542 +
379 @Test 543 @Test
380 - public final void testUpdatePortStatusAncillary() { 544 + public final void testUpdatePortStatusAncillary() throws IOException {
381 putDeviceAncillary(DID1, SW1); 545 putDeviceAncillary(DID1, SW1);
382 putDevice(DID1, SW1); 546 putDevice(DID1, SW1);
383 List<PortDescription> pds = Arrays.<PortDescription>asList( 547 List<PortDescription> pds = Arrays.<PortDescription>asList(
...@@ -385,36 +549,106 @@ public class GossipDeviceStoreTest { ...@@ -385,36 +549,106 @@ public class GossipDeviceStoreTest {
385 ); 549 );
386 deviceStore.updatePorts(PID, DID1, pds); 550 deviceStore.updatePorts(PID, DID1, pds);
387 551
388 - DeviceEvent event = deviceStore.updatePortStatus(PID, DID1, 552 + Capture<ClusterMessage> bcast = new Capture<>();
389 - new DefaultPortDescription(P1, false, A1_2)); 553 +
554 +
555 + // update port from primary
556 + resetCommunicatorExpectingSingleBroadcast(bcast);
557 + final DefaultPortDescription desc1 = new DefaultPortDescription(P1, false, A1_2);
558 + DeviceEvent event = deviceStore.updatePortStatus(PID, DID1, desc1);
390 assertEquals(PORT_UPDATED, event.type()); 559 assertEquals(PORT_UPDATED, event.type());
391 assertDevice(DID1, SW1, event.subject()); 560 assertDevice(DID1, SW1, event.subject());
392 assertEquals(P1, event.port().number()); 561 assertEquals(P1, event.port().number());
393 assertAnnotationsEquals(event.port().annotations(), A1, A1_2); 562 assertAnnotationsEquals(event.port().annotations(), A1, A1_2);
394 assertFalse("Port is disabled", event.port().isEnabled()); 563 assertFalse("Port is disabled", event.port().isEnabled());
395 - 564 + verify(clusterCommunicator);
396 - DeviceEvent event2 = deviceStore.updatePortStatus(PIDA, DID1, 565 + assertInternalPortStatusEvent(NID1, DID1, PID, desc1, asList(A1, A1_2), bcast);
397 - new DefaultPortDescription(P1, true)); 566 + assertTrue(bcast.hasCaptured());
567 +
568 + // update port from ancillary with no attributes
569 + resetCommunicatorExpectingNoBroadcast(bcast);
570 + final DefaultPortDescription desc2 = new DefaultPortDescription(P1, true);
571 + DeviceEvent event2 = deviceStore.updatePortStatus(PIDA, DID1, desc2);
398 assertNull("Ancillary is ignored if primary exists", event2); 572 assertNull("Ancillary is ignored if primary exists", event2);
573 + verify(clusterCommunicator);
574 + assertFalse(bcast.hasCaptured());
399 575
400 // but, Ancillary annotation update will be notified 576 // but, Ancillary annotation update will be notified
401 - DeviceEvent event3 = deviceStore.updatePortStatus(PIDA, DID1, 577 + resetCommunicatorExpectingSingleBroadcast(bcast);
402 - new DefaultPortDescription(P1, true, A2)); 578 + final DefaultPortDescription desc3 = new DefaultPortDescription(P1, true, A2);
579 + DeviceEvent event3 = deviceStore.updatePortStatus(PIDA, DID1, desc3);
403 assertEquals(PORT_UPDATED, event3.type()); 580 assertEquals(PORT_UPDATED, event3.type());
404 assertDevice(DID1, SW1, event3.subject()); 581 assertDevice(DID1, SW1, event3.subject());
405 assertEquals(P1, event3.port().number()); 582 assertEquals(P1, event3.port().number());
406 assertAnnotationsEquals(event3.port().annotations(), A1, A1_2, A2); 583 assertAnnotationsEquals(event3.port().annotations(), A1, A1_2, A2);
407 assertFalse("Port is disabled", event3.port().isEnabled()); 584 assertFalse("Port is disabled", event3.port().isEnabled());
585 + verify(clusterCommunicator);
586 + assertInternalPortStatusEvent(NID1, DID1, PIDA, desc3, asList(A2), bcast);
587 + assertTrue(bcast.hasCaptured());
408 588
409 // port only reported from Ancillary will be notified as down 589 // port only reported from Ancillary will be notified as down
410 - DeviceEvent event4 = deviceStore.updatePortStatus(PIDA, DID1, 590 + resetCommunicatorExpectingSingleBroadcast(bcast);
411 - new DefaultPortDescription(P2, true)); 591 + final DefaultPortDescription desc4 = new DefaultPortDescription(P2, true);
592 + DeviceEvent event4 = deviceStore.updatePortStatus(PIDA, DID1, desc4);
412 assertEquals(PORT_ADDED, event4.type()); 593 assertEquals(PORT_ADDED, event4.type());
413 assertDevice(DID1, SW1, event4.subject()); 594 assertDevice(DID1, SW1, event4.subject());
414 assertEquals(P2, event4.port().number()); 595 assertEquals(P2, event4.port().number());
415 assertAnnotationsEquals(event4.port().annotations()); 596 assertAnnotationsEquals(event4.port().annotations());
416 assertFalse("Port is disabled if not given from primary provider", 597 assertFalse("Port is disabled if not given from primary provider",
417 event4.port().isEnabled()); 598 event4.port().isEnabled());
599 + verify(clusterCommunicator);
600 + // TODO: verify broadcast message content
601 + assertInternalPortStatusEvent(NID1, DID1, PIDA, desc4, NO_ANNOTATION, bcast);
602 + assertTrue(bcast.hasCaptured());
603 + }
604 +
605 + private void assertInternalPortStatusEvent(NodeId sender, DeviceId did,
606 + ProviderId pid, DefaultPortDescription expectedDesc,
607 + List<SparseAnnotations> expectedAnnotations, Capture<ClusterMessage> actualMsg) {
608 +
609 + assertTrue(actualMsg.hasCaptured());
610 + assertEquals(sender, actualMsg.getValue().sender());
611 + assertEquals(GossipDeviceStoreMessageSubjects.PORT_STATUS_UPDATE,
612 + actualMsg.getValue().subject());
613 + InternalPortStatusEvent addEvent
614 + = testGossipDeviceStore.deserialize(actualMsg.getValue().payload());
615 + assertEquals(did, addEvent.deviceId());
616 + assertEquals(pid, addEvent.providerId());
617 + assertPortDescriptionEquals(expectedDesc, expectedAnnotations,
618 + addEvent.portDescription().value());
619 +
620 + }
621 +
622 + private void assertPortDescriptionEquals(
623 + PortDescription expectedDesc,
624 + List<SparseAnnotations> expectedAnnotations,
625 + PortDescription actual) {
626 +
627 + assertEquals(expectedDesc.portNumber(), actual.portNumber());
628 + assertEquals(expectedDesc.isEnabled(), actual.isEnabled());
629 +
630 + assertAnnotationsEquals(actual.annotations(),
631 + expectedAnnotations.toArray(new SparseAnnotations[0]));
632 + }
633 +
634 + private void resetCommunicatorExpectingNoBroadcast(
635 + Capture<ClusterMessage> bcast) {
636 + bcast.reset();
637 + reset(clusterCommunicator);
638 + replay(clusterCommunicator);
639 + }
640 +
641 + private void resetCommunicatorExpectingSingleBroadcast(
642 + Capture<ClusterMessage> bcast) {
643 +
644 + bcast.reset();
645 + reset(clusterCommunicator);
646 + try {
647 + expect(clusterCommunicator.broadcast(capture(bcast))).andReturn(true).once();
648 + } catch (IOException e) {
649 + fail("Should never reach here");
650 + }
651 + replay(clusterCommunicator);
418 } 652 }
419 653
420 @Test 654 @Test
...@@ -476,12 +710,19 @@ public class GossipDeviceStoreTest { ...@@ -476,12 +710,19 @@ public class GossipDeviceStoreTest {
476 assertAnnotationsEquals(deviceStore.getDevice(DID1).annotations(), A1); 710 assertAnnotationsEquals(deviceStore.getDevice(DID1).annotations(), A1);
477 assertAnnotationsEquals(deviceStore.getPort(DID1, P1).annotations(), A2); 711 assertAnnotationsEquals(deviceStore.getPort(DID1, P1).annotations(), A2);
478 712
713 + Capture<ClusterMessage> bcast = new Capture<>();
714 +
715 + resetCommunicatorExpectingSingleBroadcast(bcast);
716 +
479 DeviceEvent event = deviceStore.removeDevice(DID1); 717 DeviceEvent event = deviceStore.removeDevice(DID1);
480 assertEquals(DEVICE_REMOVED, event.type()); 718 assertEquals(DEVICE_REMOVED, event.type());
481 assertDevice(DID1, SW1, event.subject()); 719 assertDevice(DID1, SW1, event.subject());
482 720
483 assertEquals(1, deviceStore.getDeviceCount()); 721 assertEquals(1, deviceStore.getDeviceCount());
484 assertEquals(0, deviceStore.getPorts(DID1).size()); 722 assertEquals(0, deviceStore.getPorts(DID1).size());
723 + verify(clusterCommunicator);
724 + // TODO: verify broadcast message
725 + assertTrue(bcast.hasCaptured());
485 726
486 // putBack Device, Port w/o annotation 727 // putBack Device, Port w/o annotation
487 putDevice(DID1, SW1); 728 putDevice(DID1, SW1);
...@@ -563,34 +804,28 @@ public class GossipDeviceStoreTest { ...@@ -563,34 +804,28 @@ public class GossipDeviceStoreTest {
563 this.clusterService = clusterService; 804 this.clusterService = clusterService;
564 this.clusterCommunicator = clusterCommunicator; 805 this.clusterCommunicator = clusterCommunicator;
565 } 806 }
566 - }
567 807
568 - private static final class TestClusterCommunicationService implements ClusterCommunicationService { 808 + public <T> T deserialize(byte[] bytes) {
569 - @Override 809 + return SERIALIZER.decode(bytes);
570 - public boolean broadcast(ClusterMessage message) throws IOException { return true; } 810 + }
571 - @Override
572 - public boolean unicast(ClusterMessage message, NodeId nodeId) throws IOException { return true; }
573 - @Override
574 - public boolean multicast(ClusterMessage message, Set<NodeId> nodeIds) throws IOException { return true; }
575 - @Override
576 - public void addSubscriber(MessageSubject subject, ClusterMessageHandler subscriber) {}
577 } 811 }
578 812
579 private static final class TestClusterService implements ClusterService { 813 private static final class TestClusterService implements ClusterService {
580 814
581 - private static final ControllerNode ONOS1 =
582 - new DefaultControllerNode(new NodeId("N1"), IpPrefix.valueOf("127.0.0.1"));
583 private final Map<NodeId, ControllerNode> nodes = new HashMap<>(); 815 private final Map<NodeId, ControllerNode> nodes = new HashMap<>();
584 private final Map<NodeId, ControllerNode.State> nodeStates = new HashMap<>(); 816 private final Map<NodeId, ControllerNode.State> nodeStates = new HashMap<>();
585 817
586 public TestClusterService() { 818 public TestClusterService() {
587 - nodes.put(new NodeId("N1"), ONOS1); 819 + nodes.put(NID1, ONOS1);
588 - nodeStates.put(new NodeId("N1"), ControllerNode.State.ACTIVE); 820 + nodeStates.put(NID1, ACTIVE);
821 +
822 + nodes.put(NID2, ONOS2);
823 + nodeStates.put(NID2, ACTIVE);
589 } 824 }
590 825
591 @Override 826 @Override
592 public ControllerNode getLocalNode() { 827 public ControllerNode getLocalNode() {
593 - return ONOS1; 828 + return GossipDeviceStoreTest.ONOS1;
594 } 829 }
595 830
596 @Override 831 @Override
......
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>
......
...@@ -43,8 +43,8 @@ public class DistributedFlowRuleStore ...@@ -43,8 +43,8 @@ public class DistributedFlowRuleStore
43 private final Multimap<DeviceId, FlowEntry> flowEntries = 43 private final Multimap<DeviceId, FlowEntry> flowEntries =
44 ArrayListMultimap.<DeviceId, FlowEntry>create(); 44 ArrayListMultimap.<DeviceId, FlowEntry>create();
45 45
46 - private final Multimap<ApplicationId, FlowRule> flowEntriesById = 46 + private final Multimap<Short, FlowRule> flowEntriesById =
47 - ArrayListMultimap.<ApplicationId, FlowRule>create(); 47 + ArrayListMultimap.<Short, FlowRule>create();
48 48
49 @Activate 49 @Activate
50 public void activate() { 50 public void activate() {
...@@ -83,7 +83,7 @@ public class DistributedFlowRuleStore ...@@ -83,7 +83,7 @@ public class DistributedFlowRuleStore
83 83
84 @Override 84 @Override
85 public synchronized Iterable<FlowRule> getFlowRulesByAppId(ApplicationId appId) { 85 public synchronized Iterable<FlowRule> getFlowRulesByAppId(ApplicationId appId) {
86 - Collection<FlowRule> rules = flowEntriesById.get(appId); 86 + Collection<FlowRule> rules = flowEntriesById.get(appId.id());
87 if (rules == null) { 87 if (rules == null) {
88 return Collections.emptyList(); 88 return Collections.emptyList();
89 } 89 }
......
1 package org.onlab.onos.store.host.impl; 1 package org.onlab.onos.store.host.impl;
2 2
3 -import static org.onlab.onos.net.host.HostEvent.Type.HOST_ADDED; 3 +import com.google.common.collect.HashMultimap;
4 -import static org.onlab.onos.net.host.HostEvent.Type.HOST_MOVED; 4 +import com.google.common.collect.ImmutableSet;
5 -import static org.onlab.onos.net.host.HostEvent.Type.HOST_REMOVED; 5 +import com.google.common.collect.Multimap;
6 -import static org.onlab.onos.net.host.HostEvent.Type.HOST_UPDATED; 6 +import com.google.common.collect.Sets;
7 -import static org.slf4j.LoggerFactory.getLogger;
8 -
9 -import java.util.Collections;
10 -import java.util.HashSet;
11 -import java.util.Map;
12 -import java.util.Set;
13 -import java.util.concurrent.ConcurrentHashMap;
14 -
15 import org.apache.felix.scr.annotations.Activate; 7 import org.apache.felix.scr.annotations.Activate;
16 import org.apache.felix.scr.annotations.Component; 8 import org.apache.felix.scr.annotations.Component;
17 import org.apache.felix.scr.annotations.Deactivate; 9 import org.apache.felix.scr.annotations.Deactivate;
18 import org.apache.felix.scr.annotations.Service; 10 import org.apache.felix.scr.annotations.Service;
11 +import org.onlab.onos.net.Annotations;
19 import org.onlab.onos.net.ConnectPoint; 12 import org.onlab.onos.net.ConnectPoint;
20 import org.onlab.onos.net.DefaultHost; 13 import org.onlab.onos.net.DefaultHost;
21 import org.onlab.onos.net.DeviceId; 14 import org.onlab.onos.net.DeviceId;
22 import org.onlab.onos.net.Host; 15 import org.onlab.onos.net.Host;
23 import org.onlab.onos.net.HostId; 16 import org.onlab.onos.net.HostId;
17 +import org.onlab.onos.net.HostLocation;
24 import org.onlab.onos.net.host.HostDescription; 18 import org.onlab.onos.net.host.HostDescription;
25 import org.onlab.onos.net.host.HostEvent; 19 import org.onlab.onos.net.host.HostEvent;
26 import org.onlab.onos.net.host.HostStore; 20 import org.onlab.onos.net.host.HostStore;
...@@ -33,10 +27,13 @@ import org.onlab.packet.MacAddress; ...@@ -33,10 +27,13 @@ import org.onlab.packet.MacAddress;
33 import org.onlab.packet.VlanId; 27 import org.onlab.packet.VlanId;
34 import org.slf4j.Logger; 28 import org.slf4j.Logger;
35 29
36 -import com.google.common.collect.HashMultimap; 30 +import java.util.HashSet;
37 -import com.google.common.collect.ImmutableSet; 31 +import java.util.Map;
38 -import com.google.common.collect.Multimap; 32 +import java.util.Set;
39 -import com.google.common.collect.Sets; 33 +import java.util.concurrent.ConcurrentHashMap;
34 +
35 +import static org.onlab.onos.net.host.HostEvent.Type.*;
36 +import static org.slf4j.LoggerFactory.getLogger;
40 37
41 /** 38 /**
42 * TEMPORARY: Manages inventory of end-station hosts using distributed 39 * TEMPORARY: Manages inventory of end-station hosts using distributed
...@@ -46,13 +43,13 @@ import com.google.common.collect.Sets; ...@@ -46,13 +43,13 @@ import com.google.common.collect.Sets;
46 @Component(immediate = true) 43 @Component(immediate = true)
47 @Service 44 @Service
48 public class DistributedHostStore 45 public class DistributedHostStore
49 -extends AbstractStore<HostEvent, HostStoreDelegate> 46 + extends AbstractStore<HostEvent, HostStoreDelegate>
50 -implements HostStore { 47 + implements HostStore {
51 48
52 private final Logger log = getLogger(getClass()); 49 private final Logger log = getLogger(getClass());
53 50
54 // Host inventory 51 // Host inventory
55 - private final Map<HostId, Host> hosts = new ConcurrentHashMap<>(); 52 + private final Map<HostId, StoredHost> hosts = new ConcurrentHashMap<>(2000000, 0.75f, 16);
56 53
57 // Hosts tracked by their location 54 // Hosts tracked by their location
58 private final Multimap<ConnectPoint, Host> locations = HashMultimap.create(); 55 private final Multimap<ConnectPoint, Host> locations = HashMultimap.create();
...@@ -72,8 +69,8 @@ implements HostStore { ...@@ -72,8 +69,8 @@ implements HostStore {
72 69
73 @Override 70 @Override
74 public HostEvent createOrUpdateHost(ProviderId providerId, HostId hostId, 71 public HostEvent createOrUpdateHost(ProviderId providerId, HostId hostId,
75 - HostDescription hostDescription) { 72 + HostDescription hostDescription) {
76 - Host host = hosts.get(hostId); 73 + StoredHost host = hosts.get(hostId);
77 if (host == null) { 74 if (host == null) {
78 return createHost(providerId, hostId, hostDescription); 75 return createHost(providerId, hostId, hostDescription);
79 } 76 }
...@@ -82,12 +79,12 @@ implements HostStore { ...@@ -82,12 +79,12 @@ implements HostStore {
82 79
83 // creates a new host and sends HOST_ADDED 80 // creates a new host and sends HOST_ADDED
84 private HostEvent createHost(ProviderId providerId, HostId hostId, 81 private HostEvent createHost(ProviderId providerId, HostId hostId,
85 - HostDescription descr) { 82 + HostDescription descr) {
86 - DefaultHost newhost = new DefaultHost(providerId, hostId, 83 + StoredHost newhost = new StoredHost(providerId, hostId,
87 - descr.hwAddress(), 84 + descr.hwAddress(),
88 - descr.vlan(), 85 + descr.vlan(),
89 - descr.location(), 86 + descr.location(),
90 - descr.ipAddresses()); 87 + ImmutableSet.of(descr.ipAddress()));
91 synchronized (this) { 88 synchronized (this) {
92 hosts.put(hostId, newhost); 89 hosts.put(hostId, newhost);
93 locations.put(descr.location(), newhost); 90 locations.put(descr.location(), newhost);
...@@ -96,28 +93,24 @@ implements HostStore { ...@@ -96,28 +93,24 @@ implements HostStore {
96 } 93 }
97 94
98 // checks for type of update to host, sends appropriate event 95 // checks for type of update to host, sends appropriate event
99 - private HostEvent updateHost(ProviderId providerId, Host host, 96 + private HostEvent updateHost(ProviderId providerId, StoredHost host,
100 - HostDescription descr) { 97 + HostDescription descr) {
101 - DefaultHost updated;
102 HostEvent event; 98 HostEvent event;
103 if (!host.location().equals(descr.location())) { 99 if (!host.location().equals(descr.location())) {
104 - updated = new DefaultHost(providerId, host.id(), 100 + host.setLocation(descr.location());
105 - host.mac(), 101 + return new HostEvent(HOST_MOVED, host);
106 - host.vlan(), 102 + }
107 - descr.location(), 103 +
108 - host.ipAddresses()); 104 + if (host.ipAddresses().contains(descr.ipAddress())) {
109 - event = new HostEvent(HOST_MOVED, updated);
110 -
111 - } else if (!(host.ipAddresses().equals(descr.ipAddresses()))) {
112 - updated = new DefaultHost(providerId, host.id(),
113 - host.mac(),
114 - host.vlan(),
115 - descr.location(),
116 - descr.ipAddresses());
117 - event = new HostEvent(HOST_UPDATED, updated);
118 - } else {
119 return null; 105 return null;
120 } 106 }
107 +
108 + Set<IpPrefix> addresses = new HashSet<>(host.ipAddresses());
109 + addresses.add(descr.ipAddress());
110 + StoredHost updated = new StoredHost(providerId, host.id(),
111 + host.mac(), host.vlan(),
112 + descr.location(), addresses);
113 + event = new HostEvent(HOST_UPDATED, updated);
121 synchronized (this) { 114 synchronized (this) {
122 hosts.put(host.id(), updated); 115 hosts.put(host.id(), updated);
123 locations.remove(host.location(), host); 116 locations.remove(host.location(), host);
...@@ -145,7 +138,7 @@ implements HostStore { ...@@ -145,7 +138,7 @@ implements HostStore {
145 138
146 @Override 139 @Override
147 public Iterable<Host> getHosts() { 140 public Iterable<Host> getHosts() {
148 - return Collections.unmodifiableSet(new HashSet<>(hosts.values())); 141 + return ImmutableSet.<Host>copyOf(hosts.values());
149 } 142 }
150 143
151 @Override 144 @Override
...@@ -275,4 +268,35 @@ implements HostStore { ...@@ -275,4 +268,35 @@ implements HostStore {
275 return addresses; 268 return addresses;
276 } 269 }
277 270
271 + // Auxiliary extension to allow location to mutate.
272 + private class StoredHost extends DefaultHost {
273 + private HostLocation location;
274 +
275 + /**
276 + * Creates an end-station host using the supplied information.
277 + *
278 + * @param providerId provider identity
279 + * @param id host identifier
280 + * @param mac host MAC address
281 + * @param vlan host VLAN identifier
282 + * @param location host location
283 + * @param ips host IP addresses
284 + * @param annotations optional key/value annotations
285 + */
286 + public StoredHost(ProviderId providerId, HostId id,
287 + MacAddress mac, VlanId vlan, HostLocation location,
288 + Set<IpPrefix> ips, Annotations... annotations) {
289 + super(providerId, id, mac, vlan, location, ips, annotations);
290 + this.location = location;
291 + }
292 +
293 + void setLocation(HostLocation location) {
294 + this.location = location;
295 + }
296 +
297 + @Override
298 + public HostLocation location() {
299 + return location;
300 + }
301 + }
278 } 302 }
......
...@@ -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
......
1 +package org.onlab.onos.store.serializers;
2 +
3 +import org.onlab.util.KryoPool.FamilySerializer;
4 +
5 +import com.esotericsoftware.kryo.Kryo;
6 +import com.esotericsoftware.kryo.io.Input;
7 +import com.esotericsoftware.kryo.io.Output;
8 +import com.google.common.collect.ImmutableList;
9 +import com.google.common.collect.ImmutableList.Builder;
10 +
11 +/**
12 + * Creates {@link ImmutableList} serializer instance.
13 + */
14 +public class ImmutableListSerializer extends FamilySerializer<ImmutableList<?>> {
15 +
16 + /**
17 + * Creates {@link ImmutableList} serializer instance.
18 + */
19 + public ImmutableListSerializer() {
20 + // non-null, immutable
21 + super(false, true);
22 + }
23 + @Override
24 + public void write(Kryo kryo, Output output, ImmutableList<?> object) {
25 + output.writeInt(object.size());
26 + for (Object e : object) {
27 + kryo.writeClassAndObject(output, e);
28 + }
29 + }
30 +
31 + @Override
32 + public ImmutableList<?> read(Kryo kryo, Input input,
33 + Class<ImmutableList<?>> type) {
34 + final int size = input.readInt();
35 + Builder<Object> builder = ImmutableList.builder();
36 + for (int i = 0; i < size; ++i) {
37 + builder.add(kryo.readClassAndObject(input));
38 + }
39 + return builder.build();
40 + }
41 +
42 + @Override
43 + public void registerFamilies(Kryo kryo) {
44 + kryo.register(ImmutableList.of(1).getClass(), this);
45 + kryo.register(ImmutableList.of(1, 2).getClass(), this);
46 + // TODO register required ImmutableList variants
47 + }
48 +
49 +}
...@@ -24,12 +24,15 @@ import org.onlab.onos.net.Port; ...@@ -24,12 +24,15 @@ 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;
29 +import org.onlab.onos.store.Timestamp;
28 import org.onlab.packet.IpAddress; 30 import org.onlab.packet.IpAddress;
29 import org.onlab.packet.IpPrefix; 31 import org.onlab.packet.IpPrefix;
30 import org.onlab.util.KryoPool; 32 import org.onlab.util.KryoPool;
31 33
32 -import de.javakaffee.kryoserializers.URISerializer; 34 +import com.google.common.collect.ImmutableList;
35 +import com.google.common.collect.ImmutableMap;
33 36
34 public final class KryoPoolUtil { 37 public final class KryoPoolUtil {
35 38
...@@ -47,23 +50,29 @@ public final class KryoPoolUtil { ...@@ -47,23 +50,29 @@ public final class KryoPoolUtil {
47 */ 50 */
48 public static final KryoPool API = KryoPool.newBuilder() 51 public static final KryoPool API = KryoPool.newBuilder()
49 .register(MISC) 52 .register(MISC)
53 + .register(ImmutableMap.class, new ImmutableMapSerializer())
54 + .register(ImmutableList.class, new ImmutableListSerializer())
50 .register( 55 .register(
51 // 56 //
52 ArrayList.class, 57 ArrayList.class,
53 Arrays.asList().getClass(), 58 Arrays.asList().getClass(),
54 HashMap.class, 59 HashMap.class,
55 // 60 //
61 + //
56 ControllerNode.State.class, 62 ControllerNode.State.class,
57 Device.Type.class, 63 Device.Type.class,
58 DefaultAnnotations.class, 64 DefaultAnnotations.class,
59 DefaultControllerNode.class, 65 DefaultControllerNode.class,
60 DefaultDevice.class, 66 DefaultDevice.class,
61 DefaultDeviceDescription.class, 67 DefaultDeviceDescription.class,
68 + DefaultLinkDescription.class,
62 MastershipRole.class, 69 MastershipRole.class,
63 Port.class, 70 Port.class,
64 DefaultPortDescription.class, 71 DefaultPortDescription.class,
65 Element.class, 72 Element.class,
66 - Link.Type.class 73 + Link.Type.class,
74 + Timestamp.class
75 +
67 ) 76 )
68 .register(URI.class, new URISerializer()) 77 .register(URI.class, new URISerializer())
69 .register(NodeId.class, new NodeIdSerializer()) 78 .register(NodeId.class, new NodeIdSerializer())
......
1 package org.onlab.onos.store.serializers; 1 package org.onlab.onos.store.serializers;
2 2
3 import org.onlab.util.KryoPool; 3 import org.onlab.util.KryoPool;
4 -import org.slf4j.Logger;
5 -import org.slf4j.LoggerFactory;
6 -
7 import java.nio.ByteBuffer; 4 import java.nio.ByteBuffer;
8 5
9 /** 6 /**
...@@ -11,10 +8,8 @@ import java.nio.ByteBuffer; ...@@ -11,10 +8,8 @@ import java.nio.ByteBuffer;
11 */ 8 */
12 public class KryoSerializer implements StoreSerializer { 9 public class KryoSerializer implements StoreSerializer {
13 10
14 - private final Logger log = LoggerFactory.getLogger(getClass());
15 protected KryoPool serializerPool; 11 protected KryoPool serializerPool;
16 12
17 -
18 public KryoSerializer() { 13 public KryoSerializer() {
19 setupKryoPool(); 14 setupKryoPool();
20 } 15 }
......
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 +}
...@@ -42,8 +42,8 @@ public class SimpleFlowRuleStore ...@@ -42,8 +42,8 @@ public class SimpleFlowRuleStore
42 private final Multimap<DeviceId, FlowEntry> flowEntries = 42 private final Multimap<DeviceId, FlowEntry> flowEntries =
43 ArrayListMultimap.<DeviceId, FlowEntry>create(); 43 ArrayListMultimap.<DeviceId, FlowEntry>create();
44 44
45 - private final Multimap<ApplicationId, FlowRule> flowEntriesById = 45 + private final Multimap<Short, FlowRule> flowEntriesById =
46 - ArrayListMultimap.<ApplicationId, FlowRule>create(); 46 + ArrayListMultimap.<Short, FlowRule>create();
47 47
48 @Activate 48 @Activate
49 public void activate() { 49 public void activate() {
...@@ -82,7 +82,7 @@ public class SimpleFlowRuleStore ...@@ -82,7 +82,7 @@ public class SimpleFlowRuleStore
82 82
83 @Override 83 @Override
84 public synchronized Iterable<FlowRule> getFlowRulesByAppId(ApplicationId appId) { 84 public synchronized Iterable<FlowRule> getFlowRulesByAppId(ApplicationId appId) {
85 - Collection<FlowRule> rules = flowEntriesById.get(appId); 85 + Collection<FlowRule> rules = flowEntriesById.get(appId.id());
86 if (rules == null) { 86 if (rules == null) {
87 return Collections.emptyList(); 87 return Collections.emptyList();
88 } 88 }
......
1 package org.onlab.onos.store.trivial.impl; 1 package org.onlab.onos.store.trivial.impl;
2 2
3 -import static org.onlab.onos.net.host.HostEvent.Type.HOST_ADDED; 3 +import com.google.common.collect.HashMultimap;
4 -import static org.onlab.onos.net.host.HostEvent.Type.HOST_MOVED; 4 +import com.google.common.collect.ImmutableSet;
5 -import static org.onlab.onos.net.host.HostEvent.Type.HOST_REMOVED; 5 +import com.google.common.collect.Multimap;
6 -import static org.onlab.onos.net.host.HostEvent.Type.HOST_UPDATED; 6 +import com.google.common.collect.Sets;
7 -import static org.slf4j.LoggerFactory.getLogger;
8 -
9 -import java.util.Collections;
10 -import java.util.HashSet;
11 -import java.util.Map;
12 -import java.util.Set;
13 -import java.util.concurrent.ConcurrentHashMap;
14 -
15 import org.apache.felix.scr.annotations.Activate; 7 import org.apache.felix.scr.annotations.Activate;
16 import org.apache.felix.scr.annotations.Component; 8 import org.apache.felix.scr.annotations.Component;
17 import org.apache.felix.scr.annotations.Deactivate; 9 import org.apache.felix.scr.annotations.Deactivate;
18 import org.apache.felix.scr.annotations.Service; 10 import org.apache.felix.scr.annotations.Service;
11 +import org.onlab.onos.net.Annotations;
19 import org.onlab.onos.net.ConnectPoint; 12 import org.onlab.onos.net.ConnectPoint;
20 import org.onlab.onos.net.DefaultHost; 13 import org.onlab.onos.net.DefaultHost;
21 import org.onlab.onos.net.DeviceId; 14 import org.onlab.onos.net.DeviceId;
22 import org.onlab.onos.net.Host; 15 import org.onlab.onos.net.Host;
23 import org.onlab.onos.net.HostId; 16 import org.onlab.onos.net.HostId;
17 +import org.onlab.onos.net.HostLocation;
24 import org.onlab.onos.net.host.HostDescription; 18 import org.onlab.onos.net.host.HostDescription;
25 import org.onlab.onos.net.host.HostEvent; 19 import org.onlab.onos.net.host.HostEvent;
26 import org.onlab.onos.net.host.HostStore; 20 import org.onlab.onos.net.host.HostStore;
...@@ -33,10 +27,13 @@ import org.onlab.packet.MacAddress; ...@@ -33,10 +27,13 @@ import org.onlab.packet.MacAddress;
33 import org.onlab.packet.VlanId; 27 import org.onlab.packet.VlanId;
34 import org.slf4j.Logger; 28 import org.slf4j.Logger;
35 29
36 -import com.google.common.collect.HashMultimap; 30 +import java.util.HashSet;
37 -import com.google.common.collect.ImmutableSet; 31 +import java.util.Map;
38 -import com.google.common.collect.Multimap; 32 +import java.util.Set;
39 -import com.google.common.collect.Sets; 33 +import java.util.concurrent.ConcurrentHashMap;
34 +
35 +import static org.onlab.onos.net.host.HostEvent.Type.*;
36 +import static org.slf4j.LoggerFactory.getLogger;
40 37
41 /** 38 /**
42 * Manages inventory of end-station hosts using trivial in-memory 39 * Manages inventory of end-station hosts using trivial in-memory
...@@ -51,7 +48,7 @@ public class SimpleHostStore ...@@ -51,7 +48,7 @@ public class SimpleHostStore
51 private final Logger log = getLogger(getClass()); 48 private final Logger log = getLogger(getClass());
52 49
53 // Host inventory 50 // Host inventory
54 - private final Map<HostId, Host> hosts = new ConcurrentHashMap<>(); 51 + private final Map<HostId, StoredHost> hosts = new ConcurrentHashMap<>(2000000, 0.75f, 16);
55 52
56 // Hosts tracked by their location 53 // Hosts tracked by their location
57 private final Multimap<ConnectPoint, Host> locations = HashMultimap.create(); 54 private final Multimap<ConnectPoint, Host> locations = HashMultimap.create();
...@@ -72,7 +69,7 @@ public class SimpleHostStore ...@@ -72,7 +69,7 @@ public class SimpleHostStore
72 @Override 69 @Override
73 public HostEvent createOrUpdateHost(ProviderId providerId, HostId hostId, 70 public HostEvent createOrUpdateHost(ProviderId providerId, HostId hostId,
74 HostDescription hostDescription) { 71 HostDescription hostDescription) {
75 - Host host = hosts.get(hostId); 72 + StoredHost host = hosts.get(hostId);
76 if (host == null) { 73 if (host == null) {
77 return createHost(providerId, hostId, hostDescription); 74 return createHost(providerId, hostId, hostDescription);
78 } 75 }
...@@ -82,11 +79,11 @@ public class SimpleHostStore ...@@ -82,11 +79,11 @@ public class SimpleHostStore
82 // creates a new host and sends HOST_ADDED 79 // creates a new host and sends HOST_ADDED
83 private HostEvent createHost(ProviderId providerId, HostId hostId, 80 private HostEvent createHost(ProviderId providerId, HostId hostId,
84 HostDescription descr) { 81 HostDescription descr) {
85 - DefaultHost newhost = new DefaultHost(providerId, hostId, 82 + StoredHost newhost = new StoredHost(providerId, hostId,
86 - descr.hwAddress(), 83 + descr.hwAddress(),
87 - descr.vlan(), 84 + descr.vlan(),
88 - descr.location(), 85 + descr.location(),
89 - descr.ipAddresses()); 86 + ImmutableSet.of(descr.ipAddress()));
90 synchronized (this) { 87 synchronized (this) {
91 hosts.put(hostId, newhost); 88 hosts.put(hostId, newhost);
92 locations.put(descr.location(), newhost); 89 locations.put(descr.location(), newhost);
...@@ -95,28 +92,24 @@ public class SimpleHostStore ...@@ -95,28 +92,24 @@ public class SimpleHostStore
95 } 92 }
96 93
97 // checks for type of update to host, sends appropriate event 94 // checks for type of update to host, sends appropriate event
98 - private HostEvent updateHost(ProviderId providerId, Host host, 95 + private HostEvent updateHost(ProviderId providerId, StoredHost host,
99 HostDescription descr) { 96 HostDescription descr) {
100 - DefaultHost updated;
101 HostEvent event; 97 HostEvent event;
102 if (!host.location().equals(descr.location())) { 98 if (!host.location().equals(descr.location())) {
103 - updated = new DefaultHost(providerId, host.id(), 99 + host.setLocation(descr.location());
104 - host.mac(), 100 + return new HostEvent(HOST_MOVED, host);
105 - host.vlan(), 101 + }
106 - descr.location(), 102 +
107 - host.ipAddresses()); 103 + if (host.ipAddresses().contains(descr.ipAddress())) {
108 - event = new HostEvent(HOST_MOVED, updated);
109 -
110 - } else if (!(host.ipAddresses().equals(descr.ipAddresses()))) {
111 - updated = new DefaultHost(providerId, host.id(),
112 - host.mac(),
113 - host.vlan(),
114 - descr.location(),
115 - descr.ipAddresses());
116 - event = new HostEvent(HOST_UPDATED, updated);
117 - } else {
118 return null; 104 return null;
119 } 105 }
106 +
107 + Set<IpPrefix> addresses = new HashSet<>(host.ipAddresses());
108 + addresses.add(descr.ipAddress());
109 + StoredHost updated = new StoredHost(providerId, host.id(),
110 + host.mac(), host.vlan(),
111 + descr.location(), addresses);
112 + event = new HostEvent(HOST_UPDATED, updated);
120 synchronized (this) { 113 synchronized (this) {
121 hosts.put(host.id(), updated); 114 hosts.put(host.id(), updated);
122 locations.remove(host.location(), host); 115 locations.remove(host.location(), host);
...@@ -144,7 +137,7 @@ public class SimpleHostStore ...@@ -144,7 +137,7 @@ public class SimpleHostStore
144 137
145 @Override 138 @Override
146 public Iterable<Host> getHosts() { 139 public Iterable<Host> getHosts() {
147 - return Collections.unmodifiableSet(new HashSet<>(hosts.values())); 140 + return ImmutableSet.<Host>copyOf(hosts.values());
148 } 141 }
149 142
150 @Override 143 @Override
...@@ -274,4 +267,35 @@ public class SimpleHostStore ...@@ -274,4 +267,35 @@ public class SimpleHostStore
274 return addresses; 267 return addresses;
275 } 268 }
276 269
270 + // Auxiliary extension to allow location to mutate.
271 + private class StoredHost extends DefaultHost {
272 + private HostLocation location;
273 +
274 + /**
275 + * Creates an end-station host using the supplied information.
276 + *
277 + * @param providerId provider identity
278 + * @param id host identifier
279 + * @param mac host MAC address
280 + * @param vlan host VLAN identifier
281 + * @param location host location
282 + * @param ips host IP addresses
283 + * @param annotations optional key/value annotations
284 + */
285 + public StoredHost(ProviderId providerId, HostId id,
286 + MacAddress mac, VlanId vlan, HostLocation location,
287 + Set<IpPrefix> ips, Annotations... annotations) {
288 + super(providerId, id, mac, vlan, location, ips, annotations);
289 + this.location = location;
290 + }
291 +
292 + void setLocation(HostLocation location) {
293 + this.location = location;
294 + }
295 +
296 + @Override
297 + public HostLocation location() {
298 + return location;
299 + }
300 + }
277 } 301 }
......
...@@ -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
......
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
30 <groupId>org.projectfloodlight</groupId> 30 <groupId>org.projectfloodlight</groupId>
31 <artifactId>openflowj</artifactId> 31 <artifactId>openflowj</artifactId>
32 <!-- FIXME once experimenter gets merged to upstream --> 32 <!-- FIXME once experimenter gets merged to upstream -->
33 - <version>0.3.8-optical_experimenter</version> 33 + <version>0.3.8-optical_experimenter2</version>
34 </dependency> 34 </dependency>
35 <dependency> 35 <dependency>
36 <groupId>io.netty</groupId> 36 <groupId>io.netty</groupId>
......
1 package org.onlab.onos.openflow.controller; 1 package org.onlab.onos.openflow.controller;
2 2
3 -import static org.slf4j.LoggerFactory.getLogger;
4 -
5 -import java.util.Collections;
6 -import java.util.concurrent.atomic.AtomicBoolean;
7 -
8 import org.onlab.packet.Ethernet; 3 import org.onlab.packet.Ethernet;
9 import org.projectfloodlight.openflow.protocol.OFPacketIn; 4 import org.projectfloodlight.openflow.protocol.OFPacketIn;
10 import org.projectfloodlight.openflow.protocol.OFPacketOut; 5 import org.projectfloodlight.openflow.protocol.OFPacketOut;
...@@ -13,11 +8,11 @@ import org.projectfloodlight.openflow.protocol.action.OFActionOutput; ...@@ -13,11 +8,11 @@ import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
13 import org.projectfloodlight.openflow.protocol.match.MatchField; 8 import org.projectfloodlight.openflow.protocol.match.MatchField;
14 import org.projectfloodlight.openflow.types.OFBufferId; 9 import org.projectfloodlight.openflow.types.OFBufferId;
15 import org.projectfloodlight.openflow.types.OFPort; 10 import org.projectfloodlight.openflow.types.OFPort;
16 -import org.slf4j.Logger;
17 11
18 -public final class DefaultOpenFlowPacketContext implements OpenFlowPacketContext { 12 +import java.util.Collections;
13 +import java.util.concurrent.atomic.AtomicBoolean;
19 14
20 - private final Logger log = getLogger(getClass()); 15 +public final class DefaultOpenFlowPacketContext implements OpenFlowPacketContext {
21 16
22 private final AtomicBoolean free = new AtomicBoolean(true); 17 private final AtomicBoolean free = new AtomicBoolean(true);
23 private final AtomicBoolean isBuilt = new AtomicBoolean(false); 18 private final AtomicBoolean isBuilt = new AtomicBoolean(false);
...@@ -82,7 +77,7 @@ public final class DefaultOpenFlowPacketContext implements OpenFlowPacketContext ...@@ -82,7 +77,7 @@ public final class DefaultOpenFlowPacketContext implements OpenFlowPacketContext
82 } 77 }
83 78
84 public static OpenFlowPacketContext packetContextFromPacketIn(OpenFlowSwitch s, 79 public static OpenFlowPacketContext packetContextFromPacketIn(OpenFlowSwitch s,
85 - OFPacketIn pkt) { 80 + OFPacketIn pkt) {
86 return new DefaultOpenFlowPacketContext(s, pkt); 81 return new DefaultOpenFlowPacketContext(s, pkt);
87 } 82 }
88 83
......
...@@ -157,9 +157,7 @@ public class Controller { ...@@ -157,9 +157,7 @@ public class Controller {
157 } 157 }
158 log.debug("OpenFlow port set to {}", this.openFlowPort); 158 log.debug("OpenFlow port set to {}", this.openFlowPort);
159 String threads = configParams.get("workerthreads"); 159 String threads = configParams.get("workerthreads");
160 - if (threads != null) { 160 + this.workerThreads = threads != null ? Integer.parseInt(threads) : 16;
161 - this.workerThreads = Integer.parseInt(threads);
162 - }
163 log.debug("Number of worker threads set to {}", this.workerThreads); 161 log.debug("Number of worker threads set to {}", this.workerThreads);
164 } 162 }
165 163
......
...@@ -981,13 +981,13 @@ class OFChannelHandler extends IdleStateAwareChannelHandler { ...@@ -981,13 +981,13 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
981 // switch was a duplicate-dpid, calling the method below would clear 981 // switch was a duplicate-dpid, calling the method below would clear
982 // all state for the original switch (with the same dpid), 982 // all state for the original switch (with the same dpid),
983 // which we obviously don't want. 983 // which we obviously don't want.
984 - log.info("{}:removal called"); 984 + log.info("{}:removal called", getSwitchInfoString());
985 sw.removeConnectedSwitch(); 985 sw.removeConnectedSwitch();
986 } else { 986 } else {
987 // A duplicate was disconnected on this ChannelHandler, 987 // A duplicate was disconnected on this ChannelHandler,
988 // this is the same switch reconnecting, but the original state was 988 // this is the same switch reconnecting, but the original state was
989 // not cleaned up - XXX check liveness of original ChannelHandler 989 // not cleaned up - XXX check liveness of original ChannelHandler
990 - log.info("{}:duplicate found"); 990 + log.info("{}:duplicate found", getSwitchInfoString());
991 duplicateDpidFound = Boolean.FALSE; 991 duplicateDpidFound = Boolean.FALSE;
992 } 992 }
993 } else { 993 } else {
......
...@@ -44,7 +44,6 @@ public class OpenFlowControllerImpl implements OpenFlowController { ...@@ -44,7 +44,6 @@ public class OpenFlowControllerImpl implements OpenFlowController {
44 private final ExecutorService executor = Executors.newFixedThreadPool(16, 44 private final ExecutorService executor = Executors.newFixedThreadPool(16,
45 namedThreads("of-event-%d")); 45 namedThreads("of-event-%d"));
46 46
47 -
48 protected ConcurrentHashMap<Dpid, OpenFlowSwitch> connectedSwitches = 47 protected ConcurrentHashMap<Dpid, OpenFlowSwitch> connectedSwitches =
49 new ConcurrentHashMap<Dpid, OpenFlowSwitch>(); 48 new ConcurrentHashMap<Dpid, OpenFlowSwitch>();
50 protected ConcurrentHashMap<Dpid, OpenFlowSwitch> activeMasterSwitches = 49 protected ConcurrentHashMap<Dpid, OpenFlowSwitch> activeMasterSwitches =
......
...@@ -57,6 +57,12 @@ public final class DriverManager implements OpenFlowSwitchDriverFactory { ...@@ -57,6 +57,12 @@ public final class DriverManager implements OpenFlowSwitchDriverFactory {
57 } 57 }
58 } 58 }
59 59
60 + String sw = desc.getSwDesc();
61 + if (sw.startsWith("LINC-OE")) {
62 + log.debug("Optical Emulator LINC-OE with DPID:{} found..", dpid);
63 + return new OFOpticalSwitchImplLINC13(dpid, desc);
64 + }
65 +
60 log.warn("DriverManager could not identify switch desc: {}. " 66 log.warn("DriverManager could not identify switch desc: {}. "
61 + "Assigning AbstractOpenFlowSwich", desc); 67 + "Assigning AbstractOpenFlowSwich", desc);
62 return new AbstractOpenFlowSwitch(dpid, desc) { 68 return new AbstractOpenFlowSwitch(dpid, desc) {
......
1 +package org.onlab.onos.openflow.drivers.impl;
2 +
3 +import org.onlab.onos.openflow.controller.driver.SwitchDriverSubHandshakeAlreadyStarted;
4 +import org.onlab.onos.openflow.controller.driver.SwitchDriverSubHandshakeCompleted;
5 +import org.onlab.onos.openflow.controller.driver.SwitchDriverSubHandshakeNotStarted;
6 +import org.onlab.onos.openflow.controller.Dpid;
7 +import org.onlab.onos.openflow.controller.driver.AbstractOpenFlowSwitch;
8 +import org.projectfloodlight.openflow.protocol.OFCircuitPortsReply;
9 +import org.projectfloodlight.openflow.protocol.OFCircuitPortsRequest;
10 +import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
11 +import org.projectfloodlight.openflow.protocol.OFErrorMsg;
12 +import org.projectfloodlight.openflow.protocol.OFMatchV3;
13 +import org.projectfloodlight.openflow.protocol.OFMessage;
14 +import org.projectfloodlight.openflow.protocol.OFOxmList;
15 +import org.projectfloodlight.openflow.protocol.OFPortDesc;
16 +import org.projectfloodlight.openflow.protocol.OFPortOptical;
17 +import org.projectfloodlight.openflow.protocol.action.OFAction;
18 +import org.projectfloodlight.openflow.protocol.action.OFActionCircuit;
19 +import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
20 +import org.projectfloodlight.openflow.protocol.oxm.OFOxmInPort;
21 +import org.projectfloodlight.openflow.protocol.oxm.OFOxmOchSigid;
22 +import org.projectfloodlight.openflow.protocol.oxm.OFOxmOchSigidBasic;
23 +import org.projectfloodlight.openflow.protocol.oxm.OFOxmOchSigtype;
24 +import org.projectfloodlight.openflow.protocol.oxm.OFOxmOchSigtypeBasic;
25 +import org.projectfloodlight.openflow.types.CircuitSignalID;
26 +import org.projectfloodlight.openflow.types.OFPort;
27 +import org.projectfloodlight.openflow.types.U8;
28 +import org.slf4j.Logger;
29 +import org.slf4j.LoggerFactory;
30 +
31 +import java.io.IOException;
32 +import java.util.ArrayList;
33 +import java.util.Collection;
34 +import java.util.Collections;
35 +import java.util.List;
36 +import java.util.concurrent.atomic.AtomicBoolean;
37 +
38 +/**
39 + * LINC-OE Optical Emulator switch class.
40 + */
41 +public class OFOpticalSwitchImplLINC13 extends AbstractOpenFlowSwitch {
42 +
43 + private final AtomicBoolean driverHandshakeComplete;
44 + private long barrierXidToWaitFor = -1;
45 +
46 + private final Logger log =
47 + LoggerFactory.getLogger(OFOpticalSwitchImplLINC13.class);
48 +
49 + OFOpticalSwitchImplLINC13(Dpid dpid, OFDescStatsReply desc) {
50 + super(dpid);
51 + //setAttribute("optical", "true");
52 + driverHandshakeComplete = new AtomicBoolean(false);
53 + setSwitchDescription(desc);
54 + }
55 +
56 + @Override
57 + public String toString() {
58 + return "OFOpticalSwitchImplLINC13 [" + ((channel != null)
59 + ? channel.getRemoteAddress() : "?")
60 + + " DPID[" + ((getStringId() != null) ? getStringId() : "?") + "]]";
61 + }
62 +
63 + @Override
64 + public void startDriverHandshake() {
65 + log.debug("Starting driver handshake for sw {}", getStringId());
66 + if (startDriverHandshakeCalled) {
67 + throw new SwitchDriverSubHandshakeAlreadyStarted();
68 + }
69 + startDriverHandshakeCalled = true;
70 + try {
71 + sendHandshakeOFExperimenterPortDescRequest();
72 + } catch (IOException e) {
73 + e.printStackTrace();
74 + }
75 + }
76 +
77 + @Override
78 + public boolean isDriverHandshakeComplete() {
79 + if (!startDriverHandshakeCalled) {
80 + throw new SwitchDriverSubHandshakeNotStarted();
81 + }
82 + return driverHandshakeComplete.get();
83 + }
84 +
85 + @Override
86 + public void processDriverHandshakeMessage(OFMessage m) {
87 + if (!startDriverHandshakeCalled) {
88 + throw new SwitchDriverSubHandshakeNotStarted();
89 + }
90 + if (driverHandshakeComplete.get()) {
91 + throw new SwitchDriverSubHandshakeCompleted(m);
92 + }
93 +
94 + switch (m.getType()) {
95 + case BARRIER_REPLY:
96 + if (m.getXid() == barrierXidToWaitFor) {
97 + log.debug("LINC-OE Received barrier response");
98 + }
99 + break;
100 + case ERROR:
101 + log.error("Switch {} Error {}", getStringId(), (OFErrorMsg) m);
102 + break;
103 + case FEATURES_REPLY:
104 + break;
105 + case FLOW_REMOVED:
106 + break;
107 + case GET_ASYNC_REPLY:
108 + break;
109 + case PACKET_IN:
110 + break;
111 + case PORT_STATUS:
112 + break;
113 + case QUEUE_GET_CONFIG_REPLY:
114 + break;
115 + case ROLE_REPLY:
116 + break;
117 + case STATS_REPLY:
118 + log.debug("LINC-OE : Received stats reply message {}", m);
119 + processHandshakeOFExperimenterPortDescRequest(
120 + (OFCircuitPortsReply) m);
121 + driverHandshakeComplete.set(true);
122 + /* try {
123 + testMA();
124 + } catch (IOException e) {
125 + e.printStackTrace();
126 + }*/
127 + break;
128 + default:
129 + log.debug("Received message {} during switch-driver " +
130 + "subhandshake " + "from switch {} ... " +
131 + "Ignoring message", m,
132 + getStringId());
133 +
134 + }
135 + }
136 +
137 +
138 + private void processHandshakeOFExperimenterPortDescRequest(
139 + OFCircuitPortsReply sr) {
140 + Collection<OFPortOptical> entries = sr.getEntries();
141 + List<OFPortDesc> ofPortDescList = new ArrayList<>(entries.size());
142 + for (OFPortOptical entry : entries) {
143 + ofPortDescList.add(factory().buildPortDesc().
144 + setPortNo(entry.getPortNo())
145 + .setConfig(entry.getConfig())
146 + .setState(entry.getState())
147 + .setHwAddr(entry.getHwAddr())
148 + .setName(entry.getName())
149 + .build());
150 + }
151 + setPortDescReply(factory().buildPortDescStatsReply().
152 + setEntries(ofPortDescList).build());
153 + }
154 +
155 +
156 + private void sendHandshakeOFExperimenterPortDescRequest() throws
157 + IOException {
158 + // send multi part message for port description for optical switches
159 + OFCircuitPortsRequest circuitPortsRequest = factory()
160 + .buildCircuitPortsRequest().setXid(getNextTransactionId())
161 + .build();
162 + log.debug("LINC-OE : Sending experimented circuit port stats " +
163 + "message " +
164 + "{}",
165 + circuitPortsRequest.toString());
166 + channel.write(Collections.singletonList(circuitPortsRequest));
167 + }
168 +
169 +
170 +
171 + //todo for testing
172 + public static final U8 SIGNAL_TYPE = U8.of((short) 1);
173 + private void testMA() throws IOException {
174 + log.debug("LINC OE *** Testing MA ");
175 + short lambda = 100;
176 + if (getId() == 0x0000ffffffffff02L) {
177 + final int inport = 10;
178 + final int outport = 20;
179 + //Circuit signal id
180 + CircuitSignalID sigID = getSignalID(lambda);
181 +
182 + OFOxmOchSigid fieldSigIDMatch = factory().oxms().ochSigid(sigID);
183 + OFOxmOchSigtype fieldSigType = factory()
184 + .oxms()
185 + .ochSigtype(SIGNAL_TYPE);
186 +
187 + OFOxmOchSigidBasic ofOxmOchSigidBasic =
188 + factory().oxms().ochSigidBasic(sigID);
189 +
190 + OFOxmOchSigtypeBasic ofOxmOchSigtypeBasic =
191 + factory().oxms().ochSigtypeBasic(SIGNAL_TYPE);
192 +
193 + //Match Port
194 + OFOxmInPort fieldPort = factory().oxms()
195 + .inPort(OFPort.of(inport));
196 + OFMatchV3 matchPort =
197 + factory()
198 + .buildMatchV3().
199 + setOxmList(OFOxmList.of(fieldPort,
200 + fieldSigType,
201 + fieldSigIDMatch)).build();
202 +
203 +
204 + // Set Action outport ,sigType and sigID
205 + List<OFAction> actionList = new ArrayList<>();
206 + OFAction actionOutPort =
207 + factory().actions().output(OFPort.of(outport),
208 + Short.MAX_VALUE);
209 +
210 + OFActionCircuit actionCircuit = factory()
211 + .actions()
212 + .circuit(ofOxmOchSigidBasic);
213 + OFActionCircuit setActionSigType = factory()
214 + .actions()
215 + .circuit(ofOxmOchSigtypeBasic);
216 +
217 + actionList.add(actionOutPort);
218 + actionList.add(setActionSigType);
219 + actionList.add(actionCircuit);
220 +
221 + OFInstruction instructionAction =
222 + factory().instructions().buildApplyActions()
223 + .setActions(actionList)
224 + .build();
225 + List<OFInstruction> instructions =
226 + Collections.singletonList(instructionAction);
227 +
228 + OFMessage opticalFlowEntry =
229 + factory().buildFlowAdd()
230 + .setMatch(matchPort)
231 + .setInstructions(instructions)
232 + .setXid(getNextTransactionId())
233 + .build();
234 + log.debug("Adding optical flow in sw {}", getStringId());
235 + List<OFMessage> msglist = new ArrayList<>(1);
236 + msglist.add(opticalFlowEntry);
237 + write(msglist);
238 + } else if (getId() == 0x0000ffffffffff03L) {
239 + final int inport = 21;
240 + final int outport = 22;
241 + //Circuit signal id
242 + CircuitSignalID sigID = getSignalID(lambda);
243 +
244 + OFOxmOchSigid fieldSigIDMatch = factory().oxms().ochSigid(sigID);
245 + OFOxmOchSigtype fieldSigType = factory()
246 + .oxms()
247 + .ochSigtype(SIGNAL_TYPE);
248 +
249 + OFOxmOchSigidBasic ofOxmOchSigidBasic =
250 + factory().oxms().ochSigidBasic(sigID);
251 +
252 + OFOxmOchSigtypeBasic ofOxmOchSigtypeBasic =
253 + factory().oxms().ochSigtypeBasic(SIGNAL_TYPE);
254 +
255 + //Match Port,SigType,SigID
256 + OFOxmInPort fieldPort = factory()
257 + .oxms()
258 + .inPort(OFPort.of(inport));
259 + OFMatchV3 matchPort = factory()
260 + .buildMatchV3()
261 + .setOxmList(OFOxmList.of(fieldPort,
262 + fieldSigType,
263 + fieldSigIDMatch))
264 + .build();
265 +
266 + // Set Action outport ,SigType, sigID
267 + List<OFAction> actionList = new ArrayList<>();
268 + OFAction actionOutPort =
269 + factory().actions().output(OFPort.of(outport),
270 + Short.MAX_VALUE);
271 +
272 + OFActionCircuit setActionSigType = factory()
273 + .actions()
274 + .circuit(ofOxmOchSigtypeBasic);
275 + OFActionCircuit actionCircuit = factory()
276 + .actions()
277 + .circuit(ofOxmOchSigidBasic);
278 +
279 +
280 + actionList.add(actionOutPort);
281 + actionList.add(setActionSigType);
282 + actionList.add(actionCircuit);
283 +
284 + OFInstruction instructionAction =
285 + factory().instructions().buildApplyActions()
286 + .setActions(actionList)
287 + .build();
288 + List<OFInstruction> instructions =
289 + Collections.singletonList(instructionAction);
290 +
291 + OFMessage opticalFlowEntry =
292 + factory().buildFlowAdd()
293 + .setMatch(matchPort)
294 + .setInstructions(instructions)
295 + .setXid(getNextTransactionId())
296 + .build();
297 + log.debug("Adding optical flow in sw {}", getStringId());
298 + List<OFMessage> msglist = new ArrayList<>(1);
299 + msglist.add(opticalFlowEntry);
300 + write(msglist);
301 +
302 + } else if (getId() == 0x0000ffffffffff04L) {
303 + final int inport = 23;
304 + final int outport = 11;
305 + //Circuit signal id
306 + CircuitSignalID sigID = getSignalID(lambda);
307 +
308 + OFOxmOchSigid fieldSigIDMatch = factory().oxms().ochSigid(sigID);
309 + OFOxmOchSigtype fieldSigType = factory()
310 + .oxms()
311 + .ochSigtype(SIGNAL_TYPE);
312 +
313 +
314 + //Match Port, sig type and sig id
315 + OFOxmInPort fieldPort = factory()
316 + .oxms()
317 + .inPort(OFPort.of(inport));
318 + OFMatchV3 matchPort =
319 + factory().buildMatchV3()
320 + .setOxmList(OFOxmList.of(fieldPort,
321 + fieldSigType,
322 + fieldSigIDMatch))
323 + .build();
324 +
325 + // Set Action outport
326 + List<OFAction> actionList = new ArrayList<>();
327 + OFAction actionOutPort =
328 + factory().actions().output(OFPort.of(outport),
329 + Short.MAX_VALUE);
330 +
331 + actionList.add(actionOutPort);
332 +
333 + OFInstruction instructionAction =
334 + factory().instructions().buildApplyActions()
335 + .setActions(actionList)
336 + .build();
337 + List<OFInstruction> instructions =
338 + Collections.singletonList(instructionAction);
339 +
340 + OFMessage opticalFlowEntry =
341 + factory().buildFlowAdd()
342 + .setMatch(matchPort)
343 + .setInstructions(instructions)
344 + .setXid(getNextTransactionId())
345 + .build();
346 + log.debug("Adding optical flow in sw {}", getStringId());
347 + List<OFMessage> msglist = new ArrayList<>(1);
348 + msglist.add(opticalFlowEntry);
349 + write(msglist);
350 + }
351 +
352 + }
353 +
354 + // Todo remove - for testing purpose only
355 + private static CircuitSignalID getSignalID(short lambda) {
356 + byte myGrid = 1;
357 + byte myCs = 2;
358 + short myCn = lambda;
359 + short mySw = 1;
360 +
361 + CircuitSignalID signalID = new CircuitSignalID(myGrid,
362 + myCs,
363 + myCn,
364 + mySw);
365 + return signalID;
366 + }
367 +
368 + @Override
369 + public void write(OFMessage msg) {
370 + this.channel.write(msg);
371 + }
372 +
373 + @Override
374 + public void write(List<OFMessage> msgs) {
375 + this.channel.write(msgs);
376 + }
377 +
378 + @Override
379 + public Boolean supportNxRole() {
380 + return false;
381 + }
382 +
383 +}
...@@ -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>
...@@ -493,7 +500,7 @@ ...@@ -493,7 +500,7 @@
493 <group> 500 <group>
494 <title>Core Subsystems</title> 501 <title>Core Subsystems</title>
495 <packages> 502 <packages>
496 - org.onlab.onos.cluster.impl:org.onlab.onos.net.device.impl:org.onlab.onos.net.link.impl:org.onlab.onos.net.host.impl:org.onlab.onos.net.topology.impl:org.onlab.onos.net.packet.impl:org.onlab.onos.net.flow.impl:org.onlab.onos.store.trivial.*:org.onlab.onos.net.*.impl:org.onlab.onos.event.impl:org.onlab.onos.store.*:org.onlab.onos.net.intent.impl 503 + org.onlab.onos.impl:org.onlab.onos.cluster.impl:org.onlab.onos.net.device.impl:org.onlab.onos.net.link.impl:org.onlab.onos.net.host.impl:org.onlab.onos.net.topology.impl:org.onlab.onos.net.packet.impl:org.onlab.onos.net.flow.impl:org.onlab.onos.store.trivial.*:org.onlab.onos.net.*.impl:org.onlab.onos.event.impl:org.onlab.onos.store.*:org.onlab.onos.net.intent.impl:org.onlab.onos.net.proxyarp.impl
497 </packages> 504 </packages>
498 </group> 505 </group>
499 <group> 506 <group>
...@@ -518,7 +525,7 @@ ...@@ -518,7 +525,7 @@
518 <group> 525 <group>
519 <title>Sample Applications</title> 526 <title>Sample Applications</title>
520 <packages> 527 <packages>
521 - org.onlab.onos.tvue:org.onlab.onos.fwd:org.onlab.onos.foo 528 + org.onlab.onos.tvue:org.onlab.onos.fwd:org.onlab.onos.ifwd:org.onlab.onos.mobility:org.onlab.onos.proxyarp:org.onlab.onos.foo
522 </packages> 529 </packages>
523 </group> 530 </group>
524 </groups> 531 </groups>
...@@ -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>
......
...@@ -27,6 +27,8 @@ import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModVlanPcp ...@@ -27,6 +27,8 @@ import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModVlanPcp
27 import org.onlab.onos.net.flow.instructions.L3ModificationInstruction; 27 import org.onlab.onos.net.flow.instructions.L3ModificationInstruction;
28 import org.onlab.onos.net.flow.instructions.L3ModificationInstruction.ModIPInstruction; 28 import org.onlab.onos.net.flow.instructions.L3ModificationInstruction.ModIPInstruction;
29 import org.projectfloodlight.openflow.protocol.OFFactory; 29 import org.projectfloodlight.openflow.protocol.OFFactory;
30 +import org.projectfloodlight.openflow.protocol.OFFlowAdd;
31 +import org.projectfloodlight.openflow.protocol.OFFlowDelete;
30 import org.projectfloodlight.openflow.protocol.OFFlowMod; 32 import org.projectfloodlight.openflow.protocol.OFFlowMod;
31 import org.projectfloodlight.openflow.protocol.OFFlowModFlags; 33 import org.projectfloodlight.openflow.protocol.OFFlowModFlags;
32 import org.projectfloodlight.openflow.protocol.action.OFAction; 34 import org.projectfloodlight.openflow.protocol.action.OFAction;
...@@ -68,12 +70,13 @@ public class FlowModBuilder { ...@@ -68,12 +70,13 @@ public class FlowModBuilder {
68 this.cookie = flowRule.id(); 70 this.cookie = flowRule.id();
69 } 71 }
70 72
71 - public OFFlowMod buildFlowAdd() { 73 + public OFFlowAdd buildFlowAdd() {
72 Match match = buildMatch(); 74 Match match = buildMatch();
73 List<OFAction> actions = buildActions(); 75 List<OFAction> actions = buildActions();
74 76
75 //TODO: what to do without bufferid? do we assume that there will be a pktout as well? 77 //TODO: what to do without bufferid? do we assume that there will be a pktout as well?
76 - OFFlowMod fm = factory.buildFlowAdd() 78 + OFFlowAdd fm = factory.buildFlowAdd()
79 + .setXid(cookie.value())
77 .setCookie(U64.of(cookie.value())) 80 .setCookie(U64.of(cookie.value()))
78 .setBufferId(OFBufferId.NO_BUFFER) 81 .setBufferId(OFBufferId.NO_BUFFER)
79 .setActions(actions) 82 .setActions(actions)
...@@ -92,6 +95,7 @@ public class FlowModBuilder { ...@@ -92,6 +95,7 @@ public class FlowModBuilder {
92 95
93 //TODO: what to do without bufferid? do we assume that there will be a pktout as well? 96 //TODO: what to do without bufferid? do we assume that there will be a pktout as well?
94 OFFlowMod fm = factory.buildFlowModify() 97 OFFlowMod fm = factory.buildFlowModify()
98 + .setXid(cookie.value())
95 .setCookie(U64.of(cookie.value())) 99 .setCookie(U64.of(cookie.value()))
96 .setBufferId(OFBufferId.NO_BUFFER) 100 .setBufferId(OFBufferId.NO_BUFFER)
97 .setActions(actions) 101 .setActions(actions)
...@@ -104,11 +108,12 @@ public class FlowModBuilder { ...@@ -104,11 +108,12 @@ public class FlowModBuilder {
104 108
105 } 109 }
106 110
107 - public OFFlowMod buildFlowDel() { 111 + public OFFlowDelete buildFlowDel() {
108 Match match = buildMatch(); 112 Match match = buildMatch();
109 List<OFAction> actions = buildActions(); 113 List<OFAction> actions = buildActions();
110 114
111 - OFFlowMod fm = factory.buildFlowDelete() 115 + OFFlowDelete fm = factory.buildFlowDelete()
116 + .setXid(cookie.value())
112 .setCookie(U64.of(cookie.value())) 117 .setCookie(U64.of(cookie.value()))
113 .setBufferId(OFBufferId.NO_BUFFER) 118 .setBufferId(OFBufferId.NO_BUFFER)
114 .setActions(actions) 119 .setActions(actions)
......
...@@ -2,6 +2,7 @@ package org.onlab.onos.provider.of.flow.impl; ...@@ -2,6 +2,7 @@ package org.onlab.onos.provider.of.flow.impl;
2 2
3 import static org.slf4j.LoggerFactory.getLogger; 3 import static org.slf4j.LoggerFactory.getLogger;
4 4
5 +import java.util.HashMap;
5 import java.util.HashSet; 6 import java.util.HashSet;
6 import java.util.List; 7 import java.util.List;
7 import java.util.Map; 8 import java.util.Map;
...@@ -21,9 +22,12 @@ import org.apache.felix.scr.annotations.Reference; ...@@ -21,9 +22,12 @@ import org.apache.felix.scr.annotations.Reference;
21 import org.apache.felix.scr.annotations.ReferenceCardinality; 22 import org.apache.felix.scr.annotations.ReferenceCardinality;
22 import org.onlab.onos.ApplicationId; 23 import org.onlab.onos.ApplicationId;
23 import org.onlab.onos.net.DeviceId; 24 import org.onlab.onos.net.DeviceId;
25 +import org.onlab.onos.net.flow.CompletedBatchOperation;
26 +import org.onlab.onos.net.flow.DefaultFlowEntry;
24 import org.onlab.onos.net.flow.FlowEntry; 27 import org.onlab.onos.net.flow.FlowEntry;
25 import org.onlab.onos.net.flow.FlowRule; 28 import org.onlab.onos.net.flow.FlowRule;
26 import org.onlab.onos.net.flow.FlowRuleBatchEntry; 29 import org.onlab.onos.net.flow.FlowRuleBatchEntry;
30 +import org.onlab.onos.net.flow.FlowRuleBatchEntry.FlowRuleOperation;
27 import org.onlab.onos.net.flow.FlowRuleProvider; 31 import org.onlab.onos.net.flow.FlowRuleProvider;
28 import org.onlab.onos.net.flow.FlowRuleProviderRegistry; 32 import org.onlab.onos.net.flow.FlowRuleProviderRegistry;
29 import org.onlab.onos.net.flow.FlowRuleProviderService; 33 import org.onlab.onos.net.flow.FlowRuleProviderService;
...@@ -40,6 +44,7 @@ import org.onlab.onos.openflow.controller.RoleState; ...@@ -40,6 +44,7 @@ import org.onlab.onos.openflow.controller.RoleState;
40 import org.projectfloodlight.openflow.protocol.OFActionType; 44 import org.projectfloodlight.openflow.protocol.OFActionType;
41 import org.projectfloodlight.openflow.protocol.OFBarrierRequest; 45 import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
42 import org.projectfloodlight.openflow.protocol.OFErrorMsg; 46 import org.projectfloodlight.openflow.protocol.OFErrorMsg;
47 +import org.projectfloodlight.openflow.protocol.OFFlowMod;
43 import org.projectfloodlight.openflow.protocol.OFFlowRemoved; 48 import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
44 import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry; 49 import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry;
45 import org.projectfloodlight.openflow.protocol.OFFlowStatsReply; 50 import org.projectfloodlight.openflow.protocol.OFFlowStatsReply;
...@@ -52,6 +57,11 @@ import org.projectfloodlight.openflow.protocol.OFStatsType; ...@@ -52,6 +57,11 @@ import org.projectfloodlight.openflow.protocol.OFStatsType;
52 import org.projectfloodlight.openflow.protocol.OFVersion; 57 import org.projectfloodlight.openflow.protocol.OFVersion;
53 import org.projectfloodlight.openflow.protocol.action.OFAction; 58 import org.projectfloodlight.openflow.protocol.action.OFAction;
54 import org.projectfloodlight.openflow.protocol.action.OFActionOutput; 59 import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
60 +import org.projectfloodlight.openflow.protocol.errormsg.OFBadActionErrorMsg;
61 +import org.projectfloodlight.openflow.protocol.errormsg.OFBadInstructionErrorMsg;
62 +import org.projectfloodlight.openflow.protocol.errormsg.OFBadMatchErrorMsg;
63 +import org.projectfloodlight.openflow.protocol.errormsg.OFBadRequestErrorMsg;
64 +import org.projectfloodlight.openflow.protocol.errormsg.OFFlowModFailedErrorMsg;
55 import org.projectfloodlight.openflow.protocol.instruction.OFInstruction; 65 import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
56 import org.projectfloodlight.openflow.protocol.instruction.OFInstructionApplyActions; 66 import org.projectfloodlight.openflow.protocol.instruction.OFInstructionApplyActions;
57 import org.projectfloodlight.openflow.types.OFPort; 67 import org.projectfloodlight.openflow.types.OFPort;
...@@ -70,6 +80,8 @@ import com.google.common.collect.Multimap; ...@@ -70,6 +80,8 @@ import com.google.common.collect.Multimap;
70 @Component(immediate = true) 80 @Component(immediate = true)
71 public class OpenFlowRuleProvider extends AbstractProvider implements FlowRuleProvider { 81 public class OpenFlowRuleProvider extends AbstractProvider implements FlowRuleProvider {
72 82
83 + enum BatchState { STARTED, FINISHED, CANCELLED };
84 +
73 private final Logger log = getLogger(getClass()); 85 private final Logger log = getLogger(getClass());
74 86
75 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 87 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
...@@ -88,6 +100,9 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr ...@@ -88,6 +100,9 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
88 private final Map<Long, InstallationFuture> pendingFutures = 100 private final Map<Long, InstallationFuture> pendingFutures =
89 new ConcurrentHashMap<Long, InstallationFuture>(); 101 new ConcurrentHashMap<Long, InstallationFuture>();
90 102
103 + private final Map<Long, InstallationFuture> pendingFMs =
104 + new ConcurrentHashMap<Long, InstallationFuture>();
105 +
91 /** 106 /**
92 * Creates an OpenFlow host provider. 107 * Creates an OpenFlow host provider.
93 */ 108 */
...@@ -143,9 +158,47 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr ...@@ -143,9 +158,47 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
143 removeFlowRule(flowRules); 158 removeFlowRule(flowRules);
144 } 159 }
145 160
161 + @Override
162 + public Future<CompletedBatchOperation> executeBatch(BatchOperation<FlowRuleBatchEntry> batch) {
163 + final Set<Dpid> sws = new HashSet<Dpid>();
164 + final Map<Long, FlowRuleBatchEntry> fmXids = new HashMap<Long, FlowRuleBatchEntry>();
165 + OFFlowMod mod = null;
166 + for (FlowRuleBatchEntry fbe : batch.getOperations()) {
167 + FlowRule flowRule = fbe.getTarget();
168 + OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId().uri()));
169 + sws.add(new Dpid(sw.getId()));
170 + FlowModBuilder builder = new FlowModBuilder(flowRule, sw.factory());
171 + switch (fbe.getOperator()) {
172 + case ADD:
173 + mod = builder.buildFlowAdd();
174 + break;
175 + case REMOVE:
176 + mod = builder.buildFlowDel();
177 + break;
178 + case MODIFY:
179 + mod = builder.buildFlowMod();
180 + break;
181 + default:
182 + log.error("Unsupported batch operation {}", fbe.getOperator());
183 + }
184 + if (mod != null) {
185 + sw.sendMsg(mod);
186 + fmXids.put(mod.getXid(), fbe);
187 + } else {
188 + log.error("Conversion of flowrule {} failed.", flowRule);
189 + }
190 +
191 + }
192 + InstallationFuture installation = new InstallationFuture(sws, fmXids);
193 + for (Long xid : fmXids.keySet()) {
194 + pendingFMs.put(xid, installation);
195 + }
196 + pendingFutures.put(U32.f(batch.hashCode()), installation);
197 + installation.verify(batch.hashCode());
198 + return installation;
199 + }
200 +
146 201
147 - //TODO: InternalFlowRuleProvider listening to stats and error and flowremoved.
148 - // possibly barriers as well. May not be internal at all...
149 private class InternalFlowProvider 202 private class InternalFlowProvider
150 implements OpenFlowSwitchListener, OpenFlowEventListener { 203 implements OpenFlowSwitchListener, OpenFlowEventListener {
151 204
...@@ -175,7 +228,6 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr ...@@ -175,7 +228,6 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
175 InstallationFuture future = null; 228 InstallationFuture future = null;
176 switch (msg.getType()) { 229 switch (msg.getType()) {
177 case FLOW_REMOVED: 230 case FLOW_REMOVED:
178 - //TODO: make this better
179 OFFlowRemoved removed = (OFFlowRemoved) msg; 231 OFFlowRemoved removed = (OFFlowRemoved) msg;
180 232
181 FlowEntry fr = new FlowEntryBuilder(dpid, removed).build(); 233 FlowEntry fr = new FlowEntryBuilder(dpid, removed).build();
...@@ -191,7 +243,7 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr ...@@ -191,7 +243,7 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
191 } 243 }
192 break; 244 break;
193 case ERROR: 245 case ERROR:
194 - future = pendingFutures.get(msg.getXid()); 246 + future = pendingFMs.get(msg.getXid());
195 if (future != null) { 247 if (future != null) {
196 future.fail((OFErrorMsg) msg, dpid); 248 future.fail((OFErrorMsg) msg, dpid);
197 } 249 }
...@@ -203,10 +255,7 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr ...@@ -203,10 +255,7 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
203 } 255 }
204 256
205 @Override 257 @Override
206 - public void roleAssertFailed(Dpid dpid, RoleState role) { 258 + public void roleAssertFailed(Dpid dpid, RoleState role) {}
207 - // TODO Auto-generated method stub
208 -
209 - }
210 259
211 private synchronized void pushFlowMetrics(Dpid dpid, OFStatsReply stats) { 260 private synchronized void pushFlowMetrics(Dpid dpid, OFStatsReply stats) {
212 if (stats.getStatsType() != OFStatsType.FLOW) { 261 if (stats.getStatsType() != OFStatsType.FLOW) {
...@@ -230,7 +279,6 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr ...@@ -230,7 +279,6 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
230 } 279 }
231 280
232 private boolean tableMissRule(Dpid dpid, OFFlowStatsEntry reply) { 281 private boolean tableMissRule(Dpid dpid, OFFlowStatsEntry reply) {
233 - // TODO NEED TO FIND A BETTER WAY TO AVOID DOING THIS
234 if (reply.getVersion().equals(OFVersion.OF_10) || 282 if (reply.getVersion().equals(OFVersion.OF_10) ||
235 reply.getMatch().getMatchFields().iterator().hasNext()) { 283 reply.getMatch().getMatchFields().iterator().hasNext()) {
236 return false; 284 return false;
...@@ -251,104 +299,91 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr ...@@ -251,104 +299,91 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
251 } 299 }
252 return false; 300 return false;
253 } 301 }
254 -
255 - }
256 -
257 -
258 - @Override
259 - public Future<Void> executeBatch(BatchOperation<FlowRuleBatchEntry> batch) {
260 - final Set<Dpid> sws = new HashSet<Dpid>();
261 -
262 - for (FlowRuleBatchEntry fbe : batch.getOperations()) {
263 - FlowRule flowRule = fbe.getTarget();
264 - OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId().uri()));
265 - sws.add(new Dpid(sw.getId()));
266 - switch (fbe.getOperator()) {
267 - case ADD:
268 - //TODO: Track XID for each flowmod
269 - sw.sendMsg(new FlowModBuilder(flowRule, sw.factory()).buildFlowAdd());
270 - break;
271 - case REMOVE:
272 - //TODO: Track XID for each flowmod
273 - sw.sendMsg(new FlowModBuilder(flowRule, sw.factory()).buildFlowDel());
274 - break;
275 - case MODIFY:
276 - //TODO: Track XID for each flowmod
277 - sw.sendMsg(new FlowModBuilder(flowRule, sw.factory()).buildFlowMod());
278 - break;
279 - default:
280 - log.error("Unsupported batch operation {}", fbe.getOperator());
281 - }
282 - }
283 - InstallationFuture installation = new InstallationFuture(sws);
284 - pendingFutures.put(U32.f(batch.hashCode()), installation);
285 - installation.verify(batch.hashCode());
286 - return installation;
287 } 302 }
288 303
289 - private class InstallationFuture implements Future<Void> { 304 + private class InstallationFuture implements Future<CompletedBatchOperation> {
290 305
291 private final Set<Dpid> sws; 306 private final Set<Dpid> sws;
292 private final AtomicBoolean ok = new AtomicBoolean(true); 307 private final AtomicBoolean ok = new AtomicBoolean(true);
308 + private final Map<Long, FlowRuleBatchEntry> fms;
309 +
293 private final List<FlowEntry> offendingFlowMods = Lists.newLinkedList(); 310 private final List<FlowEntry> offendingFlowMods = Lists.newLinkedList();
294 311
295 private final CountDownLatch countDownLatch; 312 private final CountDownLatch countDownLatch;
313 + private Integer pendingXid;
314 + private BatchState state;
296 315
297 - public InstallationFuture(Set<Dpid> sws) { 316 + public InstallationFuture(Set<Dpid> sws, Map<Long, FlowRuleBatchEntry> fmXids) {
317 + this.state = BatchState.STARTED;
298 this.sws = sws; 318 this.sws = sws;
319 + this.fms = fmXids;
299 countDownLatch = new CountDownLatch(sws.size()); 320 countDownLatch = new CountDownLatch(sws.size());
300 } 321 }
301 322
302 public void fail(OFErrorMsg msg, Dpid dpid) { 323 public void fail(OFErrorMsg msg, Dpid dpid) {
303 ok.set(false); 324 ok.set(false);
304 - //TODO add reason to flowentry 325 + FlowEntry fe = null;
326 + FlowRuleBatchEntry fbe = fms.get(msg.getXid());
327 + FlowRule offending = fbe.getTarget();
305 //TODO handle specific error msgs 328 //TODO handle specific error msgs
306 - //offendingFlowMods.add(new FlowEntryBuilder(dpid, msg.));
307 switch (msg.getErrType()) { 329 switch (msg.getErrType()) {
308 case BAD_ACTION: 330 case BAD_ACTION:
331 + OFBadActionErrorMsg bad = (OFBadActionErrorMsg) msg;
332 + fe = new DefaultFlowEntry(offending, bad.getErrType().ordinal(),
333 + bad.getCode().ordinal());
309 break; 334 break;
310 case BAD_INSTRUCTION: 335 case BAD_INSTRUCTION:
336 + OFBadInstructionErrorMsg badins = (OFBadInstructionErrorMsg) msg;
337 + fe = new DefaultFlowEntry(offending, badins.getErrType().ordinal(),
338 + badins.getCode().ordinal());
311 break; 339 break;
312 case BAD_MATCH: 340 case BAD_MATCH:
341 + OFBadMatchErrorMsg badMatch = (OFBadMatchErrorMsg) msg;
342 + fe = new DefaultFlowEntry(offending, badMatch.getErrType().ordinal(),
343 + badMatch.getCode().ordinal());
313 break; 344 break;
314 case BAD_REQUEST: 345 case BAD_REQUEST:
315 - break; 346 + OFBadRequestErrorMsg badReq = (OFBadRequestErrorMsg) msg;
316 - case EXPERIMENTER: 347 + fe = new DefaultFlowEntry(offending, badReq.getErrType().ordinal(),
348 + badReq.getCode().ordinal());
317 break; 349 break;
318 case FLOW_MOD_FAILED: 350 case FLOW_MOD_FAILED:
351 + OFFlowModFailedErrorMsg fmFail = (OFFlowModFailedErrorMsg) msg;
352 + fe = new DefaultFlowEntry(offending, fmFail.getErrType().ordinal(),
353 + fmFail.getCode().ordinal());
319 break; 354 break;
355 + case EXPERIMENTER:
320 case GROUP_MOD_FAILED: 356 case GROUP_MOD_FAILED:
321 - break;
322 case HELLO_FAILED: 357 case HELLO_FAILED:
323 - break;
324 case METER_MOD_FAILED: 358 case METER_MOD_FAILED:
325 - break;
326 case PORT_MOD_FAILED: 359 case PORT_MOD_FAILED:
327 - break;
328 case QUEUE_OP_FAILED: 360 case QUEUE_OP_FAILED:
329 - break;
330 case ROLE_REQUEST_FAILED: 361 case ROLE_REQUEST_FAILED:
331 - break;
332 case SWITCH_CONFIG_FAILED: 362 case SWITCH_CONFIG_FAILED:
333 - break;
334 case TABLE_FEATURES_FAILED: 363 case TABLE_FEATURES_FAILED:
335 - break;
336 case TABLE_MOD_FAILED: 364 case TABLE_MOD_FAILED:
365 + fe = new DefaultFlowEntry(offending, msg.getErrType().ordinal(), 0);
337 break; 366 break;
338 default: 367 default:
339 - break; 368 + log.error("Unknown error type {}", msg.getErrType());
340 369
341 } 370 }
371 + offendingFlowMods.add(fe);
342 372
343 } 373 }
344 374
375 +
345 public void satisfyRequirement(Dpid dpid) { 376 public void satisfyRequirement(Dpid dpid) {
346 log.warn("Satisfaction from switch {}", dpid); 377 log.warn("Satisfaction from switch {}", dpid);
347 sws.remove(dpid); 378 sws.remove(dpid);
348 countDownLatch.countDown(); 379 countDownLatch.countDown();
380 + cleanUp();
381 +
349 } 382 }
350 383
384 +
351 public void verify(Integer id) { 385 public void verify(Integer id) {
386 + pendingXid = id;
352 for (Dpid dpid : sws) { 387 for (Dpid dpid : sws) {
353 OpenFlowSwitch sw = controller.getSwitch(dpid); 388 OpenFlowSwitch sw = controller.getSwitch(dpid);
354 OFBarrierRequest.Builder builder = sw.factory() 389 OFBarrierRequest.Builder builder = sw.factory()
...@@ -356,41 +391,59 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr ...@@ -356,41 +391,59 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
356 .setXid(id); 391 .setXid(id);
357 sw.sendMsg(builder.build()); 392 sw.sendMsg(builder.build());
358 } 393 }
359 -
360 -
361 } 394 }
362 395
363 @Override 396 @Override
364 public boolean cancel(boolean mayInterruptIfRunning) { 397 public boolean cancel(boolean mayInterruptIfRunning) {
365 - // TODO Auto-generated method stub 398 + this.state = BatchState.CANCELLED;
366 - return false; 399 + cleanUp();
400 + for (FlowRuleBatchEntry fbe : fms.values()) {
401 + if (fbe.getOperator() == FlowRuleOperation.ADD ||
402 + fbe.getOperator() == FlowRuleOperation.MODIFY) {
403 + removeFlowRule(fbe.getTarget());
404 + } else if (fbe.getOperator() == FlowRuleOperation.REMOVE) {
405 + applyRule(fbe.getTarget());
406 + }
407 +
408 + }
409 + return isCancelled();
367 } 410 }
368 411
369 @Override 412 @Override
370 public boolean isCancelled() { 413 public boolean isCancelled() {
371 - // TODO Auto-generated method stub 414 + return this.state == BatchState.CANCELLED;
372 - return false;
373 } 415 }
374 416
375 @Override 417 @Override
376 public boolean isDone() { 418 public boolean isDone() {
377 - return sws.isEmpty(); 419 + return this.state == BatchState.FINISHED;
378 } 420 }
379 421
380 @Override 422 @Override
381 - public Void get() throws InterruptedException, ExecutionException { 423 + public CompletedBatchOperation get() throws InterruptedException, ExecutionException {
382 countDownLatch.await(); 424 countDownLatch.await();
383 - //return offendingFlowMods; 425 + this.state = BatchState.FINISHED;
384 - return null; 426 + return new CompletedBatchOperation(ok.get(), offendingFlowMods);
385 } 427 }
386 428
387 @Override 429 @Override
388 - public Void get(long timeout, TimeUnit unit) 430 + public CompletedBatchOperation get(long timeout, TimeUnit unit)
389 throws InterruptedException, ExecutionException, 431 throws InterruptedException, ExecutionException,
390 TimeoutException { 432 TimeoutException {
391 - countDownLatch.await(timeout, unit); 433 + if (countDownLatch.await(timeout, unit)) {
392 - //return offendingFlowMods; 434 + this.state = BatchState.FINISHED;
393 - return null; 435 + return new CompletedBatchOperation(ok.get(), offendingFlowMods);
436 + }
437 + throw new TimeoutException();
438 + }
439 +
440 + private void cleanUp() {
441 + if (sws.isEmpty()) {
442 + pendingFutures.remove(pendingXid);
443 + for (Long xid : fms.keySet()) {
444 + pendingFMs.remove(xid);
445 + }
446 + }
394 } 447 }
395 448
396 } 449 }
......
1 package org.onlab.onos.provider.of.host.impl; 1 package org.onlab.onos.provider.of.host.impl;
2 2
3 -import static com.google.common.collect.Sets.newHashSet;
4 -import static org.onlab.onos.net.DeviceId.deviceId;
5 -import static org.onlab.onos.net.PortNumber.portNumber;
6 -import static org.slf4j.LoggerFactory.getLogger;
7 -
8 -import java.util.Set;
9 -
10 import org.apache.felix.scr.annotations.Activate; 3 import org.apache.felix.scr.annotations.Activate;
11 import org.apache.felix.scr.annotations.Component; 4 import org.apache.felix.scr.annotations.Component;
12 import org.apache.felix.scr.annotations.Deactivate; 5 import org.apache.felix.scr.annotations.Deactivate;
...@@ -36,6 +29,10 @@ import org.onlab.packet.IpPrefix; ...@@ -36,6 +29,10 @@ import org.onlab.packet.IpPrefix;
36 import org.onlab.packet.VlanId; 29 import org.onlab.packet.VlanId;
37 import org.slf4j.Logger; 30 import org.slf4j.Logger;
38 31
32 +import static org.onlab.onos.net.DeviceId.deviceId;
33 +import static org.onlab.onos.net.PortNumber.portNumber;
34 +import static org.slf4j.LoggerFactory.getLogger;
35 +
39 /** 36 /**
40 * Provider which uses an OpenFlow controller to detect network 37 * Provider which uses an OpenFlow controller to detect network
41 * end-station hosts. 38 * end-station hosts.
...@@ -58,6 +55,8 @@ public class OpenFlowHostProvider extends AbstractProvider implements HostProvid ...@@ -58,6 +55,8 @@ public class OpenFlowHostProvider extends AbstractProvider implements HostProvid
58 55
59 private final InternalHostProvider listener = new InternalHostProvider(); 56 private final InternalHostProvider listener = new InternalHostProvider();
60 57
58 + private boolean ipLearn = true;
59 +
61 /** 60 /**
62 * Creates an OpenFlow host provider. 61 * Creates an OpenFlow host provider.
63 */ 62 */
...@@ -69,7 +68,6 @@ public class OpenFlowHostProvider extends AbstractProvider implements HostProvid ...@@ -69,7 +68,6 @@ public class OpenFlowHostProvider extends AbstractProvider implements HostProvid
69 public void activate() { 68 public void activate() {
70 providerService = providerRegistry.register(this); 69 providerService = providerRegistry.register(this);
71 controller.addPacketListener(10, listener); 70 controller.addPacketListener(10, listener);
72 -
73 log.info("Started"); 71 log.info("Started");
74 } 72 }
75 73
...@@ -78,7 +76,6 @@ public class OpenFlowHostProvider extends AbstractProvider implements HostProvid ...@@ -78,7 +76,6 @@ public class OpenFlowHostProvider extends AbstractProvider implements HostProvid
78 providerRegistry.unregister(this); 76 providerRegistry.unregister(this);
79 controller.removePacketListener(listener); 77 controller.removePacketListener(listener);
80 providerService = null; 78 providerService = null;
81 -
82 log.info("Stopped"); 79 log.info("Stopped");
83 } 80 }
84 81
...@@ -95,33 +92,33 @@ public class OpenFlowHostProvider extends AbstractProvider implements HostProvid ...@@ -95,33 +92,33 @@ public class OpenFlowHostProvider extends AbstractProvider implements HostProvid
95 92
96 VlanId vlan = VlanId.vlanId(eth.getVlanID()); 93 VlanId vlan = VlanId.vlanId(eth.getVlanID());
97 ConnectPoint heardOn = new ConnectPoint(deviceId(Dpid.uri(pktCtx.dpid())), 94 ConnectPoint heardOn = new ConnectPoint(deviceId(Dpid.uri(pktCtx.dpid())),
98 - portNumber(pktCtx.inPort())); 95 + portNumber(pktCtx.inPort()));
99 96
100 - // If this is not an edge port, bail out. 97 + // If this is not an edge port, bail out.
101 Topology topology = topologyService.currentTopology(); 98 Topology topology = topologyService.currentTopology();
102 if (topologyService.isInfrastructure(topology, heardOn)) { 99 if (topologyService.isInfrastructure(topology, heardOn)) {
103 return; 100 return;
104 } 101 }
105 102
106 HostLocation hloc = new HostLocation(deviceId(Dpid.uri(pktCtx.dpid())), 103 HostLocation hloc = new HostLocation(deviceId(Dpid.uri(pktCtx.dpid())),
107 - portNumber(pktCtx.inPort()), 104 + portNumber(pktCtx.inPort()),
108 - System.currentTimeMillis()); 105 + System.currentTimeMillis());
106 +
109 HostId hid = HostId.hostId(eth.getSourceMAC(), vlan); 107 HostId hid = HostId.hostId(eth.getSourceMAC(), vlan);
108 +
110 // Potentially a new or moved host 109 // Potentially a new or moved host
111 if (eth.getEtherType() == Ethernet.TYPE_ARP) { 110 if (eth.getEtherType() == Ethernet.TYPE_ARP) {
112 -
113 -
114 ARP arp = (ARP) eth.getPayload(); 111 ARP arp = (ARP) eth.getPayload();
115 - Set<IpPrefix> ips = newHashSet(IpPrefix.valueOf(arp.getSenderProtocolAddress())); 112 + IpPrefix ip = IpPrefix.valueOf(arp.getSenderProtocolAddress());
116 HostDescription hdescr = 113 HostDescription hdescr =
117 - new DefaultHostDescription(eth.getSourceMAC(), vlan, hloc, ips); 114 + new DefaultHostDescription(eth.getSourceMAC(), vlan, hloc, ip);
118 providerService.hostDetected(hid, hdescr); 115 providerService.hostDetected(hid, hdescr);
119 116
120 - } else if (eth.getEtherType() == Ethernet.TYPE_IPV4) { 117 + } else if (ipLearn && eth.getEtherType() == Ethernet.TYPE_IPV4) {
121 - IPv4 ip = (IPv4) eth.getPayload(); 118 + IPv4 pip = (IPv4) eth.getPayload();
122 - Set<IpPrefix> ips = newHashSet(IpPrefix.valueOf(ip.getSourceAddress())); 119 + IpPrefix ip = IpPrefix.valueOf(pip.getSourceAddress());
123 HostDescription hdescr = 120 HostDescription hdescr =
124 - new DefaultHostDescription(eth.getSourceMAC(), vlan, hloc, ips); 121 + new DefaultHostDescription(eth.getSourceMAC(), vlan, hloc, ip);
125 providerService.hostDetected(hid, hdescr); 122 providerService.hostDetected(hid, hdescr);
126 123
127 } 124 }
......
1 package org.onlab.onos.provider.of.packet.impl; 1 package org.onlab.onos.provider.of.packet.impl;
2 2
3 -import static org.slf4j.LoggerFactory.getLogger;
4 -
5 -import java.util.List;
6 -
7 import org.onlab.onos.net.PortNumber; 3 import org.onlab.onos.net.PortNumber;
8 import org.onlab.onos.net.flow.instructions.Instruction; 4 import org.onlab.onos.net.flow.instructions.Instruction;
9 import org.onlab.onos.net.flow.instructions.Instruction.Type; 5 import org.onlab.onos.net.flow.instructions.Instruction.Type;
...@@ -14,16 +10,16 @@ import org.onlab.onos.net.packet.OutboundPacket; ...@@ -14,16 +10,16 @@ import org.onlab.onos.net.packet.OutboundPacket;
14 import org.onlab.onos.openflow.controller.OpenFlowPacketContext; 10 import org.onlab.onos.openflow.controller.OpenFlowPacketContext;
15 import org.onlab.packet.Ethernet; 11 import org.onlab.packet.Ethernet;
16 import org.projectfloodlight.openflow.types.OFPort; 12 import org.projectfloodlight.openflow.types.OFPort;
17 -import org.slf4j.Logger;
18 13
19 -public class OpenFlowCorePacketContext extends DefaultPacketContext { 14 +import java.util.List;
20 15
21 - private final Logger log = getLogger(getClass()); 16 +public class OpenFlowCorePacketContext extends DefaultPacketContext {
22 17
23 private final OpenFlowPacketContext ofPktCtx; 18 private final OpenFlowPacketContext ofPktCtx;
24 19
25 protected OpenFlowCorePacketContext(long time, InboundPacket inPkt, 20 protected OpenFlowCorePacketContext(long time, InboundPacket inPkt,
26 - OutboundPacket outPkt, boolean block, OpenFlowPacketContext ofPktCtx) { 21 + OutboundPacket outPkt, boolean block,
22 + OpenFlowPacketContext ofPktCtx) {
27 super(time, inPkt, outPkt, block); 23 super(time, inPkt, outPkt, block);
28 this.ofPktCtx = ofPktCtx; 24 this.ofPktCtx = ofPktCtx;
29 } 25 }
...@@ -36,9 +32,8 @@ public class OpenFlowCorePacketContext extends DefaultPacketContext { ...@@ -36,9 +32,8 @@ public class OpenFlowCorePacketContext extends DefaultPacketContext {
36 } else { 32 } else {
37 Ethernet eth = new Ethernet(); 33 Ethernet eth = new Ethernet();
38 eth.deserialize(outPacket().data().array(), 0, 34 eth.deserialize(outPacket().data().array(), 0,
39 - outPacket().data().array().length); 35 + outPacket().data().array().length);
40 sendPacket(eth); 36 sendPacket(eth);
41 -
42 } 37 }
43 38
44 } 39 }
...@@ -61,6 +56,7 @@ public class OpenFlowCorePacketContext extends DefaultPacketContext { ...@@ -61,6 +56,7 @@ public class OpenFlowCorePacketContext extends DefaultPacketContext {
61 } 56 }
62 ofPktCtx.send(); 57 ofPktCtx.send();
63 } 58 }
59 +
64 private OFPort buildPort(PortNumber port) { 60 private OFPort buildPort(PortNumber port) {
65 return OFPort.of((int) port.toLong()); 61 return OFPort.of((int) port.toLong());
66 } 62 }
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
6 export ONOS_ROOT=${ONOS_ROOT:-~/onos-next} 6 export ONOS_ROOT=${ONOS_ROOT:-~/onos-next}
7 7
8 # Setup some environmental context for developers 8 # Setup some environmental context for developers
9 -export JAVA_HOME=$(/usr/libexec/java_home -v 1.7) 9 +export JAVA_HOME=${JAVA_HOME:-$(/usr/libexec/java_home -v 1.7)}
10 export MAVEN=${MAVEN:-~/Applications/apache-maven-3.2.2} 10 export MAVEN=${MAVEN:-~/Applications/apache-maven-3.2.2}
11 export KARAF=${KARAF:-~/Applications/apache-karaf-3.0.1} 11 export KARAF=${KARAF:-~/Applications/apache-karaf-3.0.1}
12 export KARAF_LOG=$KARAF/data/log/karaf.log 12 export KARAF_LOG=$KARAF/data/log/karaf.log
...@@ -33,6 +33,7 @@ alias obs='onos-build-selective' ...@@ -33,6 +33,7 @@ alias obs='onos-build-selective'
33 alias op='onos-package' 33 alias op='onos-package'
34 alias ot='onos-test' 34 alias ot='onos-test'
35 alias ol='onos-log' 35 alias ol='onos-log'
36 +alias ow='onos-watch'
36 alias go='ob && ot && onos -w' 37 alias go='ob && ot && onos -w'
37 alias pub='onos-push-update-bundle' 38 alias pub='onos-push-update-bundle'
38 39
......
1 +#!/bin/bash
1 #------------------------------------------------------------------------------ 2 #------------------------------------------------------------------------------
2 -# Echoes project-level directory if a Java file within is newer than its 3 +# Echoes project-level directory if a Java file within is newer than the
3 -# class file counterpart 4 +# target directory.
4 #------------------------------------------------------------------------------ 5 #------------------------------------------------------------------------------
5 6
6 javaFile=${1#*\/src\/*\/java/} 7 javaFile=${1#*\/src\/*\/java/}
...@@ -10,9 +11,7 @@ basename=${1/*\//} ...@@ -10,9 +11,7 @@ basename=${1/*\//}
10 11
11 src=${1/$javaFile/} 12 src=${1/$javaFile/}
12 project=${src/src*/} 13 project=${src/src*/}
13 -classFile=${javaFile/.java/.class} 14 +target=$project/target
14 15
15 -[ ${project}target/classes/$classFile -nt ${src}$javaFile -o \ 16 +[ $target -nt ${src}$javaFile ] || echo ${src/src*/}
16 - ${project}target/test-classes/$classFile -nt ${src}$javaFile ] \
17 - || echo ${src/src*/}
18 17
......
1 +#!/bin/bash
2 +
3 +kpid=$(ps -ef | grep karaf.main.Main | grep -v grep | cut -c10-15 | tr -d ' ')
4 +
5 +[ -z "$kpid" ] && echo "No ONOS!" && exit 1
6 +
7 +/opt/jprofiler8/bin/jpenable --gui --port=8849 --pid=$kpid
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
7 . $ONOS_ROOT/tools/build/envDefaults 7 . $ONOS_ROOT/tools/build/envDefaults
8 8
9 cd ~/.m2/repository 9 cd ~/.m2/repository
10 -jar=$(find org/onlab -type f -name '*.jar' | grep $1 | grep -v -e -tests | head -n 1) 10 +jar=$(find org/onlab -type f -name '*.jar' | grep -e $1 | grep -v -e -tests | head -n 1)
11 11
12 [ -z "$jar" ] && echo "No bundle $1 found for" && exit 1 12 [ -z "$jar" ] && echo "No bundle $1 found for" && exit 1
13 13
......
1 +#!/bin/bash
2 +#-------------------------------------------------------------------------------
3 +# Update bundle on locally running karaf.
4 +#-------------------------------------------------------------------------------
5 +
6 +[ ! -d "$ONOS_ROOT" ] && echo "ONOS_ROOT is not defined" >&2 && exit 1
7 +. $ONOS_ROOT/tools/build/envDefaults
8 +
9 +cd ~/.m2/repository
10 +jar=$(find org/onlab -type f -name '*.jar' | grep -e $1 | grep -v -e -tests | head -n 1)
11 +
12 +[ -z "$jar" ] && echo "No bundle $1 found for" && exit 1
13 +
14 +bundle=$(echo $(basename $jar .jar) | sed 's/-[0-9].*//g')
15 +
16 +client "bundle:update -f $bundle" 2>/dev/null
1 +#!/bin/bash
2 +#-------------------------------------------------------------------------------
3 +# Monitors selected set of ONOS commands using the system watch command.
4 +#-------------------------------------------------------------------------------
5 +
6 +[ ! -d "$ONOS_ROOT" ] && echo "ONOS_ROOT is not defined" >&2 && exit 1
7 +. $ONOS_ROOT/tools/build/envDefaults
8 +
9 +node=${1:-$OCI}
10 +
11 +commands="${2:-summary,intents,flows,hosts}"
12 +
13 +aux=/tmp/onos-watch.$$
14 +trap "rm -f $aux" EXIT
15 +
16 +echo "$commands" | tr ',' '\n' > $aux
17 +watch $3 "onos $node -b <$aux 2>/dev/null"
1 +# Local VirtualBox-based single ONOS instance & ONOS mininet box
2 +
3 +export ONOS_NIC=192.168.56.*
4 +export OC1="192.168.56.103"
5 +export OCN="192.168.56.103"
6 +
7 +export ONOS_FEATURES="webconsole,onos-api,onos-core-trivial,onos-cli,onos-openflow,onos-app-fwd"
...@@ -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>
......
...@@ -22,11 +22,12 @@ import java.util.Arrays; ...@@ -22,11 +22,12 @@ import java.util.Arrays;
22 * 22 *
23 */ 23 */
24 public class MacAddress { 24 public class MacAddress {
25 - public static final byte[] ZERO_MAC_ADDRESS =
26 - MacAddress.valueOf("00:00:00:00:00:00").getAddress();
27 25
28 - public static final byte[] BROADCAST_MAC = 26 + public static final MacAddress ZERO = valueOf("00:00:00:00:00:00");
29 - MacAddress.valueOf("ff:ff:ff:ff:ff:ff").getAddress(); 27 + public static final MacAddress BROADCAST = valueOf("ff:ff:ff:ff:ff:ff");
28 +
29 + public static final byte[] ZERO_MAC_ADDRESS = ZERO.getAddress();
30 + public static final byte[] BROADCAST_MAC = BROADCAST.getAddress();
30 31
31 public static final int MAC_ADDRESS_LENGTH = 6; 32 public static final int MAC_ADDRESS_LENGTH = 6;
32 private byte[] address = new byte[MacAddress.MAC_ADDRESS_LENGTH]; 33 private byte[] address = new byte[MacAddress.MAC_ADDRESS_LENGTH];
......
...@@ -3,12 +3,15 @@ package org.onlab.packet; ...@@ -3,12 +3,15 @@ package org.onlab.packet;
3 /** 3 /**
4 * Representation of a VLAN ID. 4 * Representation of a VLAN ID.
5 */ 5 */
6 -// FIXME: This will end-up looking like a constant; we should name it 'VlanId', 'IpAddress', 'MacAddress'.
7 public class VlanId { 6 public class VlanId {
8 7
9 private final short value; 8 private final short value;
9 +
10 // Based on convention used elsewhere? Check and change if needed 10 // Based on convention used elsewhere? Check and change if needed
11 public static final short UNTAGGED = (short) 0xffff; 11 public static final short UNTAGGED = (short) 0xffff;
12 +
13 + public static final VlanId NONE = VlanId.vlanId(UNTAGGED);
14 +
12 // A VLAN ID is actually 12 bits of a VLAN tag. 15 // A VLAN ID is actually 12 bits of a VLAN tag.
13 public static final short MAX_VLAN = 4095; 16 public static final short MAX_VLAN = 4095;
14 17
......
...@@ -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>
......