Ayaka Koshibe

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

Showing 41 changed files with 1129 additions and 553 deletions
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<project xmlns="http://maven.apache.org/POM/4.0.0"
3 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
5 + <modelVersion>4.0.0</modelVersion>
6 +
7 + <parent>
8 + <groupId>org.onlab.onos</groupId>
9 + <artifactId>onos-apps</artifactId>
10 + <version>1.0.0-SNAPSHOT</version>
11 + <relativePath>../pom.xml</relativePath>
12 + </parent>
13 +
14 + <artifactId>onos-app-mobility</artifactId>
15 + <packaging>bundle</packaging>
16 +
17 + <description>ONOS simple Mobility app</description>
18 +
19 +</project>
1 +package org.onlab.onos.mobility;
2 +import static org.slf4j.LoggerFactory.getLogger;
3 +
4 +import java.util.Collection;
5 +import java.util.List;
6 +
7 +import org.apache.felix.scr.annotations.Activate;
8 +import org.apache.felix.scr.annotations.Component;
9 +import org.apache.felix.scr.annotations.Deactivate;
10 +import org.apache.felix.scr.annotations.Reference;
11 +import org.apache.felix.scr.annotations.ReferenceCardinality;
12 +import org.onlab.onos.ApplicationId;
13 +import org.onlab.onos.net.Device;
14 +import org.onlab.onos.net.Host;
15 +import org.onlab.onos.net.device.DeviceService;
16 +import org.onlab.onos.net.flow.FlowRule;
17 +import org.onlab.onos.net.flow.FlowRuleService;
18 +import org.onlab.onos.net.flow.criteria.Criteria.EthCriterion;
19 +import org.onlab.onos.net.flow.criteria.Criterion;
20 +import org.onlab.onos.net.flow.criteria.Criterion.Type;
21 +import org.onlab.onos.net.host.HostEvent;
22 +import org.onlab.onos.net.host.HostListener;
23 +import org.onlab.onos.net.host.HostService;
24 +import org.onlab.packet.MacAddress;
25 +import org.slf4j.Logger;
26 +
27 +import com.google.common.collect.Lists;
28 +
29 +
30 +/**
31 + * Sample mobility application. Cleans up flowmods when a host moves.
32 + */
33 +@Component(immediate = true)
34 +public class HostMobility {
35 +
36 + private final Logger log = getLogger(getClass());
37 +
38 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
39 + protected HostService hostService;
40 +
41 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
42 + protected FlowRuleService flowRuleService;
43 +
44 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
45 + protected DeviceService deviceService;
46 +
47 + private ApplicationId appId;
48 +
49 + @Activate
50 + public void activate() {
51 + appId = ApplicationId.getAppId();
52 + hostService.addListener(new InternalHostListener());
53 + log.info("Started with Application ID {}", appId.id());
54 + }
55 +
56 + @Deactivate
57 + public void deactivate() {
58 + flowRuleService.removeFlowRulesById(appId);
59 + log.info("Stopped");
60 + }
61 +
62 + public class InternalHostListener
63 + implements HostListener {
64 +
65 + @Override
66 + public void event(HostEvent event) {
67 + switch (event.type()) {
68 + case HOST_ADDED:
69 + case HOST_REMOVED:
70 + case HOST_UPDATED:
71 + // don't care if a host has been added, removed.
72 + break;
73 + case HOST_MOVED:
74 + log.info("Host {} has moved; cleaning up.", event.subject());
75 + cleanup(event.subject());
76 + break;
77 +
78 + default:
79 + break;
80 +
81 + }
82 +
83 + }
84 +
85 + /**
86 + * For a given host, remove any flow rule which references it's addresses.
87 + * @param host the host to clean up for
88 + */
89 + private void cleanup(Host host) {
90 + Iterable<Device> devices = deviceService.getDevices();
91 + List<FlowRule> flowRules = Lists.newLinkedList();
92 + for (Device device : devices) {
93 + flowRules.addAll(cleanupDevice(device, host));
94 + }
95 + FlowRule[] flows = new FlowRule[flowRules.size()];
96 + flows = flowRules.toArray(flows);
97 + flowRuleService.removeFlowRules(flows);
98 + }
99 +
100 + private Collection<? extends FlowRule> cleanupDevice(Device device, Host host) {
101 + List<FlowRule> flowRules = Lists.newLinkedList();
102 + MacAddress mac = host.mac();
103 + for (FlowRule rule : flowRuleService.getFlowEntries(device.id())) {
104 + for (Criterion c : rule.selector().criteria()) {
105 + if (c.type() == Type.ETH_DST || c.type() == Type.ETH_SRC) {
106 + EthCriterion eth = (EthCriterion) c;
107 + if (eth.mac().equals(mac)) {
108 + flowRules.add(rule);
109 + }
110 + }
111 + }
112 + }
113 + //TODO: handle ip cleanup
114 + return flowRules;
115 + }
116 +
117 + }
118 +
119 +}
120 +
121 +
1 +/**
2 + * Trivial application that provides simple form of reactive forwarding.
3 + */
4 +package org.onlab.onos.mobility;
...@@ -20,7 +20,8 @@ ...@@ -20,7 +20,8 @@
20 <module>tvue</module> 20 <module>tvue</module>
21 <module>fwd</module> 21 <module>fwd</module>
22 <module>foo</module> 22 <module>foo</module>
23 - <module>config</module> 23 + <module>mobility</module>
24 + <module>config</module>
24 </modules> 25 </modules>
25 26
26 <properties> 27 <properties>
......
...@@ -161,7 +161,7 @@ implements FlowRuleService, FlowRuleProviderRegistry { ...@@ -161,7 +161,7 @@ implements FlowRuleService, FlowRuleProviderRegistry {
161 switch (stored.state()) { 161 switch (stored.state()) {
162 case ADDED: 162 case ADDED:
163 case PENDING_ADD: 163 case PENDING_ADD:
164 - frp.applyFlowRule(flowRule); 164 + frp.applyFlowRule(stored);
165 break; 165 break;
166 case PENDING_REMOVE: 166 case PENDING_REMOVE:
167 case REMOVED: 167 case REMOVED:
......
1 +package org.onlab.onos.store.cluster.impl;
2 +
3 +import org.onlab.onos.cluster.DefaultControllerNode;
4 +
5 +/**
6 + * Service for administering communications manager.
7 + */
8 +public interface ClusterCommunicationAdminService {
9 +
10 + /**
11 + * Adds the node to the list of monitored nodes.
12 + *
13 + * @param node node to be added
14 + */
15 + void addNode(DefaultControllerNode node);
16 +
17 + /**
18 + * Removes the node from the list of monitored nodes.
19 + *
20 + * @param node node to be removed
21 + */
22 + void removeNode(DefaultControllerNode node);
23 +
24 + /**
25 + * Starts-up the communications engine.
26 + *
27 + * @param localNode local controller node
28 + * @param delegate nodes delegate
29 + */
30 + void startUp(DefaultControllerNode localNode, ClusterNodesDelegate delegate);
31 +
32 + /**
33 + * Clears all nodes and streams as part of leaving the cluster.
34 + */
35 + void clearAllNodesAndStreams();
36 +}
1 +package org.onlab.onos.store.cluster.impl;
2 +
3 +import com.google.common.collect.HashMultimap;
4 +import com.google.common.collect.ImmutableSet;
5 +import com.google.common.collect.Multimap;
6 +import org.apache.felix.scr.annotations.Activate;
7 +import org.apache.felix.scr.annotations.Component;
8 +import org.apache.felix.scr.annotations.Deactivate;
9 +import org.apache.felix.scr.annotations.Reference;
10 +import org.apache.felix.scr.annotations.ReferenceCardinality;
11 +import org.apache.felix.scr.annotations.Service;
12 +import org.onlab.onos.cluster.DefaultControllerNode;
13 +import org.onlab.onos.cluster.NodeId;
14 +import org.onlab.onos.store.cluster.messaging.ClusterCommunicationService;
15 +import org.onlab.onos.store.cluster.messaging.ClusterMembershipMessage;
16 +import org.onlab.onos.store.cluster.messaging.ClusterMessage;
17 +import org.onlab.onos.store.cluster.messaging.HelloMessage;
18 +import org.onlab.onos.store.cluster.messaging.LeavingMemberMessage;
19 +import org.onlab.onos.store.cluster.messaging.MessageSubject;
20 +import org.onlab.onos.store.cluster.messaging.MessageSubscriber;
21 +import org.onlab.onos.store.cluster.messaging.NewMemberMessage;
22 +import org.onlab.onos.store.cluster.messaging.SerializationService;
23 +import org.onlab.packet.IpPrefix;
24 +import org.slf4j.Logger;
25 +import org.slf4j.LoggerFactory;
26 +
27 +import java.io.IOException;
28 +import java.net.InetSocketAddress;
29 +import java.net.SocketAddress;
30 +import java.nio.channels.SocketChannel;
31 +import java.util.ArrayList;
32 +import java.util.HashSet;
33 +import java.util.List;
34 +import java.util.Map;
35 +import java.util.Set;
36 +import java.util.Timer;
37 +import java.util.TimerTask;
38 +import java.util.concurrent.ConcurrentHashMap;
39 +import java.util.concurrent.ExecutorService;
40 +import java.util.concurrent.Executors;
41 +
42 +import static java.net.InetAddress.getByAddress;
43 +import static org.onlab.util.Tools.namedThreads;
44 +
45 +/**
46 + * Implements the cluster communication services to use by other stores.
47 + */
48 +@Component(immediate = true)
49 +@Service
50 +public class ClusterCommunicationManager
51 + implements ClusterCommunicationService, ClusterCommunicationAdminService {
52 +
53 + private final Logger log = LoggerFactory.getLogger(getClass());
54 +
55 + private static final long CONNECTION_CUSTODIAN_DELAY = 100L;
56 + private static final long CONNECTION_CUSTODIAN_FREQUENCY = 2000;
57 +
58 + private static final long START_TIMEOUT = 1000;
59 + private static final int WORKERS = 3;
60 +
61 + private ClusterConnectionListener connectionListener;
62 + private List<ClusterIOWorker> workers = new ArrayList<>(WORKERS);
63 +
64 + private DefaultControllerNode localNode;
65 + private ClusterNodesDelegate nodesDelegate;
66 +
67 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
68 + protected SerializationService serializationService;
69 +
70 + // Nodes to be monitored to make sure they have a connection.
71 + private final Set<DefaultControllerNode> nodes = new HashSet<>();
72 +
73 + // Means to track message streams to other nodes.
74 + private final Map<NodeId, ClusterMessageStream> streams = new ConcurrentHashMap<>();
75 +
76 + // TODO: use something different that won't require synchronization
77 + private Multimap<MessageSubject, MessageSubscriber> subscribers = HashMultimap.create();
78 +
79 + // Executor pools for listening and managing connections to other nodes.
80 + private final ExecutorService listenExecutor =
81 + Executors.newSingleThreadExecutor(namedThreads("onos-comm-listen"));
82 + private final ExecutorService commExecutors =
83 + Executors.newFixedThreadPool(WORKERS, namedThreads("onos-comm-cluster"));
84 + private final ExecutorService heartbeatExecutor =
85 + Executors.newSingleThreadExecutor(namedThreads("onos-comm-heartbeat"));
86 +
87 + private final Timer timer = new Timer("onos-comm-initiator");
88 + private final TimerTask connectionCustodian = new ConnectionCustodian();
89 + private MembershipSubscriber membershipSubscriber = new MembershipSubscriber();
90 +
91 + @Activate
92 + public void activate() {
93 + addSubscriber(MessageSubject.NEW_MEMBER, membershipSubscriber);
94 + addSubscriber(MessageSubject.LEAVING_MEMBER, membershipSubscriber);
95 + log.info("Activated but waiting for delegate");
96 + }
97 +
98 + @Deactivate
99 + public void deactivate() {
100 + removeSubscriber(MessageSubject.NEW_MEMBER, membershipSubscriber);
101 + removeSubscriber(MessageSubject.LEAVING_MEMBER, membershipSubscriber);
102 +
103 + connectionCustodian.cancel();
104 + if (connectionListener != null) {
105 + connectionListener.shutdown();
106 + for (ClusterIOWorker worker : workers) {
107 + worker.shutdown();
108 + }
109 + }
110 + log.info("Stopped");
111 + }
112 +
113 + @Override
114 + public boolean send(ClusterMessage message) {
115 + boolean ok = true;
116 + for (DefaultControllerNode node : nodes) {
117 + if (!node.equals(localNode)) {
118 + ok = send(message, node.id()) && ok;
119 + }
120 + }
121 + return ok;
122 + }
123 +
124 + @Override
125 + public boolean send(ClusterMessage message, NodeId toNodeId) {
126 + ClusterMessageStream stream = streams.get(toNodeId);
127 + if (stream != null && !toNodeId.equals(localNode.id())) {
128 + try {
129 + stream.write(message);
130 + return true;
131 + } catch (IOException e) {
132 + log.warn("Unable to send message {} to node {}",
133 + message.subject(), toNodeId);
134 + }
135 + }
136 + return false;
137 + }
138 +
139 + @Override
140 + public synchronized void addSubscriber(MessageSubject subject,
141 + MessageSubscriber subscriber) {
142 + subscribers.put(subject, subscriber);
143 + }
144 +
145 + @Override
146 + public synchronized void removeSubscriber(MessageSubject subject,
147 + MessageSubscriber subscriber) {
148 + subscribers.remove(subject, subscriber);
149 + }
150 +
151 + @Override
152 + public Set<MessageSubscriber> getSubscribers(MessageSubject subject) {
153 + return ImmutableSet.copyOf(subscribers.get(subject));
154 + }
155 +
156 + @Override
157 + public void addNode(DefaultControllerNode node) {
158 + nodes.add(node);
159 + }
160 +
161 + @Override
162 + public void removeNode(DefaultControllerNode node) {
163 + send(new LeavingMemberMessage(node.id()));
164 + nodes.remove(node);
165 + ClusterMessageStream stream = streams.remove(node.id());
166 + if (stream != null) {
167 + stream.close();
168 + }
169 + }
170 +
171 + @Override
172 + public void startUp(DefaultControllerNode localNode,
173 + ClusterNodesDelegate delegate) {
174 + this.localNode = localNode;
175 + this.nodesDelegate = delegate;
176 +
177 + startCommunications();
178 + startListening();
179 + startInitiatingConnections();
180 + log.info("Started");
181 + }
182 +
183 + @Override
184 + public void clearAllNodesAndStreams() {
185 + nodes.clear();
186 + send(new LeavingMemberMessage(localNode.id()));
187 + for (ClusterMessageStream stream : streams.values()) {
188 + stream.close();
189 + }
190 + streams.clear();
191 + }
192 +
193 + /**
194 + * Dispatches the specified message to all subscribers to its subject.
195 + *
196 + * @param message message to dispatch
197 + * @param fromNodeId node from which the message was received
198 + */
199 + void dispatch(ClusterMessage message, NodeId fromNodeId) {
200 + Set<MessageSubscriber> set = getSubscribers(message.subject());
201 + if (set != null) {
202 + for (MessageSubscriber subscriber : set) {
203 + subscriber.receive(message, fromNodeId);
204 + }
205 + }
206 + }
207 +
208 + /**
209 + * Adds the stream associated with the specified node.
210 + *
211 + * @param nodeId newly detected cluster node id
212 + * @param ip node IP listen address
213 + * @param tcpPort node TCP listen port
214 + * @return controller node bound to the stream
215 + */
216 + DefaultControllerNode addNodeStream(NodeId nodeId, IpPrefix ip, int tcpPort,
217 + ClusterMessageStream stream) {
218 + DefaultControllerNode node = nodesDelegate.nodeDetected(nodeId, ip, tcpPort);
219 + stream.setNode(node);
220 + streams.put(node.id(), stream);
221 + send(new NewMemberMessage(node.id(), node.ip(), node.tcpPort()));
222 + return node;
223 + }
224 +
225 + /**
226 + * Removes the stream associated with the specified node.
227 + *
228 + * @param node node whose stream to remove
229 + */
230 + void removeNodeStream(DefaultControllerNode node) {
231 + nodesDelegate.nodeVanished(node.id());
232 + streams.remove(node.id());
233 + }
234 +
235 + /**
236 + * Finds the least utilized IO worker.
237 + *
238 + * @return IO worker
239 + */
240 + ClusterIOWorker findWorker() {
241 + ClusterIOWorker leastUtilized = null;
242 + int minCount = Integer.MAX_VALUE;
243 + for (ClusterIOWorker worker : workers) {
244 + int count = worker.streamCount();
245 + if (count == 0) {
246 + return worker;
247 + }
248 +
249 + if (count < minCount) {
250 + leastUtilized = worker;
251 + minCount = count;
252 + }
253 + }
254 + return leastUtilized;
255 + }
256 +
257 + /**
258 + * Kicks off the IO loops and waits for them to startup.
259 + */
260 + private void startCommunications() {
261 + HelloMessage hello = new HelloMessage(localNode.id(), localNode.ip(),
262 + localNode.tcpPort());
263 + for (int i = 0; i < WORKERS; i++) {
264 + try {
265 + ClusterIOWorker worker =
266 + new ClusterIOWorker(this, serializationService, hello);
267 + workers.add(worker);
268 + commExecutors.execute(worker);
269 + } catch (IOException e) {
270 + log.warn("Unable to start communication worker", e);
271 + }
272 + }
273 +
274 + // Wait for the IO loops to start
275 + for (ClusterIOWorker loop : workers) {
276 + if (!loop.awaitStart(START_TIMEOUT)) {
277 + log.warn("Comm loop did not start on-time; moving on...");
278 + }
279 + }
280 + }
281 +
282 + /**
283 + * Starts listening for connections from peer cluster members.
284 + */
285 + private void startListening() {
286 + try {
287 + connectionListener =
288 + new ClusterConnectionListener(this, localNode.ip(), localNode.tcpPort());
289 + listenExecutor.execute(connectionListener);
290 + if (!connectionListener.awaitStart(START_TIMEOUT)) {
291 + log.warn("Listener did not start on-time; moving on...");
292 + }
293 + } catch (IOException e) {
294 + log.error("Unable to listen for cluster connections", e);
295 + }
296 + }
297 +
298 + /**
299 + * Attempts to connect to any nodes that do not have an associated connection.
300 + */
301 + private void startInitiatingConnections() {
302 + timer.schedule(connectionCustodian, CONNECTION_CUSTODIAN_DELAY,
303 + CONNECTION_CUSTODIAN_FREQUENCY);
304 + }
305 +
306 + /**
307 + * Initiates open connection request and registers the pending socket
308 + * channel with the given IO worker.
309 + *
310 + * @param worker loop with which the channel should be registered
311 + * @throws java.io.IOException if the socket could not be open or connected
312 + */
313 + private void initiateConnection(DefaultControllerNode node,
314 + ClusterIOWorker worker) throws IOException {
315 + SocketAddress sa = new InetSocketAddress(getByAddress(node.ip().toOctets()), node.tcpPort());
316 + SocketChannel ch = SocketChannel.open();
317 + ch.configureBlocking(false);
318 + ch.connect(sa);
319 + worker.connectStream(ch);
320 + }
321 +
322 + // Sweeps through all controller nodes and attempts to open connection to
323 + // those that presently do not have one.
324 + private class ConnectionCustodian extends TimerTask {
325 + @Override
326 + public void run() {
327 + for (DefaultControllerNode node : nodes) {
328 + if (!node.id().equals(localNode.id()) && !streams.containsKey(node.id())) {
329 + try {
330 + initiateConnection(node, findWorker());
331 + } catch (IOException e) {
332 + log.debug("Unable to connect", e);
333 + }
334 + }
335 + }
336 + }
337 + }
338 +
339 + private class MembershipSubscriber implements MessageSubscriber {
340 + @Override
341 + public void receive(ClusterMessage message, NodeId fromNodeId) {
342 + MessageSubject subject = message.subject();
343 + ClusterMembershipMessage cmm = (ClusterMembershipMessage) message;
344 + if (message.subject() == MessageSubject.NEW_MEMBER) {
345 + log.info("Node {} arrived", cmm.nodeId());
346 + nodesDelegate.nodeDetected(cmm.nodeId(), cmm.ipAddress(), cmm.tcpPort());
347 +
348 + } else if (subject == MessageSubject.LEAVING_MEMBER) {
349 + log.info("Node {} is leaving", cmm.nodeId());
350 + nodesDelegate.nodeRemoved(cmm.nodeId());
351 + }
352 + }
353 + }
354 +}
...@@ -23,12 +23,12 @@ public class ClusterConnectionListener extends AcceptorLoop { ...@@ -23,12 +23,12 @@ public class ClusterConnectionListener extends AcceptorLoop {
23 private static final int SO_SEND_BUFFER_SIZE = COMM_BUFFER_SIZE; 23 private static final int SO_SEND_BUFFER_SIZE = COMM_BUFFER_SIZE;
24 private static final int SO_RCV_BUFFER_SIZE = COMM_BUFFER_SIZE; 24 private static final int SO_RCV_BUFFER_SIZE = COMM_BUFFER_SIZE;
25 25
26 - private final WorkerFinder workerFinder; 26 + private final ClusterCommunicationManager manager;
27 27
28 - ClusterConnectionListener(IpPrefix ip, int tcpPort, 28 + ClusterConnectionListener(ClusterCommunicationManager manager,
29 - WorkerFinder workerFinder) throws IOException { 29 + IpPrefix ip, int tcpPort) throws IOException {
30 super(SELECT_TIMEOUT, new InetSocketAddress(getByAddress(ip.toOctets()), tcpPort)); 30 super(SELECT_TIMEOUT, new InetSocketAddress(getByAddress(ip.toOctets()), tcpPort));
31 - this.workerFinder = workerFinder; 31 + this.manager = manager;
32 } 32 }
33 33
34 @Override 34 @Override
...@@ -41,7 +41,7 @@ public class ClusterConnectionListener extends AcceptorLoop { ...@@ -41,7 +41,7 @@ public class ClusterConnectionListener extends AcceptorLoop {
41 so.setReceiveBufferSize(SO_RCV_BUFFER_SIZE); 41 so.setReceiveBufferSize(SO_RCV_BUFFER_SIZE);
42 so.setSendBufferSize(SO_SEND_BUFFER_SIZE); 42 so.setSendBufferSize(SO_SEND_BUFFER_SIZE);
43 43
44 - workerFinder.findWorker().acceptStream(sc); 44 + manager.findWorker().acceptStream(sc);
45 } 45 }
46 46
47 } 47 }
......
...@@ -3,8 +3,9 @@ package org.onlab.onos.store.cluster.impl; ...@@ -3,8 +3,9 @@ package org.onlab.onos.store.cluster.impl;
3 import org.onlab.nio.IOLoop; 3 import org.onlab.nio.IOLoop;
4 import org.onlab.nio.MessageStream; 4 import org.onlab.nio.MessageStream;
5 import org.onlab.onos.cluster.DefaultControllerNode; 5 import org.onlab.onos.cluster.DefaultControllerNode;
6 +import org.onlab.onos.cluster.NodeId;
6 import org.onlab.onos.store.cluster.messaging.ClusterMessage; 7 import org.onlab.onos.store.cluster.messaging.ClusterMessage;
7 -import org.onlab.onos.store.cluster.messaging.ClusterMessageStream; 8 +import org.onlab.onos.store.cluster.messaging.HelloMessage;
8 import org.onlab.onos.store.cluster.messaging.SerializationService; 9 import org.onlab.onos.store.cluster.messaging.SerializationService;
9 import org.slf4j.Logger; 10 import org.slf4j.Logger;
10 import org.slf4j.LoggerFactory; 11 import org.slf4j.LoggerFactory;
...@@ -29,27 +30,23 @@ public class ClusterIOWorker extends ...@@ -29,27 +30,23 @@ public class ClusterIOWorker extends
29 30
30 private static final long SELECT_TIMEOUT = 50; 31 private static final long SELECT_TIMEOUT = 50;
31 32
32 - private final ConnectionManager connectionManager; 33 + private final ClusterCommunicationManager manager;
33 - private final CommunicationsDelegate commsDelegate;
34 private final SerializationService serializationService; 34 private final SerializationService serializationService;
35 private final ClusterMessage helloMessage; 35 private final ClusterMessage helloMessage;
36 36
37 /** 37 /**
38 * Creates a new cluster IO worker. 38 * Creates a new cluster IO worker.
39 * 39 *
40 - * @param connectionManager parent connection manager 40 + * @param manager parent comms manager
41 - * @param commsDelegate communications delegate for dispatching
42 * @param serializationService serialization service for encode/decode 41 * @param serializationService serialization service for encode/decode
43 * @param helloMessage hello message for greeting peers 42 * @param helloMessage hello message for greeting peers
44 * @throws IOException if errors occur during IO loop ignition 43 * @throws IOException if errors occur during IO loop ignition
45 */ 44 */
46 - ClusterIOWorker(ConnectionManager connectionManager, 45 + ClusterIOWorker(ClusterCommunicationManager manager,
47 - CommunicationsDelegate commsDelegate,
48 SerializationService serializationService, 46 SerializationService serializationService,
49 ClusterMessage helloMessage) throws IOException { 47 ClusterMessage helloMessage) throws IOException {
50 super(SELECT_TIMEOUT); 48 super(SELECT_TIMEOUT);
51 - this.connectionManager = connectionManager; 49 + this.manager = manager;
52 - this.commsDelegate = commsDelegate;
53 this.serializationService = serializationService; 50 this.serializationService = serializationService;
54 this.helloMessage = helloMessage; 51 this.helloMessage = helloMessage;
55 } 52 }
...@@ -61,11 +58,27 @@ public class ClusterIOWorker extends ...@@ -61,11 +58,27 @@ public class ClusterIOWorker extends
61 58
62 @Override 59 @Override
63 protected void processMessages(List<ClusterMessage> messages, MessageStream<ClusterMessage> stream) { 60 protected void processMessages(List<ClusterMessage> messages, MessageStream<ClusterMessage> stream) {
61 + NodeId nodeId = getNodeId(messages, (ClusterMessageStream) stream);
64 for (ClusterMessage message : messages) { 62 for (ClusterMessage message : messages) {
65 - commsDelegate.dispatch(message); 63 + manager.dispatch(message, nodeId);
66 } 64 }
67 } 65 }
68 66
67 + // Retrieves the node from the stream. If one is not bound, it attempts
68 + // to bind it using the knowledge that the first message must be a hello.
69 + private NodeId getNodeId(List<ClusterMessage> messages, ClusterMessageStream stream) {
70 + DefaultControllerNode node = stream.node();
71 + if (node == null && !messages.isEmpty()) {
72 + ClusterMessage firstMessage = messages.get(0);
73 + if (firstMessage instanceof HelloMessage) {
74 + HelloMessage hello = (HelloMessage) firstMessage;
75 + node = manager.addNodeStream(hello.nodeId(), hello.ipAddress(),
76 + hello.tcpPort(), stream);
77 + }
78 + }
79 + return node != null ? node.id() : null;
80 + }
81 +
69 @Override 82 @Override
70 public ClusterMessageStream acceptStream(SocketChannel channel) { 83 public ClusterMessageStream acceptStream(SocketChannel channel) {
71 ClusterMessageStream stream = super.acceptStream(channel); 84 ClusterMessageStream stream = super.acceptStream(channel);
...@@ -99,7 +112,7 @@ public class ClusterIOWorker extends ...@@ -99,7 +112,7 @@ public class ClusterIOWorker extends
99 DefaultControllerNode node = ((ClusterMessageStream) stream).node(); 112 DefaultControllerNode node = ((ClusterMessageStream) stream).node();
100 if (node != null) { 113 if (node != null) {
101 log.info("Closed connection to node {}", node.id()); 114 log.info("Closed connection to node {}", node.id());
102 - connectionManager.removeNodeStream(node); 115 + manager.removeNodeStream(node);
103 } 116 }
104 super.removeStream(stream); 117 super.removeStream(stream);
105 } 118 }
......
1 -package org.onlab.onos.store.cluster.messaging; 1 +package org.onlab.onos.store.cluster.impl;
2 2
3 import org.onlab.nio.IOLoop; 3 import org.onlab.nio.IOLoop;
4 import org.onlab.nio.MessageStream; 4 import org.onlab.nio.MessageStream;
5 import org.onlab.onos.cluster.DefaultControllerNode; 5 import org.onlab.onos.cluster.DefaultControllerNode;
6 +import org.onlab.onos.store.cluster.messaging.ClusterMessage;
7 +import org.onlab.onos.store.cluster.messaging.SerializationService;
6 8
7 import java.nio.ByteBuffer; 9 import java.nio.ByteBuffer;
8 import java.nio.channels.ByteChannel; 10 import java.nio.channels.ByteChannel;
......
1 package org.onlab.onos.store.cluster.impl; 1 package org.onlab.onos.store.cluster.impl;
2 2
3 import org.onlab.onos.cluster.DefaultControllerNode; 3 import org.onlab.onos.cluster.DefaultControllerNode;
4 +import org.onlab.onos.cluster.NodeId;
5 +import org.onlab.packet.IpPrefix;
4 6
5 /** 7 /**
6 * Simple back interface through which connection manager can interact with 8 * Simple back interface through which connection manager can interact with
...@@ -9,17 +11,27 @@ import org.onlab.onos.cluster.DefaultControllerNode; ...@@ -9,17 +11,27 @@ import org.onlab.onos.cluster.DefaultControllerNode;
9 public interface ClusterNodesDelegate { 11 public interface ClusterNodesDelegate {
10 12
11 /** 13 /**
12 - * Notifies about a new cluster node being detected. 14 + * Notifies about cluster node coming online.
13 * 15 *
14 - * @param node newly detected cluster node 16 + * @param nodeId newly detected cluster node id
17 + * @param ip node IP listen address
18 + * @param tcpPort node TCP listen port
19 + * @return the controller node
15 */ 20 */
16 - void nodeDetected(DefaultControllerNode node); 21 + DefaultControllerNode nodeDetected(NodeId nodeId, IpPrefix ip, int tcpPort);
17 22
18 /** 23 /**
19 * Notifies about cluster node going offline. 24 * Notifies about cluster node going offline.
20 * 25 *
21 - * @param node cluster node that vanished 26 + * @param nodeId identifier of the cluster node that vanished
22 */ 27 */
23 - void nodeVanished(DefaultControllerNode node); 28 + void nodeVanished(NodeId nodeId);
29 +
30 + /**
31 + * Notifies about remote request to remove node from cluster.
32 + *
33 + * @param nodeId identifier of the cluster node that was removed
34 + */
35 + void nodeRemoved(NodeId nodeId);
24 36
25 } 37 }
......
1 -package org.onlab.onos.store.cluster.impl;
2 -
3 -import org.onlab.onos.store.cluster.messaging.ClusterMessage;
4 -
5 -/**
6 - * Simple back interface for interacting with the communications service.
7 - */
8 -public interface CommunicationsDelegate {
9 -
10 - /**
11 - * Dispatches the specified message to all registered subscribers.
12 - *
13 - * @param message message to be dispatched
14 - */
15 - void dispatch(ClusterMessage message);
16 -
17 - /**
18 - * Sets the sender.
19 - *
20 - * @param messageSender message sender
21 - */
22 - void setSender(MessageSender messageSender);
23 -
24 -}
1 -package org.onlab.onos.store.cluster.impl;
2 -
3 -import org.onlab.onos.cluster.DefaultControllerNode;
4 -import org.onlab.onos.cluster.NodeId;
5 -import org.onlab.onos.store.cluster.messaging.ClusterMessage;
6 -import org.onlab.onos.store.cluster.messaging.ClusterMessageStream;
7 -import org.onlab.onos.store.cluster.messaging.HelloMessage;
8 -import org.onlab.onos.store.cluster.messaging.SerializationService;
9 -import org.slf4j.Logger;
10 -import org.slf4j.LoggerFactory;
11 -
12 -import java.io.IOException;
13 -import java.net.InetSocketAddress;
14 -import java.net.SocketAddress;
15 -import java.nio.channels.SocketChannel;
16 -import java.util.ArrayList;
17 -import java.util.HashSet;
18 -import java.util.List;
19 -import java.util.Map;
20 -import java.util.Set;
21 -import java.util.Timer;
22 -import java.util.TimerTask;
23 -import java.util.concurrent.ConcurrentHashMap;
24 -import java.util.concurrent.ExecutorService;
25 -import java.util.concurrent.Executors;
26 -
27 -import static java.net.InetAddress.getByAddress;
28 -import static org.onlab.util.Tools.namedThreads;
29 -
30 -/**
31 - * Manages connections to other controller cluster nodes.
32 - */
33 -public class ConnectionManager implements MessageSender {
34 -
35 - private final Logger log = LoggerFactory.getLogger(getClass());
36 -
37 - private static final long CONNECTION_CUSTODIAN_DELAY = 1000L;
38 - private static final long CONNECTION_CUSTODIAN_FREQUENCY = 5000;
39 -
40 - private static final long START_TIMEOUT = 1000;
41 - private static final int WORKERS = 3;
42 -
43 - private ClusterConnectionListener connectionListener;
44 - private List<ClusterIOWorker> workers = new ArrayList<>(WORKERS);
45 -
46 - private final DefaultControllerNode localNode;
47 - private final ClusterNodesDelegate nodesDelegate;
48 - private final CommunicationsDelegate commsDelegate;
49 - private final SerializationService serializationService;
50 -
51 - // Nodes to be monitored to make sure they have a connection.
52 - private final Set<DefaultControllerNode> nodes = new HashSet<>();
53 -
54 - // Means to track message streams to other nodes.
55 - private final Map<NodeId, ClusterMessageStream> streams = new ConcurrentHashMap<>();
56 -
57 - // Executor pools for listening and managing connections to other nodes.
58 - private final ExecutorService listenExecutor =
59 - Executors.newSingleThreadExecutor(namedThreads("onos-comm-listen"));
60 - private final ExecutorService commExecutors =
61 - Executors.newFixedThreadPool(WORKERS, namedThreads("onos-comm-cluster"));
62 - private final ExecutorService heartbeatExecutor =
63 - Executors.newSingleThreadExecutor(namedThreads("onos-comm-heartbeat"));
64 -
65 - private final Timer timer = new Timer("onos-comm-initiator");
66 - private final TimerTask connectionCustodian = new ConnectionCustodian();
67 -
68 - private final WorkerFinder workerFinder = new LeastUtilitiedWorkerFinder();
69 -
70 -
71 - /**
72 - * Creates a new connection manager.
73 - */
74 - ConnectionManager(DefaultControllerNode localNode,
75 - ClusterNodesDelegate nodesDelegate,
76 - CommunicationsDelegate commsDelegate,
77 - SerializationService serializationService) {
78 - this.localNode = localNode;
79 - this.nodesDelegate = nodesDelegate;
80 - this.commsDelegate = commsDelegate;
81 - this.serializationService = serializationService;
82 -
83 - commsDelegate.setSender(this);
84 - startCommunications();
85 - startListening();
86 - startInitiating();
87 - log.info("Started");
88 - }
89 -
90 - /**
91 - * Shuts down the connection manager.
92 - */
93 - void shutdown() {
94 - connectionListener.shutdown();
95 - for (ClusterIOWorker worker : workers) {
96 - worker.shutdown();
97 - }
98 - log.info("Stopped");
99 - }
100 -
101 - /**
102 - * Adds the node to the list of monitored nodes.
103 - *
104 - * @param node node to be added
105 - */
106 - void addNode(DefaultControllerNode node) {
107 - nodes.add(node);
108 - }
109 -
110 - /**
111 - * Removes the node from the list of monitored nodes.
112 - *
113 - * @param node node to be removed
114 - */
115 - void removeNode(DefaultControllerNode node) {
116 - nodes.remove(node);
117 - ClusterMessageStream stream = streams.remove(node.id());
118 - if (stream != null) {
119 - stream.close();
120 - }
121 - }
122 -
123 - /**
124 - * Removes the stream associated with the specified node.
125 - *
126 - * @param node node whose stream to remove
127 - */
128 - void removeNodeStream(DefaultControllerNode node) {
129 - nodesDelegate.nodeVanished(node);
130 - streams.remove(node.id());
131 - }
132 -
133 - @Override
134 - public boolean send(NodeId nodeId, ClusterMessage message) {
135 - ClusterMessageStream stream = streams.get(nodeId);
136 - if (stream != null) {
137 - try {
138 - stream.write(message);
139 - return true;
140 - } catch (IOException e) {
141 - log.warn("Unable to send a message about {} to node {}",
142 - message.subject(), nodeId);
143 - }
144 - }
145 - return false;
146 - }
147 -
148 - /**
149 - * Kicks off the IO loops and waits for them to startup.
150 - */
151 - private void startCommunications() {
152 - HelloMessage hello = new HelloMessage(localNode.id(), localNode.ip(),
153 - localNode.tcpPort());
154 - for (int i = 0; i < WORKERS; i++) {
155 - try {
156 - ClusterIOWorker worker =
157 - new ClusterIOWorker(this, commsDelegate,
158 - serializationService, hello);
159 - workers.add(worker);
160 - commExecutors.execute(worker);
161 - } catch (IOException e) {
162 - log.warn("Unable to start communication worker", e);
163 - }
164 - }
165 -
166 - // Wait for the IO loops to start
167 - for (ClusterIOWorker loop : workers) {
168 - if (!loop.awaitStart(START_TIMEOUT)) {
169 - log.warn("Comm loop did not start on-time; moving on...");
170 - }
171 - }
172 - }
173 -
174 - /**
175 - * Starts listening for connections from peer cluster members.
176 - */
177 - private void startListening() {
178 - try {
179 - connectionListener =
180 - new ClusterConnectionListener(localNode.ip(), localNode.tcpPort(),
181 - workerFinder);
182 - listenExecutor.execute(connectionListener);
183 - if (!connectionListener.awaitStart(START_TIMEOUT)) {
184 - log.warn("Listener did not start on-time; moving on...");
185 - }
186 - } catch (IOException e) {
187 - log.error("Unable to listen for cluster connections", e);
188 - }
189 - }
190 -
191 - /**
192 - * Initiates open connection request and registers the pending socket
193 - * channel with the given IO loop.
194 - *
195 - * @param loop loop with which the channel should be registered
196 - * @throws java.io.IOException if the socket could not be open or connected
197 - */
198 - private void initiateConnection(DefaultControllerNode node,
199 - ClusterIOWorker loop) throws IOException {
200 - SocketAddress sa = new InetSocketAddress(getByAddress(node.ip().toOctets()), node.tcpPort());
201 - SocketChannel ch = SocketChannel.open();
202 - ch.configureBlocking(false);
203 - ch.connect(sa);
204 - loop.connectStream(ch);
205 - }
206 -
207 -
208 - /**
209 - * Attempts to connect to any nodes that do not have an associated connection.
210 - */
211 - private void startInitiating() {
212 - timer.schedule(connectionCustodian, CONNECTION_CUSTODIAN_DELAY,
213 - CONNECTION_CUSTODIAN_FREQUENCY);
214 - }
215 -
216 - // Sweeps through all controller nodes and attempts to open connection to
217 - // those that presently do not have one.
218 - private class ConnectionCustodian extends TimerTask {
219 - @Override
220 - public void run() {
221 - for (DefaultControllerNode node : nodes) {
222 - if (node != localNode && !streams.containsKey(node.id())) {
223 - try {
224 - initiateConnection(node, workerFinder.findWorker());
225 - } catch (IOException e) {
226 - log.debug("Unable to connect", e);
227 - }
228 - }
229 - }
230 - }
231 - }
232 -
233 - // Finds the least utilitied IO loop.
234 - private class LeastUtilitiedWorkerFinder implements WorkerFinder {
235 -
236 - @Override
237 - public ClusterIOWorker findWorker() {
238 - ClusterIOWorker leastUtilized = null;
239 - int minCount = Integer.MAX_VALUE;
240 - for (ClusterIOWorker worker : workers) {
241 - int count = worker.streamCount();
242 - if (count == 0) {
243 - return worker;
244 - }
245 -
246 - if (count < minCount) {
247 - leastUtilized = worker;
248 - minCount = count;
249 - }
250 - }
251 - return leastUtilized;
252 - }
253 - }
254 -
255 -}
...@@ -14,7 +14,6 @@ import org.onlab.onos.cluster.ControllerNode; ...@@ -14,7 +14,6 @@ import org.onlab.onos.cluster.ControllerNode;
14 import org.onlab.onos.cluster.DefaultControllerNode; 14 import org.onlab.onos.cluster.DefaultControllerNode;
15 import org.onlab.onos.cluster.NodeId; 15 import org.onlab.onos.cluster.NodeId;
16 import org.onlab.onos.store.AbstractStore; 16 import org.onlab.onos.store.AbstractStore;
17 -import org.onlab.onos.store.cluster.messaging.SerializationService;
18 import org.onlab.packet.IpPrefix; 17 import org.onlab.packet.IpPrefix;
19 import org.slf4j.Logger; 18 import org.slf4j.Logger;
20 import org.slf4j.LoggerFactory; 19 import org.slf4j.LoggerFactory;
...@@ -43,20 +42,20 @@ public class DistributedClusterStore ...@@ -43,20 +42,20 @@ public class DistributedClusterStore
43 private final Map<NodeId, State> states = new ConcurrentHashMap<>(); 42 private final Map<NodeId, State> states = new ConcurrentHashMap<>();
44 43
45 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 44 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
46 - private CommunicationsDelegate commsDelegate; 45 + private ClusterCommunicationAdminService communicationAdminService;
47 -
48 - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
49 - private SerializationService serializationService;
50 46
51 private final ClusterNodesDelegate nodesDelegate = new InnerNodesDelegate(); 47 private final ClusterNodesDelegate nodesDelegate = new InnerNodesDelegate();
52 - private ConnectionManager connectionManager;
53 48
54 @Activate 49 @Activate
55 public void activate() { 50 public void activate() {
56 loadClusterDefinition(); 51 loadClusterDefinition();
57 establishSelfIdentity(); 52 establishSelfIdentity();
58 - connectionManager = new ConnectionManager(localNode, nodesDelegate, 53 +
59 - commsDelegate, serializationService); 54 + // Start-up the comm service and prime it with the loaded nodes.
55 + communicationAdminService.startUp(localNode, nodesDelegate);
56 + for (DefaultControllerNode node : nodes.values()) {
57 + communicationAdminService.addNode(node);
58 + }
60 log.info("Started"); 59 log.info("Started");
61 } 60 }
62 61
...@@ -92,8 +91,8 @@ public class DistributedClusterStore ...@@ -92,8 +91,8 @@ public class DistributedClusterStore
92 if (localNode == null) { 91 if (localNode == null) {
93 localNode = new DefaultControllerNode(new NodeId(ip.toString()), ip); 92 localNode = new DefaultControllerNode(new NodeId(ip.toString()), ip);
94 nodes.put(localNode.id(), localNode); 93 nodes.put(localNode.id(), localNode);
95 - states.put(localNode.id(), State.ACTIVE);
96 } 94 }
95 + states.put(localNode.id(), State.ACTIVE);
97 } 96 }
98 97
99 @Override 98 @Override
...@@ -122,29 +121,48 @@ public class DistributedClusterStore ...@@ -122,29 +121,48 @@ public class DistributedClusterStore
122 public ControllerNode addNode(NodeId nodeId, IpPrefix ip, int tcpPort) { 121 public ControllerNode addNode(NodeId nodeId, IpPrefix ip, int tcpPort) {
123 DefaultControllerNode node = new DefaultControllerNode(nodeId, ip, tcpPort); 122 DefaultControllerNode node = new DefaultControllerNode(nodeId, ip, tcpPort);
124 nodes.put(nodeId, node); 123 nodes.put(nodeId, node);
125 - connectionManager.addNode(node); 124 + communicationAdminService.addNode(node);
126 return node; 125 return node;
127 } 126 }
128 127
129 @Override 128 @Override
130 public void removeNode(NodeId nodeId) { 129 public void removeNode(NodeId nodeId) {
131 - DefaultControllerNode node = nodes.remove(nodeId); 130 + if (nodeId.equals(localNode.id())) {
132 - if (node != null) { 131 + // We are being ejected from the cluster, so remove all other nodes.
133 - connectionManager.removeNode(node); 132 + communicationAdminService.clearAllNodesAndStreams();
133 + nodes.clear();
134 + nodes.put(localNode.id(), localNode);
135 +
136 + } else {
137 + // Remove the other node.
138 + DefaultControllerNode node = nodes.remove(nodeId);
139 + if (node != null) {
140 + communicationAdminService.removeNode(node);
141 + }
134 } 142 }
135 } 143 }
136 144
137 // Entity to handle back calls from the connection manager. 145 // Entity to handle back calls from the connection manager.
138 private class InnerNodesDelegate implements ClusterNodesDelegate { 146 private class InnerNodesDelegate implements ClusterNodesDelegate {
139 @Override 147 @Override
140 - public void nodeDetected(DefaultControllerNode node) { 148 + public DefaultControllerNode nodeDetected(NodeId nodeId, IpPrefix ip, int tcpPort) {
141 - nodes.put(node.id(), node); 149 + DefaultControllerNode node = nodes.get(nodeId);
142 - states.put(node.id(), State.ACTIVE); 150 + if (node == null) {
151 + node = (DefaultControllerNode) addNode(nodeId, ip, tcpPort);
152 + }
153 + states.put(nodeId, State.ACTIVE);
154 + return node;
155 + }
156 +
157 + @Override
158 + public void nodeVanished(NodeId nodeId) {
159 + states.put(nodeId, State.INACTIVE);
143 } 160 }
144 161
145 @Override 162 @Override
146 - public void nodeVanished(DefaultControllerNode node) { 163 + public void nodeRemoved(NodeId nodeId) {
147 - states.put(node.id(), State.INACTIVE); 164 + removeNode(nodeId);
148 } 165 }
149 } 166 }
167 +
150 } 168 }
......
1 -package org.onlab.onos.store.cluster.impl;
2 -
3 -import org.onlab.onos.cluster.NodeId;
4 -import org.onlab.onos.store.cluster.messaging.ClusterMessage;
5 -
6 -/**
7 - * Created by tom on 9/29/14.
8 - */
9 -public interface MessageSender {
10 -
11 - /**
12 - * Sends the specified message to the given cluster node.
13 - *
14 - * @param nodeId node identifier
15 - * @param message mesage to send
16 - * @return true if the message was sent sucessfully; false if there is
17 - * no stream or if there was an error
18 - */
19 - boolean send(NodeId nodeId, ClusterMessage message);
20 -
21 -}
1 +package org.onlab.onos.store.cluster.impl;
2 +
3 +import de.javakaffee.kryoserializers.URISerializer;
4 +import org.apache.felix.scr.annotations.Activate;
5 +import org.apache.felix.scr.annotations.Component;
6 +import org.apache.felix.scr.annotations.Deactivate;
7 +import org.apache.felix.scr.annotations.Service;
8 +import org.onlab.onos.cluster.ControllerNode;
9 +import org.onlab.onos.cluster.DefaultControllerNode;
10 +import org.onlab.onos.cluster.NodeId;
11 +import org.onlab.onos.net.ConnectPoint;
12 +import org.onlab.onos.net.DefaultDevice;
13 +import org.onlab.onos.net.DefaultLink;
14 +import org.onlab.onos.net.DefaultPort;
15 +import org.onlab.onos.net.Device;
16 +import org.onlab.onos.net.DeviceId;
17 +import org.onlab.onos.net.Element;
18 +import org.onlab.onos.net.Link;
19 +import org.onlab.onos.net.LinkKey;
20 +import org.onlab.onos.net.MastershipRole;
21 +import org.onlab.onos.net.Port;
22 +import org.onlab.onos.net.PortNumber;
23 +import org.onlab.onos.net.provider.ProviderId;
24 +import org.onlab.onos.store.cluster.messaging.ClusterMessage;
25 +import org.onlab.onos.store.cluster.messaging.EchoMessage;
26 +import org.onlab.onos.store.cluster.messaging.LeavingMemberMessage;
27 +import org.onlab.onos.store.cluster.messaging.HelloMessage;
28 +import org.onlab.onos.store.cluster.messaging.MessageSubject;
29 +import org.onlab.onos.store.cluster.messaging.NewMemberMessage;
30 +import org.onlab.onos.store.cluster.messaging.SerializationService;
31 +import org.onlab.onos.store.serializers.ConnectPointSerializer;
32 +import org.onlab.onos.store.serializers.DefaultLinkSerializer;
33 +import org.onlab.onos.store.serializers.DefaultPortSerializer;
34 +import org.onlab.onos.store.serializers.DeviceIdSerializer;
35 +import org.onlab.onos.store.serializers.IpPrefixSerializer;
36 +import org.onlab.onos.store.serializers.LinkKeySerializer;
37 +import org.onlab.onos.store.serializers.NodeIdSerializer;
38 +import org.onlab.onos.store.serializers.PortNumberSerializer;
39 +import org.onlab.onos.store.serializers.ProviderIdSerializer;
40 +import org.onlab.packet.IpPrefix;
41 +import org.onlab.util.KryoPool;
42 +import org.slf4j.Logger;
43 +import org.slf4j.LoggerFactory;
44 +
45 +import java.net.URI;
46 +import java.nio.ByteBuffer;
47 +import java.util.ArrayList;
48 +import java.util.HashMap;
49 +
50 +import static com.google.common.base.Preconditions.checkState;
51 +
52 +/**
53 + * Factory for parsing messages sent between cluster members.
54 + */
55 +@Component(immediate = true)
56 +@Service
57 +public class MessageSerializer implements SerializationService {
58 +
59 + private final Logger log = LoggerFactory.getLogger(getClass());
60 +
61 + private static final int METADATA_LENGTH = 12; // 8 + 4
62 + private static final int LENGTH_OFFSET = 8;
63 +
64 + private static final long MARKER = 0xfeedcafebeaddeadL;
65 +
66 + private KryoPool serializerPool;
67 +
68 + @Activate
69 + public void activate() {
70 + setupKryoPool();
71 + log.info("Started");
72 + }
73 +
74 + @Deactivate
75 + public void deactivate() {
76 + log.info("Stopped");
77 + }
78 +
79 + /**
80 + * Sets up the common serialzers pool.
81 + */
82 + protected void setupKryoPool() {
83 + // FIXME Slice out types used in common to separate pool/namespace.
84 + serializerPool = KryoPool.newBuilder()
85 + .register(ArrayList.class,
86 + HashMap.class,
87 +
88 + ControllerNode.State.class,
89 + Device.Type.class,
90 +
91 + DefaultControllerNode.class,
92 + DefaultDevice.class,
93 + MastershipRole.class,
94 + Port.class,
95 + Element.class,
96 +
97 + Link.Type.class,
98 +
99 + MessageSubject.class,
100 + HelloMessage.class,
101 + NewMemberMessage.class,
102 + LeavingMemberMessage.class,
103 + EchoMessage.class
104 + )
105 + .register(IpPrefix.class, new IpPrefixSerializer())
106 + .register(URI.class, new URISerializer())
107 + .register(NodeId.class, new NodeIdSerializer())
108 + .register(ProviderId.class, new ProviderIdSerializer())
109 + .register(DeviceId.class, new DeviceIdSerializer())
110 + .register(PortNumber.class, new PortNumberSerializer())
111 + .register(DefaultPort.class, new DefaultPortSerializer())
112 + .register(LinkKey.class, new LinkKeySerializer())
113 + .register(ConnectPoint.class, new ConnectPointSerializer())
114 + .register(DefaultLink.class, new DefaultLinkSerializer())
115 + .build()
116 + .populate(1);
117 + }
118 +
119 +
120 + @Override
121 + public ClusterMessage decode(ByteBuffer buffer) {
122 + try {
123 + // Do we have enough bytes to read the header? If not, bail.
124 + if (buffer.remaining() < METADATA_LENGTH) {
125 + return null;
126 + }
127 +
128 + // Peek at the length and if we have enough to read the entire message
129 + // go ahead, otherwise bail.
130 + int length = buffer.getInt(buffer.position() + LENGTH_OFFSET);
131 + if (buffer.remaining() < length) {
132 + return null;
133 + }
134 +
135 + // At this point, we have enough data to read a complete message.
136 + long marker = buffer.getLong();
137 + checkState(marker == MARKER, "Incorrect message marker");
138 + length = buffer.getInt();
139 +
140 + // TODO: sanity checking for length
141 + byte[] data = new byte[length - METADATA_LENGTH];
142 + buffer.get(data);
143 + return (ClusterMessage) serializerPool.deserialize(data);
144 +
145 + } catch (Exception e) {
146 + // TODO: recover from exceptions by forwarding stream to next marker
147 + log.warn("Unable to decode message due to: " + e);
148 + }
149 + return null;
150 + }
151 +
152 + @Override
153 + public void encode(ClusterMessage message, ByteBuffer buffer) {
154 + try {
155 + byte[] data = serializerPool.serialize(message);
156 + buffer.putLong(MARKER);
157 + buffer.putInt(data.length + METADATA_LENGTH);
158 + buffer.put(data);
159 +
160 + } catch (Exception e) {
161 + // TODO: recover from exceptions by forwarding stream to next marker
162 + log.warn("Unable to encode message due to: " + e);
163 + }
164 + }
165 +
166 +}
1 -package org.onlab.onos.store.cluster.impl;
2 -
3 -/**
4 - * Provides means to find a worker IO loop.
5 - */
6 -public interface WorkerFinder {
7 -
8 - /**
9 - * Finds a suitable worker.
10 - *
11 - * @return available worker
12 - */
13 - ClusterIOWorker findWorker();
14 -}
1 +/**
2 + * Distributed cluster store and messaging subsystem implementation.
3 + */
4 +package org.onlab.onos.store.cluster.impl;
...\ No newline at end of file ...\ No newline at end of file
...@@ -10,6 +10,15 @@ import java.util.Set; ...@@ -10,6 +10,15 @@ import java.util.Set;
10 public interface ClusterCommunicationService { 10 public interface ClusterCommunicationService {
11 11
12 /** 12 /**
13 + * Sends a message to all controller nodes.
14 + *
15 + * @param message message to send
16 + * @return true if the message was sent sucessfully to all nodes; false
17 + * if there is no stream or if there was an error for some node
18 + */
19 + boolean send(ClusterMessage message);
20 +
21 + /**
13 * Sends a message to the specified controller node. 22 * Sends a message to the specified controller node.
14 * 23 *
15 * @param message message to send 24 * @param message message to send
......
1 +package org.onlab.onos.store.cluster.messaging;
2 +
3 +import org.onlab.onos.cluster.NodeId;
4 +import org.onlab.packet.IpPrefix;
5 +
6 +/**
7 + * Base for cluster membership messages.
8 + */
9 +public abstract class ClusterMembershipMessage extends ClusterMessage {
10 +
11 + private NodeId nodeId;
12 + private IpPrefix ipAddress;
13 + private int tcpPort;
14 +
15 + // For serialization
16 + protected ClusterMembershipMessage() {
17 + super(MessageSubject.HELLO);
18 + nodeId = null;
19 + ipAddress = null;
20 + tcpPort = 0;
21 + }
22 +
23 + /**
24 + * Creates a new membership message for the specified end-point data.
25 + *
26 + * @param subject message subject
27 + * @param nodeId sending node identification
28 + * @param ipAddress sending node IP address
29 + * @param tcpPort sending node TCP port
30 + */
31 + protected ClusterMembershipMessage(MessageSubject subject, NodeId nodeId,
32 + IpPrefix ipAddress, int tcpPort) {
33 + super(subject);
34 + this.nodeId = nodeId;
35 + this.ipAddress = ipAddress;
36 + this.tcpPort = tcpPort;
37 + }
38 +
39 + /**
40 + * Returns the sending node identifer.
41 + *
42 + * @return node identifier
43 + */
44 + public NodeId nodeId() {
45 + return nodeId;
46 + }
47 +
48 + /**
49 + * Returns the sending node IP address.
50 + *
51 + * @return node IP address
52 + */
53 + public IpPrefix ipAddress() {
54 + return ipAddress;
55 + }
56 +
57 + /**
58 + * Returns the sending node TCP listen port.
59 + *
60 + * @return TCP listen port
61 + */
62 + public int tcpPort() {
63 + return tcpPort;
64 + }
65 +
66 +}
...@@ -6,18 +6,10 @@ import org.onlab.packet.IpPrefix; ...@@ -6,18 +6,10 @@ import org.onlab.packet.IpPrefix;
6 /** 6 /**
7 * Hello message that nodes use to greet each other. 7 * Hello message that nodes use to greet each other.
8 */ 8 */
9 -public class HelloMessage extends ClusterMessage { 9 +public class HelloMessage extends ClusterMembershipMessage {
10 -
11 - private NodeId nodeId;
12 - private IpPrefix ipAddress;
13 - private int tcpPort;
14 10
15 // For serialization 11 // For serialization
16 private HelloMessage() { 12 private HelloMessage() {
17 - super(MessageSubject.HELLO);
18 - nodeId = null;
19 - ipAddress = null;
20 - tcpPort = 0;
21 } 13 }
22 14
23 /** 15 /**
...@@ -28,36 +20,7 @@ public class HelloMessage extends ClusterMessage { ...@@ -28,36 +20,7 @@ public class HelloMessage extends ClusterMessage {
28 * @param tcpPort sending node TCP port 20 * @param tcpPort sending node TCP port
29 */ 21 */
30 public HelloMessage(NodeId nodeId, IpPrefix ipAddress, int tcpPort) { 22 public HelloMessage(NodeId nodeId, IpPrefix ipAddress, int tcpPort) {
31 - super(MessageSubject.HELLO); 23 + super(MessageSubject.HELLO, nodeId, ipAddress, tcpPort);
32 - nodeId = nodeId;
33 - ipAddress = ipAddress;
34 - tcpPort = tcpPort;
35 - }
36 -
37 - /**
38 - * Returns the sending node identifer.
39 - *
40 - * @return node identifier
41 - */
42 - public NodeId nodeId() {
43 - return nodeId;
44 } 24 }
45 25
46 - /**
47 - * Returns the sending node IP address.
48 - *
49 - * @return node IP address
50 - */
51 - public IpPrefix ipAddress() {
52 - return ipAddress;
53 - }
54 -
55 - /**
56 - * Returns the sending node TCP listen port.
57 - *
58 - * @return TCP listen port
59 - */
60 - public int tcpPort() {
61 - return tcpPort;
62 - }
63 } 26 }
......
1 +package org.onlab.onos.store.cluster.messaging;
2 +
3 +import org.onlab.onos.cluster.NodeId;
4 +
5 +/**
6 + * Announcement message that nodes use to gossip about team departures.
7 + */
8 +public class LeavingMemberMessage extends ClusterMembershipMessage {
9 +
10 + // For serialization
11 + private LeavingMemberMessage() {
12 + super();
13 + }
14 +
15 + /**
16 + * Creates a new goodbye message.
17 + *
18 + * @param nodeId sending node identification
19 + */
20 + public LeavingMemberMessage(NodeId nodeId) {
21 + super(MessageSubject.LEAVING_MEMBER, nodeId, null, 0);
22 + }
23 +
24 +}
...@@ -8,6 +8,12 @@ public enum MessageSubject { ...@@ -8,6 +8,12 @@ public enum MessageSubject {
8 /** Represents a first greeting message. */ 8 /** Represents a first greeting message. */
9 HELLO, 9 HELLO,
10 10
11 + /** Signifies announcement about new member. */
12 + NEW_MEMBER,
13 +
14 + /** Signifies announcement about leaving member. */
15 + LEAVING_MEMBER,
16 +
11 /** Signifies a heart-beat message. */ 17 /** Signifies a heart-beat message. */
12 ECHO 18 ECHO
13 19
......
1 package org.onlab.onos.store.cluster.messaging; 1 package org.onlab.onos.store.cluster.messaging;
2 2
3 +import org.onlab.onos.cluster.NodeId;
4 +
3 /** 5 /**
4 * Represents a message consumer. 6 * Represents a message consumer.
5 */ 7 */
...@@ -8,8 +10,9 @@ public interface MessageSubscriber { ...@@ -8,8 +10,9 @@ public interface MessageSubscriber {
8 /** 10 /**
9 * Receives the specified cluster message. 11 * Receives the specified cluster message.
10 * 12 *
11 - * @param message message to be received 13 + * @param message message to be received
14 + * @param fromNodeId node from which the message was received
12 */ 15 */
13 - void receive(ClusterMessage message); 16 + void receive(ClusterMessage message, NodeId fromNodeId);
14 17
15 } 18 }
......
1 +package org.onlab.onos.store.cluster.messaging;
2 +
3 +import org.onlab.onos.cluster.NodeId;
4 +import org.onlab.packet.IpPrefix;
5 +
6 +/**
7 + * Announcement message that nodes use to gossip about new arrivals.
8 + */
9 +public class NewMemberMessage extends ClusterMembershipMessage {
10 +
11 + // For serialization
12 + private NewMemberMessage() {
13 + }
14 +
15 + /**
16 + * Creates a new gossip message for the specified end-point data.
17 + *
18 + * @param nodeId sending node identification
19 + * @param ipAddress sending node IP address
20 + * @param tcpPort sending node TCP port
21 + */
22 + public NewMemberMessage(NodeId nodeId, IpPrefix ipAddress, int tcpPort) {
23 + super(MessageSubject.NEW_MEMBER, nodeId, ipAddress, tcpPort);
24 + }
25 +
26 +}
...@@ -3,12 +3,12 @@ package org.onlab.onos.store.cluster.messaging; ...@@ -3,12 +3,12 @@ package org.onlab.onos.store.cluster.messaging;
3 import java.nio.ByteBuffer; 3 import java.nio.ByteBuffer;
4 4
5 /** 5 /**
6 - * Service for serializing/deserializing intra-cluster messages. 6 + * Service for encoding &amp; decoding intra-cluster messages.
7 */ 7 */
8 public interface SerializationService { 8 public interface SerializationService {
9 9
10 /** 10 /**
11 - * Decodes the specified byte buffer to obtain a message within. 11 + * Decodes the specified byte buffer to obtain the message within.
12 * 12 *
13 * @param buffer byte buffer with message(s) 13 * @param buffer byte buffer with message(s)
14 * @return parsed message 14 * @return parsed message
......
1 -package org.onlab.onos.store.cluster.messaging.impl;
2 -
3 -import com.google.common.collect.HashMultimap;
4 -import com.google.common.collect.ImmutableSet;
5 -import com.google.common.collect.Multimap;
6 -import org.apache.felix.scr.annotations.Component;
7 -import org.apache.felix.scr.annotations.Service;
8 -import org.onlab.onos.cluster.NodeId;
9 -import org.onlab.onos.store.cluster.impl.CommunicationsDelegate;
10 -import org.onlab.onos.store.cluster.impl.MessageSender;
11 -import org.onlab.onos.store.cluster.messaging.ClusterCommunicationService;
12 -import org.onlab.onos.store.cluster.messaging.ClusterMessage;
13 -import org.onlab.onos.store.cluster.messaging.MessageSubject;
14 -import org.onlab.onos.store.cluster.messaging.MessageSubscriber;
15 -
16 -import java.util.Set;
17 -
18 -/**
19 - * Implements the cluster communication services to use by other stores.
20 - */
21 -@Component(immediate = true)
22 -@Service
23 -public class ClusterCommunicationManager
24 - implements ClusterCommunicationService, CommunicationsDelegate {
25 -
26 - // TODO: use something different that won't require synchronization
27 - private Multimap<MessageSubject, MessageSubscriber> subscribers = HashMultimap.create();
28 - private MessageSender messageSender;
29 -
30 - @Override
31 - public boolean send(ClusterMessage message, NodeId toNodeId) {
32 - return messageSender.send(toNodeId, message);
33 - }
34 -
35 - @Override
36 - public synchronized void addSubscriber(MessageSubject subject, MessageSubscriber subscriber) {
37 - subscribers.put(subject, subscriber);
38 - }
39 -
40 - @Override
41 - public synchronized void removeSubscriber(MessageSubject subject, MessageSubscriber subscriber) {
42 - subscribers.remove(subject, subscriber);
43 - }
44 -
45 - @Override
46 - public Set<MessageSubscriber> getSubscribers(MessageSubject subject) {
47 - return ImmutableSet.copyOf(subscribers.get(subject));
48 - }
49 -
50 - @Override
51 - public void dispatch(ClusterMessage message) {
52 - Set<MessageSubscriber> set = getSubscribers(message.subject());
53 - if (set != null) {
54 - for (MessageSubscriber subscriber : set) {
55 - subscriber.receive(message);
56 - }
57 - }
58 - }
59 -
60 - @Override
61 - public void setSender(MessageSender messageSender) {
62 - this.messageSender = messageSender;
63 - }
64 -}
1 -package org.onlab.onos.store.cluster.messaging.impl;
2 -
3 -import org.onlab.onos.store.cluster.messaging.ClusterMessage;
4 -import org.onlab.onos.store.cluster.messaging.MessageSubject;
5 -import org.onlab.onos.store.cluster.messaging.SerializationService;
6 -
7 -import java.nio.ByteBuffer;
8 -
9 -import static com.google.common.base.Preconditions.checkState;
10 -
11 -/**
12 - * Factory for parsing messages sent between cluster members.
13 - */
14 -public class MessageSerializer implements SerializationService {
15 -
16 - private static final int METADATA_LENGTH = 16; // 8 + 4 + 4
17 - private static final int LENGTH_OFFSET = 12;
18 -
19 - private static final long MARKER = 0xfeedcafebeaddeadL;
20 -
21 - @Override
22 - public ClusterMessage decode(ByteBuffer buffer) {
23 - try {
24 - // Do we have enough bytes to read the header? If not, bail.
25 - if (buffer.remaining() < METADATA_LENGTH) {
26 - return null;
27 - }
28 -
29 - // Peek at the length and if we have enough to read the entire message
30 - // go ahead, otherwise bail.
31 - int length = buffer.getInt(buffer.position() + LENGTH_OFFSET);
32 - if (buffer.remaining() < length) {
33 - return null;
34 - }
35 -
36 - // At this point, we have enough data to read a complete message.
37 - long marker = buffer.getLong();
38 - checkState(marker == MARKER, "Incorrect message marker");
39 -
40 - int subjectOrdinal = buffer.getInt();
41 - MessageSubject subject = MessageSubject.values()[subjectOrdinal];
42 - length = buffer.getInt();
43 -
44 - // TODO: sanity checking for length
45 - byte[] data = new byte[length - METADATA_LENGTH];
46 - buffer.get(data);
47 -
48 - // TODO: add deserialization hook here; for now this hack
49 - return null; // actually deserialize
50 -
51 - } catch (Exception e) {
52 - // TODO: recover from exceptions by forwarding stream to next marker
53 - e.printStackTrace();
54 - }
55 - return null;
56 - }
57 -
58 - @Override
59 - public void encode(ClusterMessage message, ByteBuffer buffer) {
60 - try {
61 - int i = 0;
62 - // Type based lookup for proper encoder
63 - } catch (Exception e) {
64 - // TODO: recover from exceptions by forwarding stream to next marker
65 - e.printStackTrace();
66 - }
67 - }
68 -
69 -}
1 +/**
2 + * Cluster messaging APIs for the use by the various distributed stores.
3 + */
4 +package org.onlab.onos.store.cluster.messaging;
...\ No newline at end of file ...\ No newline at end of file
1 +package org.onlab.onos.store.cluster.impl;
2 +
3 +import org.junit.After;
4 +import org.junit.Before;
5 +import org.junit.Test;
6 +import org.onlab.onos.cluster.DefaultControllerNode;
7 +import org.onlab.onos.cluster.NodeId;
8 +import org.onlab.packet.IpPrefix;
9 +
10 +import java.util.concurrent.CountDownLatch;
11 +import java.util.concurrent.TimeUnit;
12 +
13 +import static org.junit.Assert.assertEquals;
14 +import static org.junit.Assert.assertTrue;
15 +
16 +/**
17 + * Tests of the cluster communication manager.
18 + */
19 +public class ClusterCommunicationManagerTest {
20 +
21 + private static final NodeId N1 = new NodeId("n1");
22 + private static final NodeId N2 = new NodeId("n2");
23 +
24 + private static final int P1 = 9881;
25 + private static final int P2 = 9882;
26 +
27 + private static final IpPrefix IP = IpPrefix.valueOf("127.0.0.1");
28 +
29 + private ClusterCommunicationManager ccm1;
30 + private ClusterCommunicationManager ccm2;
31 +
32 + private TestDelegate cnd1 = new TestDelegate();
33 + private TestDelegate cnd2 = new TestDelegate();
34 +
35 + private DefaultControllerNode node1 = new DefaultControllerNode(N1, IP, P1);
36 + private DefaultControllerNode node2 = new DefaultControllerNode(N2, IP, P2);
37 +
38 + @Before
39 + public void setUp() {
40 + MessageSerializer messageSerializer = new MessageSerializer();
41 + messageSerializer.activate();
42 +
43 + ccm1 = new ClusterCommunicationManager();
44 + ccm1.serializationService = messageSerializer;
45 + ccm1.activate();
46 +
47 + ccm2 = new ClusterCommunicationManager();
48 + ccm2.serializationService = messageSerializer;
49 + ccm2.activate();
50 +
51 + ccm1.startUp(node1, cnd1);
52 + ccm2.startUp(node2, cnd2);
53 + }
54 +
55 + @After
56 + public void tearDown() {
57 + ccm1.deactivate();
58 + ccm2.deactivate();
59 + }
60 +
61 + @Test
62 + public void connect() throws Exception {
63 + cnd1.latch = new CountDownLatch(1);
64 + cnd2.latch = new CountDownLatch(1);
65 +
66 + ccm1.addNode(node2);
67 + validateDelegateEvent(cnd1, Op.DETECTED, node2.id());
68 + validateDelegateEvent(cnd2, Op.DETECTED, node1.id());
69 + }
70 +
71 + @Test
72 + public void disconnect() throws Exception {
73 + cnd1.latch = new CountDownLatch(1);
74 + cnd2.latch = new CountDownLatch(1);
75 +
76 + ccm1.addNode(node2);
77 + validateDelegateEvent(cnd1, Op.DETECTED, node2.id());
78 + validateDelegateEvent(cnd2, Op.DETECTED, node1.id());
79 +
80 + cnd1.latch = new CountDownLatch(1);
81 + cnd2.latch = new CountDownLatch(1);
82 + ccm1.deactivate();
83 +//
84 +// validateDelegateEvent(cnd2, Op.VANISHED, node1.id());
85 + }
86 +
87 + private void validateDelegateEvent(TestDelegate delegate, Op op, NodeId nodeId)
88 + throws InterruptedException {
89 + assertTrue("did not connect in time", delegate.latch.await(2500, TimeUnit.MILLISECONDS));
90 + assertEquals("incorrect event", op, delegate.op);
91 + assertEquals("incorrect event node", nodeId, delegate.nodeId);
92 + }
93 +
94 + enum Op { DETECTED, VANISHED, REMOVED };
95 +
96 + private class TestDelegate implements ClusterNodesDelegate {
97 +
98 + Op op;
99 + CountDownLatch latch;
100 + NodeId nodeId;
101 +
102 + @Override
103 + public DefaultControllerNode nodeDetected(NodeId nodeId, IpPrefix ip, int tcpPort) {
104 + latch(nodeId, Op.DETECTED);
105 + return new DefaultControllerNode(nodeId, ip, tcpPort);
106 + }
107 +
108 + @Override
109 + public void nodeVanished(NodeId nodeId) {
110 + latch(nodeId, Op.VANISHED);
111 + }
112 +
113 + @Override
114 + public void nodeRemoved(NodeId nodeId) {
115 + latch(nodeId, Op.REMOVED);
116 + }
117 +
118 + private void latch(NodeId nodeId, Op op) {
119 + this.op = op;
120 + this.nodeId = nodeId;
121 + latch.countDown();
122 + }
123 + }
124 +}
...\ No newline at end of file ...\ No newline at end of file
...@@ -105,11 +105,9 @@ public class SimpleFlowRuleStore ...@@ -105,11 +105,9 @@ public class SimpleFlowRuleStore
105 */ 105 */
106 106
107 if (flowEntries.containsEntry(did, f)) { 107 if (flowEntries.containsEntry(did, f)) {
108 - //synchronized (flowEntries) {
109 flowEntries.remove(did, f); 108 flowEntries.remove(did, f);
110 flowEntries.put(did, f); 109 flowEntries.put(did, f);
111 flowEntriesById.remove(rule.appId(), rule); 110 flowEntriesById.remove(rule.appId(), rule);
112 - //}
113 } 111 }
114 } 112 }
115 113
......
...@@ -119,6 +119,14 @@ ...@@ -119,6 +119,14 @@
119 <bundle>mvn:org.onlab.onos/onos-app-fwd/1.0.0-SNAPSHOT</bundle> 119 <bundle>mvn:org.onlab.onos/onos-app-fwd/1.0.0-SNAPSHOT</bundle>
120 </feature> 120 </feature>
121 121
122 + <feature name="onos-app-mobility" version="1.0.0"
123 + description="ONOS sample forwarding application">
124 + <feature>onos-api</feature>
125 + <bundle>mvn:org.onlab.onos/onos-app-mobility/1.0.0-SNAPSHOT</bundle>
126 + </feature>
127 +
128 +
129 +
122 <feature name="onos-app-foo" version="1.0.0" 130 <feature name="onos-app-foo" version="1.0.0"
123 description="ONOS sample playground application"> 131 description="ONOS sample playground application">
124 <feature>onos-api</feature> 132 <feature>onos-api</feature>
......
...@@ -243,6 +243,8 @@ public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitchDriver { ...@@ -243,6 +243,8 @@ public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitchDriver {
243 if (role == RoleState.SLAVE || role == RoleState.EQUAL) { 243 if (role == RoleState.SLAVE || role == RoleState.EQUAL) {
244 this.role = role; 244 this.role = role;
245 } 245 }
246 + } else {
247 + this.role = role;
246 } 248 }
247 } catch (IOException e) { 249 } catch (IOException e) {
248 log.error("Unable to write to switch {}.", this.dpid); 250 log.error("Unable to write to switch {}.", this.dpid);
......
...@@ -651,7 +651,7 @@ class OFChannelHandler extends IdleStateAwareChannelHandler { ...@@ -651,7 +651,7 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
651 * @param error The error message 651 * @param error The error message
652 */ 652 */
653 protected void logError(OFChannelHandler h, OFErrorMsg error) { 653 protected void logError(OFChannelHandler h, OFErrorMsg error) {
654 - log.error("{} from switch {} in state {}", 654 + log.debug("{} from switch {} in state {}",
655 new Object[] { 655 new Object[] {
656 error, 656 error,
657 h.getSwitchInfoString(), 657 h.getSwitchInfoString(),
......
...@@ -77,6 +77,7 @@ public class FlowModBuilder { ...@@ -77,6 +77,7 @@ public class FlowModBuilder {
77 .setCookie(U64.of(cookie.value())) 77 .setCookie(U64.of(cookie.value()))
78 .setBufferId(OFBufferId.NO_BUFFER) 78 .setBufferId(OFBufferId.NO_BUFFER)
79 .setActions(actions) 79 .setActions(actions)
80 + .setIdleTimeout(10)
80 .setMatch(match) 81 .setMatch(match)
81 .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM)) 82 .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM))
82 .setPriority(priority) 83 .setPriority(priority)
...@@ -104,6 +105,9 @@ public class FlowModBuilder { ...@@ -104,6 +105,9 @@ public class FlowModBuilder {
104 105
105 private List<OFAction> buildActions() { 106 private List<OFAction> buildActions() {
106 List<OFAction> acts = new LinkedList<>(); 107 List<OFAction> acts = new LinkedList<>();
108 + if (treatment == null) {
109 + return acts;
110 + }
107 for (Instruction i : treatment.instructions()) { 111 for (Instruction i : treatment.instructions()) {
108 switch (i.type()) { 112 switch (i.type()) {
109 case DROP: 113 case DROP:
......
...@@ -31,6 +31,7 @@ import org.onlab.onos.openflow.controller.OpenFlowPacketContext; ...@@ -31,6 +31,7 @@ import org.onlab.onos.openflow.controller.OpenFlowPacketContext;
31 import org.onlab.onos.openflow.controller.PacketListener; 31 import org.onlab.onos.openflow.controller.PacketListener;
32 import org.onlab.packet.ARP; 32 import org.onlab.packet.ARP;
33 import org.onlab.packet.Ethernet; 33 import org.onlab.packet.Ethernet;
34 +import org.onlab.packet.IPv4;
34 import org.onlab.packet.IpPrefix; 35 import org.onlab.packet.IpPrefix;
35 import org.onlab.packet.VlanId; 36 import org.onlab.packet.VlanId;
36 import org.slf4j.Logger; 37 import org.slf4j.Logger;
...@@ -92,29 +93,37 @@ public class OpenFlowHostProvider extends AbstractProvider implements HostProvid ...@@ -92,29 +93,37 @@ public class OpenFlowHostProvider extends AbstractProvider implements HostProvid
92 public void handlePacket(OpenFlowPacketContext pktCtx) { 93 public void handlePacket(OpenFlowPacketContext pktCtx) {
93 Ethernet eth = pktCtx.parsed(); 94 Ethernet eth = pktCtx.parsed();
94 95
96 + VlanId vlan = VlanId.vlanId(eth.getVlanID());
97 + ConnectPoint heardOn = new ConnectPoint(deviceId(Dpid.uri(pktCtx.dpid())),
98 + portNumber(pktCtx.inPort()));
99 +
100 + // If this is not an edge port, bail out.
101 + Topology topology = topologyService.currentTopology();
102 + if (topologyService.isInfrastructure(topology, heardOn)) {
103 + return;
104 + }
105 +
106 + HostLocation hloc = new HostLocation(deviceId(Dpid.uri(pktCtx.dpid())),
107 + portNumber(pktCtx.inPort()),
108 + System.currentTimeMillis());
109 + HostId hid = HostId.hostId(eth.getSourceMAC(), vlan);
95 // Potentially a new or moved host 110 // Potentially a new or moved host
96 if (eth.getEtherType() == Ethernet.TYPE_ARP) { 111 if (eth.getEtherType() == Ethernet.TYPE_ARP) {
97 - VlanId vlan = VlanId.vlanId(eth.getVlanID());
98 - ConnectPoint heardOn = new ConnectPoint(deviceId(Dpid.uri(pktCtx.dpid())),
99 - portNumber(pktCtx.inPort()));
100 -
101 - // If this is not an edge port, bail out.
102 - Topology topology = topologyService.currentTopology();
103 - if (topologyService.isInfrastructure(topology, heardOn)) {
104 - return;
105 - }
106 112
107 - HostLocation hloc = new HostLocation(deviceId(Dpid.uri(pktCtx.dpid())),
108 - portNumber(pktCtx.inPort()),
109 - System.currentTimeMillis());
110 113
111 - HostId hid = HostId.hostId(eth.getSourceMAC(), vlan);
112 ARP arp = (ARP) eth.getPayload(); 114 ARP arp = (ARP) eth.getPayload();
113 Set<IpPrefix> ips = newHashSet(IpPrefix.valueOf(arp.getSenderProtocolAddress())); 115 Set<IpPrefix> ips = newHashSet(IpPrefix.valueOf(arp.getSenderProtocolAddress()));
114 HostDescription hdescr = 116 HostDescription hdescr =
115 new DefaultHostDescription(eth.getSourceMAC(), vlan, hloc, ips); 117 new DefaultHostDescription(eth.getSourceMAC(), vlan, hloc, ips);
116 providerService.hostDetected(hid, hdescr); 118 providerService.hostDetected(hid, hdescr);
117 119
120 + } else if (eth.getEtherType() == Ethernet.TYPE_IPV4) {
121 + IPv4 ip = (IPv4) eth.getPayload();
122 + Set<IpPrefix> ips = newHashSet(IpPrefix.valueOf(ip.getSourceAddress()));
123 + HostDescription hdescr =
124 + new DefaultHostDescription(eth.getSourceMAC(), vlan, hloc, ips);
125 + providerService.hostDetected(hid, hdescr);
126 +
118 } 127 }
119 128
120 // TODO: Use DHCP packets as well later... 129 // TODO: Use DHCP packets as well later...
......
...@@ -106,10 +106,6 @@ public class OpenFlowPacketProvider extends AbstractProvider implements PacketPr ...@@ -106,10 +106,6 @@ public class OpenFlowPacketProvider extends AbstractProvider implements PacketPr
106 for (Instruction inst : packet.treatment().instructions()) { 106 for (Instruction inst : packet.treatment().instructions()) {
107 if (inst.type().equals(Instruction.Type.OUTPUT)) { 107 if (inst.type().equals(Instruction.Type.OUTPUT)) {
108 p = portDesc(((OutputInstruction) inst).port()); 108 p = portDesc(((OutputInstruction) inst).port());
109 - /*if (!sw.getPorts().contains(p)) {
110 - log.warn("Tried to write out non-existent port {}", p.getPortNo());
111 - continue;
112 - }*/
113 OFPacketOut po = packetOut(sw, eth, p.getPortNo()); 109 OFPacketOut po = packetOut(sw, eth, p.getPortNo());
114 sw.sendMsg(po); 110 sw.sendMsg(po);
115 } 111 }
......
...@@ -3,5 +3,7 @@ ...@@ -3,5 +3,7 @@
3 # ONOS remote command-line client. 3 # ONOS remote command-line client.
4 #------------------------------------------------------------------------------- 4 #-------------------------------------------------------------------------------
5 5
6 +[ "$1" = "-w" ] && shift && onos-wait-for-start $1
7 +
6 [ -n "$1" ] && OCI=$1 && shift 8 [ -n "$1" ] && OCI=$1 && shift
7 -client -h $OCI "$@" 9 +client -h $OCI "$@" 2>/dev/null
......
1 +#!/bin/bash
2 +#-------------------------------------------------------------------------------
3 +# Remotely kills the ONOS service on the specified node.
4 +#-------------------------------------------------------------------------------
5 +
6 +[ ! -d "$ONOS_ROOT" ] && echo "ONOS_ROOT is not defined" >&2 && exit 1
7 +. $ONOS_ROOT/tools/build/envDefaults
8 +
9 +ssh $ONOS_USER@${1:-$OCI} "kill -9 \$(ps -ef | grep karaf.jar | grep -v grep | cut -c10-15)"
...\ No newline at end of file ...\ No newline at end of file
1 +# ProxMox-based cell of ONOS instances 1,2 & ONOS mininet box
2 +. $ONOS_ROOT/tools/test/cells/.reset
3 +
4 +export ONOS_NIC="10.128.4.*"
5 +
6 +export OC1="10.128.4.60"
7 +#export OC2="192.168.97.131"
8 +
9 +#export OCN="192.168.97.130"
10 +
1 +# Default virtual box ONOS instances 1,2 & ONOS mininet box
2 +
3 +export ONOS_NIC=192.168.56.*
4 +
5 +export OC1="192.168.56.11"
6 +export OC2="192.168.56.12"
7 +
8 +export OCN="192.168.56.7"
9 +
10 +