Madan Jampani

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

Showing 56 changed files with 2014 additions and 361 deletions
...@@ -14,6 +14,6 @@ public class NettyLoggingHandler implements MessageHandler { ...@@ -14,6 +14,6 @@ public class NettyLoggingHandler implements MessageHandler {
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 + //log.info("Received message. Payload has {} bytes", message.payload().length);
18 } 18 }
19 } 19 }
......
...@@ -10,12 +10,17 @@ import org.onlab.metrics.MetricsManager; ...@@ -10,12 +10,17 @@ import org.onlab.metrics.MetricsManager;
10 import org.onlab.netty.Endpoint; 10 import org.onlab.netty.Endpoint;
11 import org.onlab.netty.NettyMessagingService; 11 import org.onlab.netty.NettyMessagingService;
12 import org.onlab.netty.Response; 12 import org.onlab.netty.Response;
13 +import org.slf4j.Logger;
14 +import org.slf4j.LoggerFactory;
13 15
14 import com.codahale.metrics.Timer; 16 import com.codahale.metrics.Timer;
15 17
16 // FIXME: Should be move out to test or app 18 // FIXME: Should be move out to test or app
17 public final class SimpleNettyClient { 19 public final class SimpleNettyClient {
18 - private SimpleNettyClient() { 20 +
21 +private static Logger log = LoggerFactory.getLogger(SimpleNettyClient.class);
22 +
23 + private SimpleNettyClient() {
19 } 24 }
20 25
21 public static void main(String[] args) 26 public static void main(String[] args)
...@@ -29,30 +34,33 @@ public final class SimpleNettyClient { ...@@ -29,30 +34,33 @@ public final class SimpleNettyClient {
29 34
30 System.exit(0); 35 System.exit(0);
31 } 36 }
32 - public static void startStandalone(String... args) throws Exception { 37 + public static void startStandalone(String[] args) throws Exception {
33 String host = args.length > 0 ? args[0] : "localhost"; 38 String host = args.length > 0 ? args[0] : "localhost";
34 int port = args.length > 1 ? Integer.parseInt(args[1]) : 8081; 39 int port = args.length > 1 ? Integer.parseInt(args[1]) : 8081;
35 int warmup = args.length > 2 ? Integer.parseInt(args[2]) : 1000; 40 int warmup = args.length > 2 ? Integer.parseInt(args[2]) : 1000;
36 int iterations = args.length > 3 ? Integer.parseInt(args[3]) : 50 * 100000; 41 int iterations = args.length > 3 ? Integer.parseInt(args[3]) : 50 * 100000;
37 NettyMessagingService messaging = new TestNettyMessagingService(9081); 42 NettyMessagingService messaging = new TestNettyMessagingService(9081);
38 MetricsManager metrics = new MetricsManager(); 43 MetricsManager metrics = new MetricsManager();
44 + Endpoint endpoint = new Endpoint(host, port);
39 messaging.activate(); 45 messaging.activate();
40 metrics.activate(); 46 metrics.activate();
41 MetricsFeature feature = new MetricsFeature("latency"); 47 MetricsFeature feature = new MetricsFeature("latency");
42 MetricsComponent component = metrics.registerComponent("NettyMessaging"); 48 MetricsComponent component = metrics.registerComponent("NettyMessaging");
49 + log.info("connecting " + host + ":" + port + " warmup:" + warmup + " iterations:" + iterations);
43 50
44 for (int i = 0; i < warmup; i++) { 51 for (int i = 0; i < warmup; i++) {
45 - messaging.sendAsync(new Endpoint(host, port), "simple", "Hello World".getBytes()); 52 + messaging.sendAsync(endpoint, "simple", "Hello World".getBytes());
46 Response response = messaging 53 Response response = messaging
47 - .sendAndReceive(new Endpoint(host, port), "echo", 54 + .sendAndReceive(endpoint, "echo",
48 "Hello World".getBytes()); 55 "Hello World".getBytes());
49 } 56 }
50 57
58 + log.info("measuring async sender");
51 Timer sendAsyncTimer = metrics.createTimer(component, feature, "AsyncSender"); 59 Timer sendAsyncTimer = metrics.createTimer(component, feature, "AsyncSender");
52 60
53 for (int i = 0; i < iterations; i++) { 61 for (int i = 0; i < iterations; i++) {
54 Timer.Context context = sendAsyncTimer.time(); 62 Timer.Context context = sendAsyncTimer.time();
55 - messaging.sendAsync(new Endpoint(host, port), "simple", "Hello World".getBytes()); 63 + messaging.sendAsync(endpoint, "simple", "Hello World".getBytes());
56 context.stop(); 64 context.stop();
57 } 65 }
58 66
...@@ -60,11 +68,12 @@ public final class SimpleNettyClient { ...@@ -60,11 +68,12 @@ public final class SimpleNettyClient {
60 for (int i = 0; i < iterations; i++) { 68 for (int i = 0; i < iterations; i++) {
61 Timer.Context context = sendAndReceiveTimer.time(); 69 Timer.Context context = sendAndReceiveTimer.time();
62 Response response = messaging 70 Response response = messaging
63 - .sendAndReceive(new Endpoint(host, port), "echo", 71 + .sendAndReceive(endpoint, "echo",
64 "Hello World".getBytes()); 72 "Hello World".getBytes());
65 // System.out.println("Got back:" + new String(response.get(2, TimeUnit.SECONDS))); 73 // System.out.println("Got back:" + new String(response.get(2, TimeUnit.SECONDS)));
66 context.stop(); 74 context.stop();
67 } 75 }
76 + metrics.deactivate();
68 } 77 }
69 78
70 public static class TestNettyMessagingService extends NettyMessagingService { 79 public static class TestNettyMessagingService extends NettyMessagingService {
......
...@@ -16,27 +16,26 @@ public class SimpleNettyClientCommand extends AbstractShellCommand { ...@@ -16,27 +16,26 @@ public class SimpleNettyClientCommand extends AbstractShellCommand {
16 //FIXME: replace these arguments with proper ones needed for the test. 16 //FIXME: replace these arguments with proper ones needed for the test.
17 @Argument(index = 0, name = "hostname", description = "Server Hostname", 17 @Argument(index = 0, name = "hostname", description = "Server Hostname",
18 required = false, multiValued = false) 18 required = false, multiValued = false)
19 - String host = "localhost"; 19 + String hostname = "localhost";
20 20
21 - @Argument(index = 3, name = "port", description = "Port", 21 + @Argument(index = 1, name = "port", description = "Port",
22 required = false, multiValued = false) 22 required = false, multiValued = false)
23 String port = "8081"; 23 String port = "8081";
24 24
25 - @Argument(index = 1, name = "warmupCount", description = "Warm-up count", 25 + @Argument(index = 2, name = "warmupCount", description = "Warm-up count",
26 required = false, multiValued = false) 26 required = false, multiValued = false)
27 - String warmup = "1000"; 27 + String warmupCount = "1000";
28 28
29 - @Argument(index = 2, name = "messageCount", description = "Message count", 29 + @Argument(index = 3, name = "messageCount", description = "Message count",
30 required = false, multiValued = false) 30 required = false, multiValued = false)
31 - String messageCount = "5000000"; 31 + String messageCount = "100000";
32 32
33 @Override 33 @Override
34 protected void execute() { 34 protected void execute() {
35 try { 35 try {
36 - startStandalone(new String[]{host, port, warmup, messageCount}); 36 + startStandalone(new String[]{hostname, port, warmupCount, messageCount});
37 } catch (Exception e) { 37 } catch (Exception e) {
38 error("Unable to start client %s", e); 38 error("Unable to start client %s", e);
39 } 39 }
40 } 40 }
41 -
42 } 41 }
......
...@@ -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 }
......
...@@ -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 }
......
...@@ -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 }
......
...@@ -27,7 +27,7 @@ public class AddHostToHostIntentCommand extends AbstractShellCommand { ...@@ -27,7 +27,7 @@ public class AddHostToHostIntentCommand extends AbstractShellCommand {
27 required = true, multiValued = false) 27 required = true, multiValued = false)
28 String two = null; 28 String two = null;
29 29
30 - private static long id = 1; 30 + private static long id = 0x7870001;
31 31
32 @Override 32 @Override
33 protected void execute() { 33 protected void execute() {
......
...@@ -14,6 +14,7 @@ import org.onlab.onos.net.intent.Intent; ...@@ -14,6 +14,7 @@ import org.onlab.onos.net.intent.Intent;
14 import org.onlab.onos.net.intent.IntentId; 14 import org.onlab.onos.net.intent.IntentId;
15 import org.onlab.onos.net.intent.IntentService; 15 import org.onlab.onos.net.intent.IntentService;
16 import org.onlab.onos.net.intent.PointToPointIntent; 16 import org.onlab.onos.net.intent.PointToPointIntent;
17 +import org.onlab.packet.Ethernet;
17 18
18 /** 19 /**
19 * Installs point-to-point connectivity intents. 20 * Installs point-to-point connectivity intents.
...@@ -32,7 +33,7 @@ public class AddPointToPointIntentCommand extends AbstractShellCommand { ...@@ -32,7 +33,7 @@ public class AddPointToPointIntentCommand extends AbstractShellCommand {
32 required = true, multiValued = false) 33 required = true, multiValued = false)
33 String egressDeviceString = null; 34 String egressDeviceString = null;
34 35
35 - private static long id = 1; 36 + private static long id = 0x7470001;
36 37
37 @Override 38 @Override
38 protected void execute() { 39 protected void execute() {
...@@ -48,7 +49,9 @@ public class AddPointToPointIntentCommand extends AbstractShellCommand { ...@@ -48,7 +49,9 @@ public class AddPointToPointIntentCommand extends AbstractShellCommand {
48 PortNumber.portNumber(getPortNumber(egressDeviceString)); 49 PortNumber.portNumber(getPortNumber(egressDeviceString));
49 ConnectPoint egress = new ConnectPoint(egressDeviceId, egressPortNumber); 50 ConnectPoint egress = new ConnectPoint(egressDeviceId, egressPortNumber);
50 51
51 - TrafficSelector selector = DefaultTrafficSelector.builder().build(); 52 + TrafficSelector selector = DefaultTrafficSelector.builder()
53 + .matchEthType(Ethernet.TYPE_IPV4)
54 + .build();
52 TrafficTreatment treatment = DefaultTrafficTreatment.builder().build(); 55 TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
53 56
54 Intent intent = 57 Intent intent =
......
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; 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 }
......
...@@ -34,7 +34,7 @@ public interface MastershipService { ...@@ -34,7 +34,7 @@ public interface MastershipService {
34 /** 34 /**
35 * Abandons mastership of the specified device on the local node thus 35 * Abandons mastership of the specified device on the local node thus
36 * forcing selection of a new master. If the local node is not a master 36 * forcing selection of a new master. If the local node is not a master
37 - * for this device, no action will be taken. 37 + * for this device, no master selection will occur.
38 * 38 *
39 * @param deviceId the identifier of the device 39 * @param deviceId the identifier of the device
40 */ 40 */
......
...@@ -66,12 +66,25 @@ public interface MastershipStore extends Store<MastershipEvent, MastershipStoreD ...@@ -66,12 +66,25 @@ public interface MastershipStore extends Store<MastershipEvent, MastershipStoreD
66 MastershipTerm getTermFor(DeviceId deviceId); 66 MastershipTerm getTermFor(DeviceId deviceId);
67 67
68 /** 68 /**
69 - * Revokes a controller instance's mastership over a device and hands 69 + * Sets a controller instance's mastership role to STANDBY for a device.
70 - * over mastership to another controller instance. 70 + * If the role is MASTER, another controller instance will be selected
71 + * as a candidate master.
71 * 72 *
72 * @param nodeId the controller instance identifier 73 * @param nodeId the controller instance identifier
73 - * @param deviceId device to revoke mastership for 74 + * @param deviceId device to revoke mastership role for
74 * @return a mastership event 75 * @return a mastership event
75 */ 76 */
76 - MastershipEvent unsetMaster(NodeId nodeId, DeviceId deviceId); 77 + MastershipEvent setStandby(NodeId nodeId, DeviceId deviceId);
78 +
79 + /**
80 + * Allows a controller instance to give up its current role for a device.
81 + * If the role is MASTER, another controller instance will be selected
82 + * as a candidate master.
83 + *
84 + * @param nodeId the controller instance identifier
85 + * @param deviceId device to revoke mastership role for
86 + * @return a mastership event
87 + */
88 + MastershipEvent relinquishRole(NodeId nodeId, DeviceId deviceId);
89 +
77 } 90 }
......
...@@ -42,6 +42,7 @@ public interface DeviceService { ...@@ -42,6 +42,7 @@ public interface DeviceService {
42 * @param deviceId device identifier 42 * @param deviceId device identifier
43 * @return designated mastership role 43 * @return designated mastership role
44 */ 44 */
45 + //XXX do we want this method here when MastershipService already does?
45 MastershipRole getRole(DeviceId deviceId); 46 MastershipRole getRole(DeviceId deviceId);
46 47
47 48
......
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 }
......
...@@ -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.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.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
......
...@@ -82,7 +82,7 @@ implements MastershipService, MastershipAdminService { ...@@ -82,7 +82,7 @@ implements MastershipService, MastershipAdminService {
82 if (role.equals(MastershipRole.MASTER)) { 82 if (role.equals(MastershipRole.MASTER)) {
83 event = store.setMaster(nodeId, deviceId); 83 event = store.setMaster(nodeId, deviceId);
84 } else { 84 } else {
85 - event = store.unsetMaster(nodeId, deviceId); 85 + event = store.setStandby(nodeId, deviceId);
86 } 86 }
87 87
88 if (event != null) { 88 if (event != null) {
...@@ -98,13 +98,10 @@ implements MastershipService, MastershipAdminService { ...@@ -98,13 +98,10 @@ implements MastershipService, MastershipAdminService {
98 98
99 @Override 99 @Override
100 public void relinquishMastership(DeviceId deviceId) { 100 public void relinquishMastership(DeviceId deviceId) {
101 - MastershipRole role = getLocalRole(deviceId); 101 + MastershipEvent event = null;
102 - if (!role.equals(MastershipRole.MASTER)) { 102 + event = store.relinquishRole(
103 - return;
104 - }
105 -
106 - MastershipEvent event = store.unsetMaster(
107 clusterService.getLocalNode().id(), deviceId); 103 clusterService.getLocalNode().id(), deviceId);
104 +
108 if (event != null) { 105 if (event != null) {
109 post(event); 106 post(event);
110 } 107 }
......
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
...@@ -143,7 +143,7 @@ public class DeviceManager ...@@ -143,7 +143,7 @@ public class DeviceManager
143 143
144 // Applies the specified role to the device; ignores NONE 144 // Applies the specified role to the device; ignores NONE
145 private void applyRole(DeviceId deviceId, MastershipRole newRole) { 145 private void applyRole(DeviceId deviceId, MastershipRole newRole) {
146 - if (newRole != MastershipRole.NONE) { 146 + if (newRole.equals(MastershipRole.NONE)) {
147 Device device = store.getDevice(deviceId); 147 Device device = store.getDevice(deviceId);
148 // FIXME: Device might not be there yet. (eventual consistent) 148 // FIXME: Device might not be there yet. (eventual consistent)
149 if (device == null) { 149 if (device == null) {
...@@ -257,13 +257,14 @@ public class DeviceManager ...@@ -257,13 +257,14 @@ public class DeviceManager
257 // temporarily request for Master Role and mark offline. 257 // temporarily request for Master Role and mark offline.
258 if (!mastershipService.getLocalRole(deviceId).equals(MastershipRole.MASTER)) { 258 if (!mastershipService.getLocalRole(deviceId).equals(MastershipRole.MASTER)) {
259 log.debug("Device {} disconnected, but I am not the master", deviceId); 259 log.debug("Device {} disconnected, but I am not the master", deviceId);
260 + //let go of any role anyways
261 + mastershipService.relinquishMastership(deviceId);
260 return; 262 return;
261 } 263 }
262 DeviceEvent event = store.markOffline(deviceId); 264 DeviceEvent event = store.markOffline(deviceId);
263 - 265 + //we're no longer capable of being master or a candidate.
264 mastershipService.relinquishMastership(deviceId); 266 mastershipService.relinquishMastership(deviceId);
265 267
266 - //we're no longer capable of mastership.
267 if (event != null) { 268 if (event != null) {
268 log.info("Device {} disconnected", deviceId); 269 log.info("Device {} disconnected", deviceId);
269 post(event); 270 post(event);
...@@ -319,24 +320,29 @@ public class DeviceManager ...@@ -319,24 +320,29 @@ public class DeviceManager
319 } 320 }
320 321
321 // Intercepts mastership events 322 // Intercepts mastership events
322 - private class InternalMastershipListener 323 + private class InternalMastershipListener implements MastershipListener {
323 - implements MastershipListener { 324 +
324 @Override 325 @Override
325 public void event(MastershipEvent event) { 326 public void event(MastershipEvent event) {
326 - final NodeId myNodeId = clusterService.getLocalNode().id(); 327 + final DeviceId did = event.subject();
327 - if (myNodeId.equals(event.master())) { 328 + if (isAvailable(did)) {
328 - 329 + final NodeId myNodeId = clusterService.getLocalNode().id();
329 - MastershipTerm term = mastershipService.requestTermService() 330 +
330 - .getMastershipTerm(event.subject()); 331 + if (myNodeId.equals(event.master())) {
331 - 332 + MastershipTerm term = termService.getMastershipTerm(did);
332 - if (term.master().equals(myNodeId)) { 333 +
333 - // only set the new term if I am the master 334 + if (term.master().equals(myNodeId)) {
334 - clockProviderService.setMastershipTerm(event.subject(), term); 335 + // only set the new term if I am the master
336 + clockProviderService.setMastershipTerm(did, term);
337 + }
338 + applyRole(did, MastershipRole.MASTER);
339 + } else {
340 + applyRole(did, MastershipRole.STANDBY);
335 } 341 }
336 -
337 - applyRole(event.subject(), MastershipRole.MASTER);
338 } else { 342 } else {
339 - applyRole(event.subject(), MastershipRole.STANDBY); 343 + //device dead to node, give up
344 + mastershipService.relinquishMastership(did);
345 + applyRole(did, MastershipRole.STANDBY);
340 } 346 }
341 } 347 }
342 } 348 }
......
...@@ -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 }
......
...@@ -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())));
......
...@@ -272,7 +272,8 @@ public class DeviceManagerTest { ...@@ -272,7 +272,8 @@ public class DeviceManagerTest {
272 } 272 }
273 } 273 }
274 274
275 - private static class TestMastershipService extends MastershipServiceAdapter { 275 + private static class TestMastershipService
276 + extends MastershipServiceAdapter {
276 @Override 277 @Override
277 public MastershipRole getLocalRole(DeviceId deviceId) { 278 public MastershipRole getLocalRole(DeviceId deviceId) {
278 return MastershipRole.MASTER; 279 return MastershipRole.MASTER;
......
...@@ -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 }
......
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 +}
...@@ -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.cluster.impl; 1 package org.onlab.onos.store.cluster.impl;
2 2
3 -import static com.google.common.cache.CacheBuilder.newBuilder;
4 import static org.onlab.onos.cluster.MastershipEvent.Type.MASTER_CHANGED; 3 import static org.onlab.onos.cluster.MastershipEvent.Type.MASTER_CHANGED;
5 4
6 import java.util.Map; 5 import java.util.Map;
7 -import java.util.Objects;
8 import java.util.Set; 6 import java.util.Set;
9 7
10 import org.apache.felix.scr.annotations.Activate; 8 import org.apache.felix.scr.annotations.Activate;
...@@ -21,17 +19,16 @@ import org.onlab.onos.cluster.MastershipTerm; ...@@ -21,17 +19,16 @@ import org.onlab.onos.cluster.MastershipTerm;
21 import org.onlab.onos.cluster.NodeId; 19 import org.onlab.onos.cluster.NodeId;
22 import org.onlab.onos.net.DeviceId; 20 import org.onlab.onos.net.DeviceId;
23 import org.onlab.onos.net.MastershipRole; 21 import org.onlab.onos.net.MastershipRole;
24 -import org.onlab.onos.store.common.AbsentInvalidatingLoadingCache;
25 import org.onlab.onos.store.common.AbstractHazelcastStore; 22 import org.onlab.onos.store.common.AbstractHazelcastStore;
26 -import org.onlab.onos.store.common.OptionalCacheLoader;
27 23
28 -import com.google.common.base.Optional;
29 -import com.google.common.cache.LoadingCache;
30 import com.google.common.collect.ImmutableSet; 24 import com.google.common.collect.ImmutableSet;
25 +import com.hazelcast.core.ILock;
31 import com.hazelcast.core.IMap; 26 import com.hazelcast.core.IMap;
27 +import com.hazelcast.core.MultiMap;
32 28
33 /** 29 /**
34 - * Distributed implementation of the cluster nodes store. 30 + * Distributed implementation of the mastership store. The store is
31 + * responsible for the master selection process.
35 */ 32 */
36 @Component(immediate = true) 33 @Component(immediate = true)
37 @Service 34 @Service
...@@ -39,8 +36,21 @@ public class DistributedMastershipStore ...@@ -39,8 +36,21 @@ public class DistributedMastershipStore
39 extends AbstractHazelcastStore<MastershipEvent, MastershipStoreDelegate> 36 extends AbstractHazelcastStore<MastershipEvent, MastershipStoreDelegate>
40 implements MastershipStore { 37 implements MastershipStore {
41 38
42 - private IMap<byte[], byte[]> rawMasters; 39 + //arbitrary lock name
43 - private LoadingCache<DeviceId, Optional<NodeId>> masters; 40 + private static final String LOCK = "lock";
41 + //initial term/TTL value
42 + private static final Integer INIT = 0;
43 +
44 + //devices to masters
45 + protected IMap<byte[], byte[]> masters;
46 + //devices to terms
47 + protected IMap<byte[], Integer> terms;
48 +
49 + //re-election related, disjoint-set structures:
50 + //device-nodes multiset of available nodes
51 + protected MultiMap<byte[], byte[]> standbys;
52 + //device-nodes multiset for nodes that have given up on device
53 + protected MultiMap<byte[], byte[]> unusable;
44 54
45 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 55 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
46 protected ClusterService clusterService; 56 protected ClusterService clusterService;
...@@ -50,99 +60,263 @@ implements MastershipStore { ...@@ -50,99 +60,263 @@ implements MastershipStore {
50 public void activate() { 60 public void activate() {
51 super.activate(); 61 super.activate();
52 62
53 - rawMasters = theInstance.getMap("masters"); 63 + masters = theInstance.getMap("masters");
54 - OptionalCacheLoader<DeviceId, NodeId> nodeLoader 64 + terms = theInstance.getMap("terms");
55 - = new OptionalCacheLoader<>(serializer, rawMasters); 65 + standbys = theInstance.getMultiMap("backups");
56 - masters = new AbsentInvalidatingLoadingCache<>(newBuilder().build(nodeLoader)); 66 + unusable = theInstance.getMultiMap("unusable");
57 - rawMasters.addEntryListener(new RemoteMasterShipEventHandler(masters), true);
58 67
59 - loadMasters(); 68 + masters.addEntryListener(new RemoteMasterShipEventHandler(), true);
60 69
61 log.info("Started"); 70 log.info("Started");
62 } 71 }
63 72
64 - private void loadMasters() {
65 - for (byte[] keyBytes : rawMasters.keySet()) {
66 - final DeviceId id = deserialize(keyBytes);
67 - masters.refresh(id);
68 - }
69 - }
70 -
71 @Deactivate 73 @Deactivate
72 public void deactivate() { 74 public void deactivate() {
73 log.info("Stopped"); 75 log.info("Stopped");
74 } 76 }
75 77
76 @Override 78 @Override
77 - public MastershipEvent setMaster(NodeId nodeId, DeviceId deviceId) { 79 + public MastershipRole getRole(NodeId nodeId, DeviceId deviceId) {
78 - synchronized (this) { 80 + byte[] did = serialize(deviceId);
79 - NodeId currentMaster = getMaster(deviceId); 81 + byte[] nid = serialize(nodeId);
80 - if (Objects.equals(currentMaster, nodeId)) { 82 +
81 - return null; 83 + NodeId current = deserialize(masters.get(did));
84 + if (current == null) {
85 + if (standbys.containsEntry(did, nid)) {
86 + //was previously standby, or set to standby from master
87 + return MastershipRole.STANDBY;
88 + } else {
89 + return MastershipRole.NONE;
90 + }
91 + } else {
92 + if (current.equals(nodeId)) {
93 + //*should* be in unusable, not always
94 + return MastershipRole.MASTER;
95 + } else {
96 + //may be in backups or unusable from earlier retirement
97 + return MastershipRole.STANDBY;
82 } 98 }
99 + }
100 + }
83 101
84 - // FIXME: for now implementing semantics of setMaster 102 + @Override
85 - rawMasters.put(serialize(deviceId), serialize(nodeId)); 103 + public MastershipEvent setMaster(NodeId nodeId, DeviceId deviceId) {
86 - masters.put(deviceId, Optional.of(nodeId)); 104 + byte [] did = serialize(deviceId);
87 - return new MastershipEvent(MastershipEvent.Type.MASTER_CHANGED, deviceId, nodeId); 105 + byte [] nid = serialize(nodeId);
106 +
107 + ILock lock = theInstance.getLock(LOCK);
108 + lock.lock();
109 + try {
110 + MastershipRole role = getRole(nodeId, deviceId);
111 + switch (role) {
112 + case MASTER:
113 + //reinforce mastership
114 + evict(nid, did);
115 + return null;
116 + case STANDBY:
117 + //make current master standby
118 + byte [] current = masters.get(did);
119 + if (current != null) {
120 + backup(current, did);
121 + }
122 + //assign specified node as new master
123 + masters.put(did, nid);
124 + evict(nid, did);
125 + updateTerm(did);
126 + return new MastershipEvent(MASTER_CHANGED, deviceId, nodeId);
127 + case NONE:
128 + masters.put(did, nid);
129 + evict(nid, did);
130 + updateTerm(did);
131 + return new MastershipEvent(MASTER_CHANGED, deviceId, nodeId);
132 + default:
133 + log.warn("unknown Mastership Role {}", role);
134 + return null;
135 + }
136 + } finally {
137 + lock.unlock();
88 } 138 }
89 } 139 }
90 140
91 @Override 141 @Override
92 public NodeId getMaster(DeviceId deviceId) { 142 public NodeId getMaster(DeviceId deviceId) {
93 - return masters.getUnchecked(deviceId).orNull(); 143 + return deserialize(masters.get(serialize(deviceId)));
94 } 144 }
95 145
96 @Override 146 @Override
97 public Set<DeviceId> getDevices(NodeId nodeId) { 147 public Set<DeviceId> getDevices(NodeId nodeId) {
98 ImmutableSet.Builder<DeviceId> builder = ImmutableSet.builder(); 148 ImmutableSet.Builder<DeviceId> builder = ImmutableSet.builder();
99 - for (Map.Entry<DeviceId, Optional<NodeId>> entry : masters.asMap().entrySet()) { 149 +
100 - if (nodeId.equals(entry.getValue().get())) { 150 + for (Map.Entry<byte[], byte[]> entry : masters.entrySet()) {
101 - builder.add(entry.getKey()); 151 + if (nodeId.equals(deserialize(entry.getValue()))) {
152 + builder.add((DeviceId) deserialize(entry.getKey()));
102 } 153 }
103 } 154 }
155 +
104 return builder.build(); 156 return builder.build();
105 } 157 }
106 158
107 @Override 159 @Override
108 public MastershipRole requestRole(DeviceId deviceId) { 160 public MastershipRole requestRole(DeviceId deviceId) {
109 - // FIXME: for now we are 'selecting' as master whoever asks 161 + NodeId local = clusterService.getLocalNode().id();
110 - setMaster(clusterService.getLocalNode().id(), deviceId); 162 + byte [] did = serialize(deviceId);
111 - return MastershipRole.MASTER; 163 + byte [] lnid = serialize(local);
164 +
165 + ILock lock = theInstance.getLock(LOCK);
166 + lock.lock();
167 + try {
168 + MastershipRole role = getRole(local, deviceId);
169 + switch (role) {
170 + case MASTER:
171 + evict(lnid, did);
172 + break;
173 + case STANDBY:
174 + backup(lnid, did);
175 + terms.putIfAbsent(did, INIT);
176 + break;
177 + case NONE:
178 + //claim mastership
179 + masters.put(did, lnid);
180 + evict(lnid, did);
181 + updateTerm(did);
182 + role = MastershipRole.MASTER;
183 + break;
184 + default:
185 + log.warn("unknown Mastership Role {}", role);
186 + }
187 + return role;
188 + } finally {
189 + lock.unlock();
190 + }
112 } 191 }
113 192
114 @Override 193 @Override
115 - public MastershipRole getRole(NodeId nodeId, DeviceId deviceId) { 194 + public MastershipTerm getTermFor(DeviceId deviceId) {
116 - NodeId master = masters.getUnchecked(deviceId).orNull(); 195 + byte[] did = serialize(deviceId);
117 - return nodeId.equals(master) ? MastershipRole.MASTER : MastershipRole.STANDBY; 196 + if ((masters.get(did) == null) ||
197 + (terms.get(did) == null)) {
198 + return null;
199 + }
200 + return MastershipTerm.of(
201 + (NodeId) deserialize(masters.get(did)), terms.get(did));
118 } 202 }
119 203
120 @Override 204 @Override
121 - public MastershipTerm getTermFor(DeviceId deviceId) { 205 + public MastershipEvent setStandby(NodeId nodeId, DeviceId deviceId) {
122 - // FIXME: implement this properly 206 + byte [] did = serialize(deviceId);
123 - return MastershipTerm.of(getMaster(deviceId), 1); 207 + byte [] nid = serialize(nodeId);
208 + MastershipEvent event = null;
209 +
210 + ILock lock = theInstance.getLock(LOCK);
211 + lock.lock();
212 + try {
213 + MastershipRole role = getRole(nodeId, deviceId);
214 + switch (role) {
215 + case MASTER:
216 + event = reelect(nodeId, deviceId);
217 + backup(nid, did);
218 + break;
219 + case STANDBY:
220 + //fall through to reinforce role
221 + case NONE:
222 + backup(nid, did);
223 + break;
224 + default:
225 + log.warn("unknown Mastership Role {}", role);
226 + }
227 + return event;
228 + } finally {
229 + lock.unlock();
230 + }
124 } 231 }
125 232
126 @Override 233 @Override
127 - public MastershipEvent unsetMaster(NodeId nodeId, DeviceId deviceId) { 234 + public MastershipEvent relinquishRole(NodeId nodeId, DeviceId deviceId) {
128 - boolean removed = rawMasters.remove(serialize(deviceId), serialize(nodeId)); 235 + byte [] did = serialize(deviceId);
129 - masters.invalidate(deviceId); 236 + byte [] nid = serialize(nodeId);
130 - if (!removed) { 237 + MastershipEvent event = null;
131 - return null; 238 +
239 + ILock lock = theInstance.getLock(LOCK);
240 + lock.lock();
241 + try {
242 + MastershipRole role = getRole(nodeId, deviceId);
243 + switch (role) {
244 + case MASTER:
245 + event = reelect(nodeId, deviceId);
246 + evict(nid, did);
247 + break;
248 + case STANDBY:
249 + //fall through to reinforce relinquishment
250 + case NONE:
251 + evict(nid, did);
252 + break;
253 + default:
254 + log.warn("unknown Mastership Role {}", role);
255 + }
256 + return event;
257 + } finally {
258 + lock.unlock();
132 } 259 }
133 - Optional<NodeId> newMaster = masters.getUnchecked(deviceId); 260 + }
134 - if (newMaster.isPresent()) { 261 +
135 - return new MastershipEvent(MASTER_CHANGED, deviceId, newMaster.get()); 262 + //helper to fetch a new master candidate for a given device.
136 - } else { 263 + private MastershipEvent reelect(NodeId current, DeviceId deviceId) {
137 - // FIXME: probably need to express NO_MASTER somehow. 264 + byte [] did = serialize(deviceId);
265 + byte [] nid = serialize(current);
266 +
267 + //if this is an queue it'd be neater.
268 + byte [] backup = null;
269 + for (byte [] n : standbys.get(serialize(deviceId))) {
270 + if (!current.equals(deserialize(n))) {
271 + backup = n;
272 + break;
273 + }
274 + }
275 +
276 + if (backup == null) {
277 + masters.remove(did, nid);
138 return null; 278 return null;
279 + } else {
280 + masters.put(did, backup);
281 + evict(backup, did);
282 + Integer term = terms.get(did);
283 + terms.put(did, ++term);
284 + return new MastershipEvent(
285 + MASTER_CHANGED, deviceId, (NodeId) deserialize(backup));
139 } 286 }
140 } 287 }
141 288
142 - private class RemoteMasterShipEventHandler extends RemoteCacheEventHandler<DeviceId, NodeId> { 289 + //adds node to pool(s) of backups and moves them from unusable.
143 - public RemoteMasterShipEventHandler(LoadingCache<DeviceId, Optional<NodeId>> cache) { 290 + private void backup(byte [] nodeId, byte [] deviceId) {
144 - super(cache); 291 + if (!standbys.containsEntry(deviceId, nodeId)) {
292 + standbys.put(deviceId, nodeId);
145 } 293 }
294 + if (unusable.containsEntry(deviceId, nodeId)) {
295 + unusable.remove(deviceId, nodeId);
296 + }
297 + }
298 +
299 + //adds node to unusable and evicts it from backup pool.
300 + private void evict(byte [] nodeId, byte [] deviceId) {
301 + if (!unusable.containsEntry(deviceId, nodeId)) {
302 + unusable.put(deviceId, nodeId);
303 + }
304 + if (standbys.containsEntry(deviceId, nodeId)) {
305 + standbys.remove(deviceId, nodeId);
306 + }
307 + }
308 +
309 + //adds or updates term information.
310 + private void updateTerm(byte [] deviceId) {
311 + Integer term = terms.get(deviceId);
312 + if (term == null) {
313 + terms.put(deviceId, INIT);
314 + } else {
315 + terms.put(deviceId, ++term);
316 + }
317 + }
318 +
319 + private class RemoteMasterShipEventHandler extends RemoteEventHandler<DeviceId, NodeId> {
146 320
147 @Override 321 @Override
148 protected void onAdd(DeviceId deviceId, NodeId nodeId) { 322 protected void onAdd(DeviceId deviceId, NodeId nodeId) {
...@@ -151,12 +325,13 @@ implements MastershipStore { ...@@ -151,12 +325,13 @@ implements MastershipStore {
151 325
152 @Override 326 @Override
153 protected void onRemove(DeviceId deviceId, NodeId nodeId) { 327 protected void onRemove(DeviceId deviceId, NodeId nodeId) {
154 - notifyDelegate(new MastershipEvent(MASTER_CHANGED, deviceId, nodeId)); 328 + //notifyDelegate(new MastershipEvent(MASTER_CHANGED, deviceId, nodeId));
155 } 329 }
156 330
157 @Override 331 @Override
158 protected void onUpdate(DeviceId deviceId, NodeId oldNodeId, NodeId nodeId) { 332 protected void onUpdate(DeviceId deviceId, NodeId oldNodeId, NodeId nodeId) {
159 - notifyDelegate(new MastershipEvent(MASTER_CHANGED, deviceId, nodeId)); 333 + //only addition indicates a change in mastership
334 + //notifyDelegate(new MastershipEvent(MASTER_CHANGED, deviceId, nodeId));
160 } 335 }
161 } 336 }
162 337
......
1 +package org.onlab.onos.store.cluster.impl;
2 +
3 +import static org.junit.Assert.assertEquals;
4 +import static org.junit.Assert.assertNull;
5 +import static org.junit.Assert.assertTrue;
6 +import static org.onlab.onos.net.MastershipRole.*;
7 +
8 +import java.util.Map;
9 +import java.util.Set;
10 +import java.util.concurrent.CountDownLatch;
11 +import java.util.concurrent.TimeUnit;
12 +
13 +import org.junit.After;
14 +import org.junit.AfterClass;
15 +import org.junit.Before;
16 +import org.junit.BeforeClass;
17 +import org.junit.Ignore;
18 +import org.junit.Test;
19 +import org.onlab.onos.cluster.ClusterEventListener;
20 +import org.onlab.onos.cluster.ClusterService;
21 +import org.onlab.onos.cluster.ControllerNode;
22 +import org.onlab.onos.cluster.ControllerNode.State;
23 +import org.onlab.onos.cluster.DefaultControllerNode;
24 +import org.onlab.onos.cluster.MastershipEvent;
25 +import org.onlab.onos.cluster.MastershipEvent.Type;
26 +import org.onlab.onos.cluster.MastershipStoreDelegate;
27 +import org.onlab.onos.cluster.MastershipTerm;
28 +import org.onlab.onos.cluster.NodeId;
29 +import org.onlab.onos.net.DeviceId;
30 +import org.onlab.onos.store.common.StoreManager;
31 +import org.onlab.onos.store.common.StoreService;
32 +import org.onlab.onos.store.common.TestStoreManager;
33 +import org.onlab.onos.store.serializers.KryoSerializer;
34 +import org.onlab.packet.IpPrefix;
35 +
36 +import com.google.common.collect.Sets;
37 +import com.hazelcast.config.Config;
38 +import com.hazelcast.core.Hazelcast;
39 +
40 +/**
41 + * Test of the Hazelcast-based distributed MastershipStore implementation.
42 + */
43 +public class DistributedMastershipStoreTest {
44 +
45 + private static final DeviceId DID1 = DeviceId.deviceId("of:01");
46 + private static final DeviceId DID2 = DeviceId.deviceId("of:02");
47 + private static final DeviceId DID3 = DeviceId.deviceId("of:03");
48 +
49 + private static final IpPrefix IP = IpPrefix.valueOf("127.0.0.1");
50 +
51 + private static final NodeId N1 = new NodeId("node1");
52 + private static final NodeId N2 = new NodeId("node2");
53 +
54 + private static final ControllerNode CN1 = new DefaultControllerNode(N1, IP);
55 + private static final ControllerNode CN2 = new DefaultControllerNode(N2, IP);
56 +
57 + private DistributedMastershipStore dms;
58 + private TestDistributedMastershipStore testStore;
59 + private KryoSerializer serializationMgr;
60 + private StoreManager storeMgr;
61 +
62 + @BeforeClass
63 + public static void setUpBeforeClass() throws Exception {
64 + }
65 +
66 + @AfterClass
67 + public static void tearDownAfterClass() throws Exception {
68 + }
69 +
70 + @Before
71 + public void setUp() throws Exception {
72 + // TODO should find a way to clean Hazelcast instance without shutdown.
73 + Config config = TestStoreManager.getTestConfig();
74 +
75 + storeMgr = new TestStoreManager(Hazelcast.newHazelcastInstance(config));
76 + storeMgr.activate();
77 +
78 + serializationMgr = new KryoSerializer();
79 +
80 + dms = new TestDistributedMastershipStore(storeMgr, serializationMgr);
81 + dms.clusterService = new TestClusterService();
82 + dms.activate();
83 +
84 + testStore = (TestDistributedMastershipStore) dms;
85 + }
86 +
87 + @After
88 + public void tearDown() throws Exception {
89 + dms.deactivate();
90 +
91 + storeMgr.deactivate();
92 + }
93 +
94 + @Test
95 + public void getRole() {
96 + assertEquals("wrong role:", NONE, dms.getRole(N1, DID1));
97 + testStore.put(DID1, N1, true, false, true);
98 + assertEquals("wrong role:", MASTER, dms.getRole(N1, DID1));
99 + assertEquals("wrong role:", STANDBY, dms.getRole(N2, DID1));
100 + }
101 +
102 + @Test
103 + public void getMaster() {
104 + assertTrue("wrong store state:", dms.masters.isEmpty());
105 +
106 + testStore.put(DID1, N1, true, false, false);
107 + assertEquals("wrong master:", N1, dms.getMaster(DID1));
108 + assertNull("wrong master:", dms.getMaster(DID2));
109 + }
110 +
111 + @Test
112 + public void getDevices() {
113 + assertTrue("wrong store state:", dms.masters.isEmpty());
114 +
115 + testStore.put(DID1, N1, true, false, false);
116 + testStore.put(DID2, N1, true, false, false);
117 + testStore.put(DID3, N2, true, false, false);
118 +
119 + assertEquals("wrong devices",
120 + Sets.newHashSet(DID1, DID2), dms.getDevices(N1));
121 + }
122 +
123 + @Test
124 + public void requestRoleAndTerm() {
125 + //CN1 is "local"
126 + testStore.setCurrent(CN1);
127 +
128 + //if already MASTER, nothing should happen
129 + testStore.put(DID2, N1, true, false, false);
130 + assertEquals("wrong role for MASTER:", MASTER, dms.requestRole(DID2));
131 +
132 + //populate maps with DID1, N1 thru NONE case
133 + assertEquals("wrong role for NONE:", MASTER, dms.requestRole(DID1));
134 + assertTrue("wrong state for store:", !dms.terms.isEmpty());
135 + assertEquals("wrong term",
136 + MastershipTerm.of(N1, 0), dms.getTermFor(DID1));
137 +
138 + //CN2 now local. DID2 has N1 as MASTER so N2 is STANDBY
139 + testStore.setCurrent(CN2);
140 + assertEquals("wrong role for STANDBY:", STANDBY, dms.requestRole(DID2));
141 + assertEquals("wrong number of entries:", 2, dms.terms.size());
142 +
143 + //change term and requestRole() again; should persist
144 + testStore.increment(DID2);
145 + assertEquals("wrong role for STANDBY:", STANDBY, dms.requestRole(DID2));
146 + assertEquals("wrong term", MastershipTerm.of(N1, 1), dms.getTermFor(DID2));
147 + }
148 +
149 + @Test
150 + public void setMaster() {
151 + //populate maps with DID1, N1 as MASTER thru NONE case
152 + testStore.setCurrent(CN1);
153 + assertEquals("wrong role for NONE:", MASTER, dms.requestRole(DID1));
154 + assertNull("wrong event:", dms.setMaster(N1, DID1));
155 +
156 + //switch over to N2
157 + assertEquals("wrong event:", Type.MASTER_CHANGED, dms.setMaster(N2, DID1).type());
158 + assertEquals("wrong term", MastershipTerm.of(N2, 1), dms.getTermFor(DID1));
159 +
160 + //orphan switch - should be rare case
161 + assertEquals("wrong event:", Type.MASTER_CHANGED, dms.setMaster(N2, DID2).type());
162 + assertEquals("wrong term", MastershipTerm.of(N2, 0), dms.getTermFor(DID2));
163 + //disconnect and reconnect - sign of failing re-election or single-instance channel
164 + testStore.reset(true, false, false);
165 + dms.setMaster(N2, DID2);
166 + assertEquals("wrong term", MastershipTerm.of(N2, 1), dms.getTermFor(DID2));
167 + }
168 +
169 + @Test
170 + public void relinquishRole() {
171 + //populate maps with DID1, N1 as MASTER thru NONE case
172 + testStore.setCurrent(CN1);
173 + assertEquals("wrong role for NONE:", MASTER, dms.requestRole(DID1));
174 + //no backup, no new MASTER/event
175 + assertNull("wrong event:", dms.relinquishRole(N1, DID1));
176 +
177 + dms.requestRole(DID1);
178 +
179 + //add backup CN2, get it elected MASTER by relinquishing
180 + testStore.setCurrent(CN2);
181 + assertEquals("wrong role for NONE:", STANDBY, dms.requestRole(DID1));
182 + assertEquals("wrong event:", Type.MASTER_CHANGED, dms.relinquishRole(N1, DID1).type());
183 + assertEquals("wrong master", N2, dms.getMaster(DID1));
184 +
185 + //STANDBY - nothing here, either
186 + assertNull("wrong event:", dms.relinquishRole(N1, DID1));
187 + assertEquals("wrong role for node:", STANDBY, dms.getRole(N1, DID1));
188 +
189 + //all nodes "give up" on device, which goes back to NONE.
190 + assertNull("wrong event:", dms.relinquishRole(N2, DID1));
191 + assertEquals("wrong role for node:", NONE, dms.getRole(N2, DID1));
192 + assertEquals("wrong role for node:", NONE, dms.getRole(N1, DID1));
193 +
194 + assertEquals("wrong number of retired nodes", 2, dms.unusable.size());
195 +
196 + //bring nodes back
197 + assertEquals("wrong role for NONE:", MASTER, dms.requestRole(DID1));
198 + testStore.setCurrent(CN1);
199 + assertEquals("wrong role for NONE:", STANDBY, dms.requestRole(DID1));
200 + assertEquals("wrong number of backup nodes", 1, dms.standbys.size());
201 +
202 + //NONE - nothing happens
203 + assertNull("wrong event:", dms.relinquishRole(N1, DID2));
204 + assertEquals("wrong role for node:", NONE, dms.getRole(N1, DID2));
205 +
206 + }
207 +
208 + @Ignore("Ignore until Delegate spec. is clear.")
209 + @Test
210 + public void testEvents() throws InterruptedException {
211 + //shamelessly copy other distributed store tests
212 + final CountDownLatch addLatch = new CountDownLatch(1);
213 +
214 + MastershipStoreDelegate checkAdd = new MastershipStoreDelegate() {
215 + @Override
216 + public void notify(MastershipEvent event) {
217 + assertEquals("wrong event:", Type.MASTER_CHANGED, event.type());
218 + assertEquals("wrong subject", DID1, event.subject());
219 + assertEquals("wrong subject", N1, event.master());
220 + addLatch.countDown();
221 + }
222 + };
223 +
224 + dms.setDelegate(checkAdd);
225 + dms.setMaster(N1, DID1);
226 + //this will fail until we do something about single-instance-ness
227 + assertTrue("Add event fired", addLatch.await(1, TimeUnit.SECONDS));
228 + }
229 +
230 + private class TestDistributedMastershipStore extends
231 + DistributedMastershipStore {
232 + public TestDistributedMastershipStore(StoreService storeService,
233 + KryoSerializer kryoSerialization) {
234 + this.storeService = storeService;
235 + this.serializer = kryoSerialization;
236 + }
237 +
238 + //helper to populate master/backup structures
239 + public void put(DeviceId dev, NodeId node,
240 + boolean master, boolean backup, boolean term) {
241 + byte [] n = serialize(node);
242 + byte [] d = serialize(dev);
243 +
244 + if (master) {
245 + dms.masters.put(d, n);
246 + dms.unusable.put(d, n);
247 + dms.standbys.remove(d, n);
248 + }
249 + if (backup) {
250 + dms.standbys.put(d, n);
251 + dms.masters.remove(d, n);
252 + dms.unusable.remove(d, n);
253 + }
254 + if (term) {
255 + dms.terms.put(d, 0);
256 + }
257 + }
258 +
259 + //a dumb utility function.
260 + public void dump() {
261 + System.out.println("standbys");
262 + for (Map.Entry<byte [], byte []> e : standbys.entrySet()) {
263 + System.out.println(deserialize(e.getKey()) + ":" + deserialize(e.getValue()));
264 + }
265 + System.out.println("unusable");
266 + for (Map.Entry<byte [], byte []> e : unusable.entrySet()) {
267 + System.out.println(deserialize(e.getKey()) + ":" + deserialize(e.getValue()));
268 + }
269 + }
270 +
271 + //clears structures
272 + public void reset(boolean store, boolean backup, boolean term) {
273 + if (store) {
274 + dms.masters.clear();
275 + dms.unusable.clear();
276 + }
277 + if (backup) {
278 + dms.standbys.clear();
279 + }
280 + if (term) {
281 + dms.terms.clear();
282 + }
283 + }
284 +
285 + //increment term for a device
286 + public void increment(DeviceId dev) {
287 + Integer t = dms.terms.get(serialize(dev));
288 + if (t != null) {
289 + dms.terms.put(serialize(dev), ++t);
290 + }
291 + }
292 +
293 + //sets the "local" node
294 + public void setCurrent(ControllerNode node) {
295 + ((TestClusterService) clusterService).current = node;
296 + }
297 + }
298 +
299 + private class TestClusterService implements ClusterService {
300 +
301 + protected ControllerNode current;
302 +
303 + @Override
304 + public ControllerNode getLocalNode() {
305 + return current;
306 + }
307 +
308 + @Override
309 + public Set<ControllerNode> getNodes() {
310 + return Sets.newHashSet(CN1, CN2);
311 + }
312 +
313 + @Override
314 + public ControllerNode getNode(NodeId nodeId) {
315 + return null;
316 + }
317 +
318 + @Override
319 + public State getState(NodeId nodeId) {
320 + return null;
321 + }
322 +
323 + @Override
324 + public void addListener(ClusterEventListener listener) {
325 + }
326 +
327 + @Override
328 + public void removeListener(ClusterEventListener listener) {
329 + }
330 +
331 + }
332 +
333 +}
...@@ -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 }
......
...@@ -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 }
......
...@@ -174,7 +174,7 @@ public class SimpleMastershipStore ...@@ -174,7 +174,7 @@ public class SimpleMastershipStore
174 } 174 }
175 175
176 @Override 176 @Override
177 - public MastershipEvent unsetMaster(NodeId nodeId, DeviceId deviceId) { 177 + public MastershipEvent setStandby(NodeId nodeId, DeviceId deviceId) {
178 MastershipRole role = getRole(nodeId, deviceId); 178 MastershipRole role = getRole(nodeId, deviceId);
179 synchronized (this) { 179 synchronized (this) {
180 switch (role) { 180 switch (role) {
...@@ -214,4 +214,9 @@ public class SimpleMastershipStore ...@@ -214,4 +214,9 @@ public class SimpleMastershipStore
214 return backup; 214 return backup;
215 } 215 }
216 216
217 + @Override
218 + public MastershipEvent relinquishRole(NodeId nodeId, DeviceId deviceId) {
219 + return setStandby(nodeId, deviceId);
220 + }
221 +
217 } 222 }
......
...@@ -129,22 +129,22 @@ public class SimpleMastershipStoreTest { ...@@ -129,22 +129,22 @@ public class SimpleMastershipStoreTest {
129 public void unsetMaster() { 129 public void unsetMaster() {
130 //NONE - record backup but take no other action 130 //NONE - record backup but take no other action
131 put(DID1, N1, false, false); 131 put(DID1, N1, false, false);
132 - sms.unsetMaster(N1, DID1); 132 + sms.setStandby(N1, DID1);
133 assertTrue("not backed up", sms.backups.contains(N1)); 133 assertTrue("not backed up", sms.backups.contains(N1));
134 sms.termMap.clear(); 134 sms.termMap.clear();
135 - sms.unsetMaster(N1, DID1); 135 + sms.setStandby(N1, DID1);
136 assertTrue("term not set", sms.termMap.containsKey(DID1)); 136 assertTrue("term not set", sms.termMap.containsKey(DID1));
137 137
138 //no backup, MASTER 138 //no backup, MASTER
139 put(DID1, N1, true, true); 139 put(DID1, N1, true, true);
140 - assertNull("wrong event", sms.unsetMaster(N1, DID1)); 140 + assertNull("wrong event", sms.setStandby(N1, DID1));
141 assertNull("wrong node", sms.masterMap.get(DID1)); 141 assertNull("wrong node", sms.masterMap.get(DID1));
142 142
143 //backup, switch 143 //backup, switch
144 sms.masterMap.clear(); 144 sms.masterMap.clear();
145 put(DID1, N1, true, true); 145 put(DID1, N1, true, true);
146 put(DID2, N2, true, true); 146 put(DID2, N2, true, true);
147 - assertEquals("wrong event", MASTER_CHANGED, sms.unsetMaster(N1, DID1).type()); 147 + assertEquals("wrong event", MASTER_CHANGED, sms.setStandby(N1, DID1).type());
148 } 148 }
149 149
150 //helper to populate master/backup structures 150 //helper to populate master/backup structures
......
...@@ -981,11 +981,13 @@ class OFChannelHandler extends IdleStateAwareChannelHandler { ...@@ -981,11 +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 sw.removeConnectedSwitch(); 985 sw.removeConnectedSwitch();
985 } else { 986 } else {
986 // A duplicate was disconnected on this ChannelHandler, 987 // A duplicate was disconnected on this ChannelHandler,
987 // this is the same switch reconnecting, but the original state was 988 // this is the same switch reconnecting, but the original state was
988 // not cleaned up - XXX check liveness of original ChannelHandler 989 // not cleaned up - XXX check liveness of original ChannelHandler
990 + log.info("{}:duplicate found");
989 duplicateDpidFound = Boolean.FALSE; 991 duplicateDpidFound = Boolean.FALSE;
990 } 992 }
991 } else { 993 } else {
......
...@@ -307,9 +307,11 @@ public class OpenFlowControllerImpl implements OpenFlowController { ...@@ -307,9 +307,11 @@ public class OpenFlowControllerImpl implements OpenFlowController {
307 connectedSwitches.remove(dpid); 307 connectedSwitches.remove(dpid);
308 OpenFlowSwitch sw = activeMasterSwitches.remove(dpid); 308 OpenFlowSwitch sw = activeMasterSwitches.remove(dpid);
309 if (sw == null) { 309 if (sw == null) {
310 + log.warn("sw was null for {}", dpid);
310 sw = activeEqualSwitches.remove(dpid); 311 sw = activeEqualSwitches.remove(dpid);
311 } 312 }
312 for (OpenFlowSwitchListener l : ofSwitchListener) { 313 for (OpenFlowSwitchListener l : ofSwitchListener) {
314 + log.warn("removal for {}", dpid);
313 l.switchRemoved(dpid); 315 l.switchRemoved(dpid);
314 } 316 }
315 } 317 }
......
...@@ -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(controller.getSwitch(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 }
......
...@@ -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 #------------------------------------------------------------------------------ 1 #------------------------------------------------------------------------------
2 -# Echoes project-level directory if a Java file within is newer than its 2 +# Echoes project-level directory if a Java file within is newer than the
3 -# class file counterpart 3 +# target directory.
4 #------------------------------------------------------------------------------ 4 #------------------------------------------------------------------------------
5 5
6 javaFile=${1#*\/src\/*\/java/} 6 javaFile=${1#*\/src\/*\/java/}
...@@ -10,9 +10,7 @@ basename=${1/*\//} ...@@ -10,9 +10,7 @@ basename=${1/*\//}
10 10
11 src=${1/$javaFile/} 11 src=${1/$javaFile/}
12 project=${src/src*/} 12 project=${src/src*/}
13 -classFile=${javaFile/.java/.class} 13 +target=$project/target
14 14
15 -[ ${project}target/classes/$classFile -nt ${src}$javaFile -o \ 15 +[ $target -nt ${src}$javaFile ] || echo ${src/src*/}
16 - ${project}target/test-classes/$classFile -nt ${src}$javaFile ] \
17 - || echo ${src/src*/}
18 16
......
...@@ -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 +# 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"
...@@ -11,6 +11,7 @@ import org.apache.felix.scr.annotations.Deactivate; ...@@ -11,6 +11,7 @@ import org.apache.felix.scr.annotations.Deactivate;
11 import org.slf4j.Logger; 11 import org.slf4j.Logger;
12 import org.slf4j.LoggerFactory; 12 import org.slf4j.LoggerFactory;
13 13
14 +import com.codahale.metrics.ConsoleReporter;
14 import com.codahale.metrics.Counter; 15 import com.codahale.metrics.Counter;
15 import com.codahale.metrics.Gauge; 16 import com.codahale.metrics.Gauge;
16 import com.codahale.metrics.Histogram; 17 import com.codahale.metrics.Histogram;
...@@ -18,7 +19,6 @@ import com.codahale.metrics.Meter; ...@@ -18,7 +19,6 @@ import com.codahale.metrics.Meter;
18 import com.codahale.metrics.Metric; 19 import com.codahale.metrics.Metric;
19 import com.codahale.metrics.MetricFilter; 20 import com.codahale.metrics.MetricFilter;
20 import com.codahale.metrics.MetricRegistry; 21 import com.codahale.metrics.MetricRegistry;
21 -import com.codahale.metrics.Slf4jReporter;
22 import com.codahale.metrics.Timer; 22 import com.codahale.metrics.Timer;
23 23
24 /** 24 /**
...@@ -70,16 +70,20 @@ public final class MetricsManager implements MetricsService { ...@@ -70,16 +70,20 @@ public final class MetricsManager implements MetricsService {
70 /** 70 /**
71 * Default Reporter for this metrics manager. 71 * Default Reporter for this metrics manager.
72 */ 72 */
73 - private final Slf4jReporter reporter; 73 + //private final Slf4jReporter reporter;
74 + private final ConsoleReporter reporter;
74 75
75 public MetricsManager() { 76 public MetricsManager() {
76 this.metricsRegistry = new MetricRegistry(); 77 this.metricsRegistry = new MetricRegistry();
77 - this.reporter = Slf4jReporter.forRegistry(this.metricsRegistry) 78 +// this.reporter = Slf4jReporter.forRegistry(this.metricsRegistry)
78 - .outputTo(log) 79 +// .outputTo(log)
80 +// .convertRatesTo(TimeUnit.SECONDS)
81 +// .convertDurationsTo(TimeUnit.MICROSECONDS)
82 +// .build();
83 + this.reporter = ConsoleReporter.forRegistry(this.metricsRegistry)
79 .convertRatesTo(TimeUnit.SECONDS) 84 .convertRatesTo(TimeUnit.SECONDS)
80 - .convertDurationsTo(TimeUnit.NANOSECONDS) 85 + .convertDurationsTo(TimeUnit.MICROSECONDS)
81 .build(); 86 .build();
82 - reporter.start(1, TimeUnit.MINUTES);
83 } 87 }
84 88
85 @Activate 89 @Activate
......