Jian Li
Committed by Gerrit Code Review

[Falcon][ONOS-3537] Implement control message collecting logic w/ unit test

Change-Id: Ic21d476a5ad92d7ef739fa3c13dcc06e5cbf7c56
Showing 18 changed files with 969 additions and 16 deletions
...@@ -157,4 +157,18 @@ public interface OpenFlowSwitch { ...@@ -157,4 +157,18 @@ public interface OpenFlowSwitch {
157 * @return string representation of the connection to the device 157 * @return string representation of the connection to the device
158 */ 158 */
159 String channelId(); 159 String channelId();
160 +
161 + /**
162 + * Registers a listener for OF msg events.
163 + *
164 + * @param listener the listener to notify
165 + */
166 + void addEventListener(OpenFlowEventListener listener);
167 +
168 + /**
169 + * Unregisters a listener.
170 + *
171 + * @param listener the listener to unregister
172 + */
173 + void removeEventListener(OpenFlowEventListener listener);
160 } 174 }
......
...@@ -16,27 +16,33 @@ ...@@ -16,27 +16,33 @@
16 16
17 package org.onosproject.openflow.controller.driver; 17 package org.onosproject.openflow.controller.driver;
18 18
19 +import static org.onlab.util.Tools.groupedThreads;
20 +
19 import com.google.common.collect.Lists; 21 import com.google.common.collect.Lists;
20 import org.jboss.netty.channel.Channel; 22 import org.jboss.netty.channel.Channel;
21 import org.onlab.packet.IpAddress; 23 import org.onlab.packet.IpAddress;
22 import org.onosproject.net.Device; 24 import org.onosproject.net.Device;
23 import org.onosproject.net.driver.AbstractHandlerBehaviour; 25 import org.onosproject.net.driver.AbstractHandlerBehaviour;
24 import org.onosproject.openflow.controller.Dpid; 26 import org.onosproject.openflow.controller.Dpid;
27 +import org.onosproject.openflow.controller.OpenFlowEventListener;
25 import org.onosproject.openflow.controller.RoleState; 28 import org.onosproject.openflow.controller.RoleState;
29 +
26 import org.projectfloodlight.openflow.protocol.OFDescStatsReply; 30 import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
27 -import org.projectfloodlight.openflow.protocol.OFErrorMsg;
28 -import org.projectfloodlight.openflow.protocol.OFExperimenter;
29 -import org.projectfloodlight.openflow.protocol.OFFactories;
30 -import org.projectfloodlight.openflow.protocol.OFFactory;
31 import org.projectfloodlight.openflow.protocol.OFFeaturesReply; 31 import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
32 +import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
33 +import org.projectfloodlight.openflow.protocol.OFVersion;
32 import org.projectfloodlight.openflow.protocol.OFMessage; 34 import org.projectfloodlight.openflow.protocol.OFMessage;
33 -import org.projectfloodlight.openflow.protocol.OFNiciraControllerRoleRequest; 35 +import org.projectfloodlight.openflow.protocol.OFType;
36 +import org.projectfloodlight.openflow.protocol.OFFactories;
34 import org.projectfloodlight.openflow.protocol.OFPortDesc; 37 import org.projectfloodlight.openflow.protocol.OFPortDesc;
35 -import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply; 38 +import org.projectfloodlight.openflow.protocol.OFExperimenter;
39 +import org.projectfloodlight.openflow.protocol.OFErrorMsg;
40 +import org.projectfloodlight.openflow.protocol.OFRoleRequest;
41 +import org.projectfloodlight.openflow.protocol.OFNiciraControllerRoleRequest;
36 import org.projectfloodlight.openflow.protocol.OFPortStatus; 42 import org.projectfloodlight.openflow.protocol.OFPortStatus;
43 +import org.projectfloodlight.openflow.protocol.OFFactory;
37 import org.projectfloodlight.openflow.protocol.OFRoleReply; 44 import org.projectfloodlight.openflow.protocol.OFRoleReply;
38 -import org.projectfloodlight.openflow.protocol.OFRoleRequest; 45 +
39 -import org.projectfloodlight.openflow.protocol.OFVersion;
40 import org.slf4j.Logger; 46 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory; 47 import org.slf4j.LoggerFactory;
42 48
...@@ -46,6 +52,10 @@ import java.net.SocketAddress; ...@@ -46,6 +52,10 @@ import java.net.SocketAddress;
46 import java.util.ArrayList; 52 import java.util.ArrayList;
47 import java.util.Collections; 53 import java.util.Collections;
48 import java.util.List; 54 import java.util.List;
55 +import java.util.Set;
56 +import java.util.concurrent.CopyOnWriteArraySet;
57 +import java.util.concurrent.ExecutorService;
58 +import java.util.concurrent.Executors;
49 import java.util.concurrent.atomic.AtomicInteger; 59 import java.util.concurrent.atomic.AtomicInteger;
50 import java.util.concurrent.atomic.AtomicReference; 60 import java.util.concurrent.atomic.AtomicReference;
51 import java.util.stream.Collectors; 61 import java.util.stream.Collectors;
...@@ -82,6 +92,11 @@ public abstract class AbstractOpenFlowSwitch extends AbstractHandlerBehaviour ...@@ -82,6 +92,11 @@ public abstract class AbstractOpenFlowSwitch extends AbstractHandlerBehaviour
82 protected OFFeaturesReply features; 92 protected OFFeaturesReply features;
83 protected OFDescStatsReply desc; 93 protected OFDescStatsReply desc;
84 94
95 + protected Set<OpenFlowEventListener> ofEventListener = new CopyOnWriteArraySet<>();
96 +
97 + protected ExecutorService executorMsgs =
98 + Executors.newFixedThreadPool(2, groupedThreads("onos/of", "ctrl-msg-stats-%d"));
99 +
85 private final AtomicReference<List<OFMessage>> messagesPendingMastership 100 private final AtomicReference<List<OFMessage>> messagesPendingMastership
86 = new AtomicReference<>(); 101 = new AtomicReference<>();
87 102
...@@ -148,6 +163,15 @@ public abstract class AbstractOpenFlowSwitch extends AbstractHandlerBehaviour ...@@ -148,6 +163,15 @@ public abstract class AbstractOpenFlowSwitch extends AbstractHandlerBehaviour
148 dpid, role, channel.isConnected(), msgs); 163 dpid, role, channel.isConnected(), msgs);
149 } 164 }
150 } 165 }
166 +
167 + // listen to outgoing control messages
168 + msgs.forEach(m -> {
169 + if (m.getType() == OFType.PACKET_OUT ||
170 + m.getType() == OFType.FLOW_MOD ||
171 + m.getType() == OFType.STATS_REQUEST) {
172 + executorMsgs.submit(new OFMessageHandler(dpid, m));
173 + }
174 + });
151 } 175 }
152 176
153 private void sendMsgsOnChannel(List<OFMessage> msgs) { 177 private void sendMsgsOnChannel(List<OFMessage> msgs) {
...@@ -301,6 +325,16 @@ public abstract class AbstractOpenFlowSwitch extends AbstractHandlerBehaviour ...@@ -301,6 +325,16 @@ public abstract class AbstractOpenFlowSwitch extends AbstractHandlerBehaviour
301 } 325 }
302 326
303 @Override 327 @Override
328 + public void addEventListener(OpenFlowEventListener listener) {
329 + ofEventListener.add(listener);
330 + }
331 +
332 + @Override
333 + public void removeEventListener(OpenFlowEventListener listener) {
334 + ofEventListener.remove(listener);
335 + }
336 +
337 + @Override
304 public OFFactory factory() { 338 public OFFactory factory() {
305 return OFFactories.getFactory(ofVersion); 339 return OFFactories.getFactory(ofVersion);
306 } 340 }
...@@ -491,4 +525,25 @@ public abstract class AbstractOpenFlowSwitch extends AbstractHandlerBehaviour ...@@ -491,4 +525,25 @@ public abstract class AbstractOpenFlowSwitch extends AbstractHandlerBehaviour
491 ? channel.getRemoteAddress() : "?") 525 ? channel.getRemoteAddress() : "?")
492 + " DPID[" + ((getStringId() != null) ? getStringId() : "?") + "]]"; 526 + " DPID[" + ((getStringId() != null) ? getStringId() : "?") + "]]";
493 } 527 }
528 +
529 + /**
530 + * OpenFlow message handler for outgoing control messages.
531 + */
532 + protected final class OFMessageHandler implements Runnable {
533 +
534 + protected final OFMessage msg;
535 + protected final Dpid dpid;
536 +
537 + public OFMessageHandler(Dpid dpid, OFMessage msg) {
538 + this.msg = msg;
539 + this.dpid = dpid;
540 + }
541 +
542 + @Override
543 + public void run() {
544 + for (OpenFlowEventListener listener : ofEventListener) {
545 + listener.handleMessage(dpid, msg);
546 + }
547 + }
548 + }
494 } 549 }
......
...@@ -217,5 +217,4 @@ public interface OpenFlowSwitchDriver extends OpenFlowSwitch, HandlerBehaviour { ...@@ -217,5 +217,4 @@ public interface OpenFlowSwitchDriver extends OpenFlowSwitch, HandlerBehaviour {
217 * @param message an OpenFlow message 217 * @param message an OpenFlow message
218 */ 218 */
219 void sendHandshakeMessage(OFMessage message); 219 void sendHandshakeMessage(OFMessage message);
220 -
221 } 220 }
......
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.openflow.controller.driver;
17 +
18 +import org.junit.Before;
19 +import org.junit.Test;
20 +import org.projectfloodlight.openflow.protocol.OFMessage;
21 +import org.jboss.netty.channel.Channel;
22 +import java.util.ArrayList;
23 +import java.util.List;
24 +import java.util.concurrent.Future;
25 +
26 +import static org.hamcrest.MatcherAssert.assertThat;
27 +import static org.hamcrest.Matchers.hasSize;
28 +import static org.hamcrest.Matchers.is;
29 +
30 +/**
31 + * Tests for packet processing in the abstract openflow switch class.
32 + */
33 +public class AbstractOpenFlowSwitchTest {
34 +
35 + OpenFlowSwitchImpl ofSwitch;
36 + TestExecutorService executorService;
37 +
38 + /**
39 + * Mock executor service that tracks submits.
40 + */
41 + static class TestExecutorService extends ExecutorServiceAdapter {
42 + private List<OFMessage> submittedMessages = new ArrayList<>();
43 +
44 + List<OFMessage> submittedMessages() {
45 + return submittedMessages;
46 + }
47 +
48 + @Override
49 + public Future<?> submit(Runnable task) {
50 + AbstractOpenFlowSwitch.OFMessageHandler handler =
51 + (AbstractOpenFlowSwitch.OFMessageHandler) task;
52 + submittedMessages.add(handler.msg);
53 + return null;
54 + }
55 + }
56 +
57 + /**
58 + * Sets up switches to use as data.
59 + */
60 + @Before
61 + public void setUp() {
62 + ofSwitch = new OpenFlowSwitchImpl();
63 +
64 + executorService = new TestExecutorService();
65 + ofSwitch.executorMsgs = executorService;
66 + Channel channel = new ChannelAdapter();
67 + ofSwitch.setChannel(channel);
68 + }
69 +
70 + /**
71 + * Tests a packet out operation.
72 + */
73 + @Test
74 + public void testPacketOut() {
75 + OFMessage ofPacketOut = new MockOfPacketOut();
76 + ofSwitch.sendMsg(ofPacketOut);
77 + assertThat(executorService.submittedMessages(), hasSize(1));
78 + assertThat(executorService.submittedMessages().get(0), is(ofPacketOut));
79 + }
80 +
81 + /**
82 + * Tests a flow mod operation.
83 + */
84 + @Test
85 + public void testFlowMod() {
86 + OFMessage ofFlowMod = new MockOfFlowMod();
87 + ofSwitch.sendMsg(ofFlowMod);
88 + assertThat(executorService.submittedMessages(), hasSize(1));
89 + assertThat(executorService.submittedMessages().get(0), is(ofFlowMod));
90 + }
91 +
92 + /**
93 + * Tests a stats request operation.
94 + */
95 + @Test
96 + public void testStatsRequest() {
97 + OFMessage ofStatsRequest = new MockOfStatsRequest();
98 + ofSwitch.sendMsg(ofStatsRequest);
99 + assertThat(executorService.submittedMessages(), hasSize(1));
100 + assertThat(executorService.submittedMessages().get(0), is(ofStatsRequest));
101 + }
102 +
103 + protected class OpenFlowSwitchImpl extends AbstractOpenFlowSwitch {
104 +
105 + @Override
106 + public Boolean supportNxRole() {
107 + return null;
108 + }
109 +
110 + @Override
111 + public void startDriverHandshake() {
112 + }
113 +
114 + @Override
115 + public boolean isDriverHandshakeComplete() {
116 + return false;
117 + }
118 +
119 + @Override
120 + public void processDriverHandshakeMessage(OFMessage m) {
121 + }
122 + }
123 +}
1 +/*
2 + * Copyright 2014-2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.openflow.controller.driver;
17 +
18 +import java.net.SocketAddress;
19 +
20 +import org.jboss.netty.channel.Channel;
21 +import org.jboss.netty.channel.ChannelConfig;
22 +import org.jboss.netty.channel.ChannelFactory;
23 +import org.jboss.netty.channel.ChannelFuture;
24 +import org.jboss.netty.channel.ChannelPipeline;
25 +
26 +/**
27 + * Adapter for testing against a netty channel.
28 + */
29 +public class ChannelAdapter implements Channel {
30 + @Override
31 + public Integer getId() {
32 + return null;
33 + }
34 +
35 + @Override
36 + public ChannelFactory getFactory() {
37 + return null;
38 + }
39 +
40 + @Override
41 + public Channel getParent() {
42 + return null;
43 + }
44 +
45 + @Override
46 + public ChannelConfig getConfig() {
47 + return null;
48 + }
49 +
50 + @Override
51 + public ChannelPipeline getPipeline() {
52 + return null;
53 + }
54 +
55 + @Override
56 + public boolean isOpen() {
57 + return false;
58 + }
59 +
60 + @Override
61 + public boolean isBound() {
62 + return false;
63 + }
64 +
65 + @Override
66 + public boolean isConnected() {
67 + return false;
68 + }
69 +
70 + @Override
71 + public SocketAddress getLocalAddress() {
72 + return null;
73 + }
74 +
75 + @Override
76 + public SocketAddress getRemoteAddress() {
77 + return null;
78 + }
79 +
80 + @Override
81 + public ChannelFuture write(Object o) {
82 + return null;
83 + }
84 +
85 + @Override
86 + public ChannelFuture write(Object o, SocketAddress socketAddress) {
87 + return null;
88 + }
89 +
90 + @Override
91 + public ChannelFuture bind(SocketAddress socketAddress) {
92 + return null;
93 + }
94 +
95 + @Override
96 + public ChannelFuture connect(SocketAddress socketAddress) {
97 + return null;
98 + }
99 +
100 + @Override
101 + public ChannelFuture disconnect() {
102 + return null;
103 + }
104 +
105 + @Override
106 + public ChannelFuture unbind() {
107 + return null;
108 + }
109 +
110 + @Override
111 + public ChannelFuture close() {
112 + return null;
113 + }
114 +
115 + @Override
116 + public ChannelFuture getCloseFuture() {
117 + return null;
118 + }
119 +
120 + @Override
121 + public int getInterestOps() {
122 + return 0;
123 + }
124 +
125 + @Override
126 + public boolean isReadable() {
127 + return false;
128 + }
129 +
130 + @Override
131 + public boolean isWritable() {
132 + return false;
133 + }
134 +
135 + @Override
136 + public ChannelFuture setInterestOps(int i) {
137 + return null;
138 + }
139 +
140 + @Override
141 + public ChannelFuture setReadable(boolean b) {
142 + return null;
143 + }
144 +
145 + @Override
146 + public Object getAttachment() {
147 + return null;
148 + }
149 +
150 + @Override
151 + public void setAttachment(Object o) {
152 +
153 + }
154 +
155 + @Override
156 + public int compareTo(Channel o) {
157 + return 0;
158 + }
159 +}
...\ No newline at end of file ...\ No newline at end of file
1 +/*
2 + * Copyright 2014-2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.openflow.controller.driver;
17 +
18 +import java.util.Collection;
19 +import java.util.List;
20 +import java.util.concurrent.Callable;
21 +import java.util.concurrent.ExecutionException;
22 +import java.util.concurrent.ExecutorService;
23 +import java.util.concurrent.Future;
24 +import java.util.concurrent.TimeUnit;
25 +import java.util.concurrent.TimeoutException;
26 +
27 +/**
28 + * Test harness adapter for the ExecutorService.
29 + */
30 +public class ExecutorServiceAdapter implements ExecutorService {
31 + @Override
32 + public void shutdown() {
33 +
34 + }
35 +
36 + @Override
37 + public List<Runnable> shutdownNow() {
38 + return null;
39 + }
40 +
41 + @Override
42 + public boolean isShutdown() {
43 + return false;
44 + }
45 +
46 + @Override
47 + public boolean isTerminated() {
48 + return false;
49 + }
50 +
51 + @Override
52 + public boolean awaitTermination(long timeout, TimeUnit unit)
53 + throws InterruptedException {
54 + return false;
55 + }
56 +
57 + @Override
58 + public <T> Future<T> submit(Callable<T> task) {
59 + return null;
60 + }
61 +
62 + @Override
63 + public <T> Future<T> submit(Runnable task, T result) {
64 + return null;
65 + }
66 +
67 + @Override
68 + public Future<?> submit(Runnable task) {
69 + return null;
70 + }
71 +
72 + @Override
73 + public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
74 + throws InterruptedException {
75 + return null;
76 + }
77 +
78 + @Override
79 + public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
80 + throws InterruptedException {
81 + return null;
82 + }
83 +
84 + @Override
85 + public <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException {
86 + return null;
87 + }
88 +
89 + @Override
90 + public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
91 + throws InterruptedException, ExecutionException, TimeoutException {
92 + return null;
93 + }
94 +
95 + @Override
96 + public void execute(Runnable command) {
97 +
98 + }
99 +}
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.openflow.controller.driver;
17 +
18 +
19 +import org.projectfloodlight.openflow.protocol.OFFlowMod;
20 +import org.projectfloodlight.openflow.protocol.OFFlowModCommand;
21 +import org.projectfloodlight.openflow.protocol.OFType;
22 +import org.projectfloodlight.openflow.protocol.OFFlowModFlags;
23 +import org.projectfloodlight.openflow.protocol.action.OFAction;
24 +import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
25 +import org.projectfloodlight.openflow.protocol.match.Match;
26 +import org.projectfloodlight.openflow.types.OFBufferId;
27 +import org.projectfloodlight.openflow.types.OFPort;
28 +import org.projectfloodlight.openflow.types.TableId;
29 +import org.projectfloodlight.openflow.types.U64;
30 +import org.projectfloodlight.openflow.types.OFGroup;
31 +
32 +import java.util.List;
33 +import java.util.Set;
34 +
35 +/**
36 + * Mock of the Open Flow flow mod message.
37 + */
38 +public class MockOfFlowMod extends OfMessageAdapter implements OFFlowMod {
39 +
40 + public MockOfFlowMod() {
41 + super(OFType.FLOW_MOD);
42 + }
43 +
44 + @Override
45 + public U64 getCookie() {
46 + return null;
47 + }
48 +
49 + @Override
50 + public U64 getCookieMask() throws UnsupportedOperationException {
51 + return null;
52 + }
53 +
54 + @Override
55 + public TableId getTableId() throws UnsupportedOperationException {
56 + return null;
57 + }
58 +
59 + @Override
60 + public OFFlowModCommand getCommand() {
61 + return null;
62 + }
63 +
64 + @Override
65 + public int getIdleTimeout() {
66 + return 0;
67 + }
68 +
69 + @Override
70 + public int getHardTimeout() {
71 + return 0;
72 + }
73 +
74 + @Override
75 + public int getPriority() {
76 + return 0;
77 + }
78 +
79 + @Override
80 + public OFBufferId getBufferId() {
81 + return null;
82 + }
83 +
84 + @Override
85 + public OFPort getOutPort() {
86 + return null;
87 + }
88 +
89 + @Override
90 + public OFGroup getOutGroup() throws UnsupportedOperationException {
91 + return null;
92 + }
93 +
94 + @Override
95 + public Set<OFFlowModFlags> getFlags() {
96 + return null;
97 + }
98 +
99 + @Override
100 + public Match getMatch() {
101 + return null;
102 + }
103 +
104 + @Override
105 + public List<OFInstruction> getInstructions() throws UnsupportedOperationException {
106 + return null;
107 + }
108 +
109 + @Override
110 + public List<OFAction> getActions() throws UnsupportedOperationException {
111 + return null;
112 + }
113 +
114 + @Override
115 + public OFFlowMod.Builder createBuilder() {
116 + return null;
117 + }
118 +}
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.openflow.controller.driver;
17 +
18 +import org.projectfloodlight.openflow.protocol.OFPacketOut;
19 +import org.projectfloodlight.openflow.protocol.OFType;
20 +import org.projectfloodlight.openflow.protocol.action.OFAction;
21 +import org.projectfloodlight.openflow.types.OFBufferId;
22 +import org.projectfloodlight.openflow.types.OFPort;
23 +
24 +import java.util.List;
25 +
26 +/**
27 + * Mock of the Open Flow packet out message.
28 + */
29 +public class MockOfPacketOut extends OfMessageAdapter implements OFPacketOut {
30 +
31 + public MockOfPacketOut() {
32 + super(OFType.PACKET_OUT);
33 + }
34 +
35 + @Override
36 + public OFBufferId getBufferId() {
37 + return null;
38 + }
39 +
40 + @Override
41 + public OFPort getInPort() {
42 + return null;
43 + }
44 +
45 + @Override
46 + public List<OFAction> getActions() {
47 + return null;
48 + }
49 +
50 + @Override
51 + public byte[] getData() {
52 + return new byte[0];
53 + }
54 +
55 + @Override
56 + public OFPacketOut.Builder createBuilder() {
57 + return null;
58 + }
59 +}
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.openflow.controller.driver;
17 +
18 +
19 +
20 +import org.projectfloodlight.openflow.protocol.OFStatsRequest;
21 +import org.projectfloodlight.openflow.protocol.OFStatsType;
22 +import org.projectfloodlight.openflow.protocol.OFType;
23 +import org.projectfloodlight.openflow.protocol.OFStatsReplyFlags;
24 +
25 +import java.util.Set;
26 +
27 +/**
28 + * Mock of the Open Flow stats request message.
29 + */
30 +public class MockOfStatsRequest extends OfMessageAdapter implements OFStatsRequest {
31 +
32 + public MockOfStatsRequest() {
33 + super(OFType.STATS_REQUEST);
34 + }
35 +
36 + @Override
37 + public OFStatsType getStatsType() {
38 + return null;
39 + }
40 +
41 + @Override
42 + public Set<OFStatsReplyFlags> getFlags() {
43 + return null;
44 + }
45 +
46 + @Override
47 + public OFStatsRequest.Builder createBuilder() {
48 + return null;
49 + }
50 +}
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.openflow.controller.driver;
17 +
18 +import org.jboss.netty.buffer.ChannelBuffer;
19 +import org.projectfloodlight.openflow.protocol.OFMessage;
20 +import org.projectfloodlight.openflow.protocol.OFType;
21 +import org.projectfloodlight.openflow.protocol.OFVersion;
22 +
23 +import com.google.common.hash.PrimitiveSink;
24 +
25 +/**
26 + * Adapter for testing against an OpenFlow message.
27 + */
28 +public class OfMessageAdapter implements OFMessage {
29 + OFType type;
30 +
31 + private OfMessageAdapter() {}
32 +
33 + public OfMessageAdapter(OFType type) {
34 + this.type = type;
35 + }
36 +
37 + @Override
38 + public OFType getType() {
39 + return type;
40 + }
41 +
42 + @Override
43 + public OFVersion getVersion() {
44 + return null;
45 + }
46 +
47 + @Override
48 + public long getXid() {
49 + return 0;
50 + }
51 +
52 + @Override
53 + public void writeTo(ChannelBuffer channelBuffer) { }
54 +
55 + @Override
56 + public Builder createBuilder() {
57 + return null;
58 + }
59 +
60 + @Override
61 + public void putTo(PrimitiveSink sink) { }
62 +}
...@@ -272,10 +272,13 @@ public class OpenFlowControllerImpl implements OpenFlowController { ...@@ -272,10 +272,13 @@ public class OpenFlowControllerImpl implements OpenFlowController {
272 for (PacketListener p : ofPacketListener.values()) { 272 for (PacketListener p : ofPacketListener.values()) {
273 p.handlePacket(pktCtx); 273 p.handlePacket(pktCtx);
274 } 274 }
275 + executorMsgs.submit(new OFMessageHandler(dpid, msg));
275 break; 276 break;
276 // TODO: Consider using separate threadpool for sensitive messages. 277 // TODO: Consider using separate threadpool for sensitive messages.
277 // ie. Back to back error could cause us to starve. 278 // ie. Back to back error could cause us to starve.
278 case FLOW_REMOVED: 279 case FLOW_REMOVED:
280 + executorMsgs.submit(new OFMessageHandler(dpid, msg));
281 + break;
279 case ERROR: 282 case ERROR:
280 executorMsgs.submit(new OFMessageHandler(dpid, msg)); 283 executorMsgs.submit(new OFMessageHandler(dpid, msg));
281 break; 284 break;
...@@ -625,6 +628,9 @@ public class OpenFlowControllerImpl implements OpenFlowController { ...@@ -625,6 +628,9 @@ public class OpenFlowControllerImpl implements OpenFlowController {
625 } 628 }
626 } 629 }
627 630
631 + /**
632 + * OpenFlow message handler for incoming control messages.
633 + */
628 protected final class OFMessageHandler implements Runnable { 634 protected final class OFMessageHandler implements Runnable {
629 635
630 protected final OFMessage msg; 636 protected final OFMessage msg;
...@@ -641,7 +647,5 @@ public class OpenFlowControllerImpl implements OpenFlowController { ...@@ -641,7 +647,5 @@ public class OpenFlowControllerImpl implements OpenFlowController {
641 listener.handleMessage(dpid, msg); 647 listener.handleMessage(dpid, msg);
642 } 648 }
643 } 649 }
644 -
645 } 650 }
646 -
647 } 651 }
......
...@@ -22,6 +22,7 @@ import org.onosproject.net.Device; ...@@ -22,6 +22,7 @@ import org.onosproject.net.Device;
22 import org.onosproject.net.driver.DriverData; 22 import org.onosproject.net.driver.DriverData;
23 import org.onosproject.net.driver.DriverHandler; 23 import org.onosproject.net.driver.DriverHandler;
24 import org.onosproject.openflow.controller.Dpid; 24 import org.onosproject.openflow.controller.Dpid;
25 +import org.onosproject.openflow.controller.OpenFlowEventListener;
25 import org.onosproject.openflow.controller.RoleState; 26 import org.onosproject.openflow.controller.RoleState;
26 import org.onosproject.openflow.controller.driver.OpenFlowAgent; 27 import org.onosproject.openflow.controller.driver.OpenFlowAgent;
27 import org.onosproject.openflow.controller.driver.OpenFlowSwitchDriver; 28 import org.onosproject.openflow.controller.driver.OpenFlowSwitchDriver;
...@@ -299,4 +300,12 @@ public class OpenflowSwitchDriverAdapter implements OpenFlowSwitchDriver { ...@@ -299,4 +300,12 @@ public class OpenflowSwitchDriverAdapter implements OpenFlowSwitchDriver {
299 public String channelId() { 300 public String channelId() {
300 return null; 301 return null;
301 } 302 }
303 +
304 + @Override
305 + public void addEventListener(OpenFlowEventListener listener) {
306 + }
307 +
308 + @Override
309 + public void removeEventListener(OpenFlowEventListener listener) {
310 + }
302 } 311 }
......
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.openflow.controller.impl;
17 +
18 +import org.onosproject.openflow.OfMessageAdapter;
19 +import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
20 +import org.projectfloodlight.openflow.protocol.OFType;
21 +import org.projectfloodlight.openflow.protocol.match.Match;
22 +import org.projectfloodlight.openflow.types.TableId;
23 +import org.projectfloodlight.openflow.types.U64;
24 +
25 +/**
26 + * Mock of the Open Flow packet removed message.
27 + */
28 +public class MockOfFlowRemoved extends OfMessageAdapter implements OFFlowRemoved {
29 +
30 + public MockOfFlowRemoved() {
31 + super(OFType.FLOW_REMOVED);
32 + }
33 +
34 + @Override
35 + public U64 getCookie() {
36 + return null;
37 + }
38 +
39 + @Override
40 + public int getPriority() {
41 + return 0;
42 + }
43 +
44 + @Override
45 + public short getReason() {
46 + return 0;
47 + }
48 +
49 + @Override
50 + public TableId getTableId() throws UnsupportedOperationException {
51 + return null;
52 + }
53 +
54 + @Override
55 + public long getDurationSec() {
56 + return 0;
57 + }
58 +
59 + @Override
60 + public long getDurationNsec() {
61 + return 0;
62 + }
63 +
64 + @Override
65 + public int getIdleTimeout() {
66 + return 0;
67 + }
68 +
69 + @Override
70 + public int getHardTimeout() throws UnsupportedOperationException {
71 + return 0;
72 + }
73 +
74 + @Override
75 + public U64 getPacketCount() {
76 + return null;
77 + }
78 +
79 + @Override
80 + public U64 getByteCount() {
81 + return null;
82 + }
83 +
84 + @Override
85 + public Match getMatch() {
86 + return null;
87 + }
88 +
89 + @Override
90 + public OFFlowRemoved.Builder createBuilder() {
91 + return null;
92 + }
93 +}
...@@ -24,12 +24,12 @@ import java.util.concurrent.Future; ...@@ -24,12 +24,12 @@ import java.util.concurrent.Future;
24 import org.junit.Before; 24 import org.junit.Before;
25 import org.junit.Test; 25 import org.junit.Test;
26 import org.onosproject.openflow.ExecutorServiceAdapter; 26 import org.onosproject.openflow.ExecutorServiceAdapter;
27 -import org.onosproject.openflow.MockOfFeaturesReply;
28 -import org.onosproject.openflow.MockOfPacketIn;
29 import org.onosproject.openflow.MockOfPortStatus; 27 import org.onosproject.openflow.MockOfPortStatus;
30 -import org.onosproject.openflow.OfMessageAdapter;
31 import org.onosproject.openflow.OpenFlowSwitchListenerAdapter; 28 import org.onosproject.openflow.OpenFlowSwitchListenerAdapter;
32 import org.onosproject.openflow.OpenflowSwitchDriverAdapter; 29 import org.onosproject.openflow.OpenflowSwitchDriverAdapter;
30 +import org.onosproject.openflow.MockOfFeaturesReply;
31 +import org.onosproject.openflow.MockOfPacketIn;
32 +import org.onosproject.openflow.OfMessageAdapter;
33 import org.onosproject.openflow.controller.Dpid; 33 import org.onosproject.openflow.controller.Dpid;
34 import org.onosproject.openflow.controller.OpenFlowPacketContext; 34 import org.onosproject.openflow.controller.OpenFlowPacketContext;
35 import org.onosproject.openflow.controller.OpenFlowSwitch; 35 import org.onosproject.openflow.controller.OpenFlowSwitch;
...@@ -143,14 +143,16 @@ public class OpenFlowControllerImplPacketsTest { ...@@ -143,14 +143,16 @@ public class OpenFlowControllerImplPacketsTest {
143 } 143 }
144 144
145 /** 145 /**
146 - * Tests a packet in operation. 146 + * Tests a packet in listen operation.
147 */ 147 */
148 @Test 148 @Test
149 - public void testPacketIn() { 149 + public void testPacketInListen() {
150 agent.addConnectedSwitch(dpid1, switch1); 150 agent.addConnectedSwitch(dpid1, switch1);
151 OFMessage packetInPacket = new MockOfPacketIn(); 151 OFMessage packetInPacket = new MockOfPacketIn();
152 controller.processPacket(dpid1, packetInPacket); 152 controller.processPacket(dpid1, packetInPacket);
153 assertThat(packetListener.contexts(), hasSize(1)); 153 assertThat(packetListener.contexts(), hasSize(1));
154 + assertThat(executorService.submittedMessages(), hasSize(1));
155 + assertThat(executorService.submittedMessages().get(0), is(packetInPacket));
154 } 156 }
155 157
156 /** 158 /**
...@@ -164,4 +166,16 @@ public class OpenFlowControllerImplPacketsTest { ...@@ -164,4 +166,16 @@ public class OpenFlowControllerImplPacketsTest {
164 assertThat(executorService.submittedMessages(), hasSize(1)); 166 assertThat(executorService.submittedMessages(), hasSize(1));
165 assertThat(executorService.submittedMessages().get(0), is(errorPacket)); 167 assertThat(executorService.submittedMessages().get(0), is(errorPacket));
166 } 168 }
169 +
170 + /**
171 + * Tests a packet in operation.
172 + */
173 + @Test
174 + public void testFlowRemoved() {
175 + agent.addConnectedSwitch(dpid1, switch1);
176 + OFMessage flowRemovedPacket = new MockOfFlowRemoved();
177 + controller.processPacket(dpid1, flowRemovedPacket);
178 + assertThat(executorService.submittedMessages(), hasSize(1));
179 + assertThat(executorService.submittedMessages().get(0), is(flowRemovedPacket));
180 + }
167 } 181 }
......
...@@ -140,6 +140,12 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr ...@@ -140,6 +140,12 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr
140 140
141 private final InternalDeviceProvider listener = new InternalDeviceProvider(); 141 private final InternalDeviceProvider listener = new InternalDeviceProvider();
142 142
143 + private final IncomingMessageProvider inMsgListener = new IncomingMessageProvider();
144 +
145 + private final OutgoingMessageProvider outMsgListener = new OutgoingMessageProvider();
146 +
147 + private boolean isCtrlMsgMonitor;
148 +
143 // TODO: We need to make the poll interval configurable. 149 // TODO: We need to make the poll interval configurable.
144 static final int POLL_INTERVAL = 5; 150 static final int POLL_INTERVAL = 5;
145 @Property(name = "PortStatsPollFrequency", intValue = POLL_INTERVAL, 151 @Property(name = "PortStatsPollFrequency", intValue = POLL_INTERVAL,
...@@ -161,6 +167,7 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr ...@@ -161,6 +167,7 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr
161 providerService = providerRegistry.register(this); 167 providerService = providerRegistry.register(this);
162 controller.addListener(listener); 168 controller.addListener(listener);
163 controller.addEventListener(listener); 169 controller.addEventListener(listener);
170 +
164 connectInitialDevices(); 171 connectInitialDevices();
165 LOG.info("Started"); 172 LOG.info("Started");
166 } 173 }
...@@ -264,6 +271,31 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr ...@@ -264,6 +271,31 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr
264 LOG.debug("Accepting mastership role change for device {}", deviceId); 271 LOG.debug("Accepting mastership role change for device {}", deviceId);
265 } 272 }
266 273
274 +
275 + /**
276 + * Enable OpenFlow control message monitoring.
277 + */
278 + public void enableCtrlMsgMonitor() {
279 + isCtrlMsgMonitor = true;
280 + controller.addEventListener(inMsgListener);
281 + for (OpenFlowSwitch sw : controller.getSwitches()) {
282 + sw.addEventListener(outMsgListener);
283 + }
284 + LOG.info("Enable control message monitoring.");
285 + }
286 +
287 + /**
288 + * Disable OpenFlow control message monitoring.
289 + */
290 + public void disableCtrlMsgMonitor() {
291 + isCtrlMsgMonitor = false;
292 + controller.removeEventListener(inMsgListener);
293 + for (OpenFlowSwitch sw: controller.getSwitches()) {
294 + sw.removeEventListener(outMsgListener);
295 + }
296 + LOG.info("Disable control message monitoring");
297 + }
298 +
267 private void pushPortMetrics(Dpid dpid, List<OFPortStatsEntry> portStatsEntries) { 299 private void pushPortMetrics(Dpid dpid, List<OFPortStatsEntry> portStatsEntries) {
268 DeviceId deviceId = DeviceId.deviceId(dpid.uri(dpid)); 300 DeviceId deviceId = DeviceId.deviceId(dpid.uri(dpid));
269 Collection<PortStatistics> stats = buildPortStatistics(deviceId, portStatsEntries); 301 Collection<PortStatistics> stats = buildPortStatistics(deviceId, portStatsEntries);
...@@ -304,6 +336,32 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr ...@@ -304,6 +336,32 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr
304 336
305 } 337 }
306 338
339 + /**
340 + * A listener for incoming OpenFlow messages.
341 + */
342 + private class IncomingMessageProvider implements OpenFlowEventListener {
343 +
344 + @Override
345 + public void handleMessage(Dpid dpid, OFMessage msg) {
346 + if (isCtrlMsgMonitor) {
347 + // TODO: feed the control message stats via ControlMetricsServiceFactory
348 + }
349 + }
350 + }
351 +
352 + /**
353 + * A listener for outgoing OpenFlow messages.
354 + */
355 + private class OutgoingMessageProvider implements OpenFlowEventListener {
356 +
357 + @Override
358 + public void handleMessage(Dpid dpid, OFMessage msg) {
359 + if (isCtrlMsgMonitor) {
360 + // TODO: feed the control message stats via ControlMetricsServiceFactory
361 + }
362 + }
363 + }
364 +
307 private class InternalDeviceProvider implements OpenFlowSwitchListener, OpenFlowEventListener { 365 private class InternalDeviceProvider implements OpenFlowSwitchListener, OpenFlowEventListener {
308 366
309 private HashMap<Dpid, List<OFPortStatsEntry>> portStatsReplies = new HashMap<>(); 367 private HashMap<Dpid, List<OFPortStatsEntry>> portStatsReplies = new HashMap<>();
...@@ -319,6 +377,11 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr ...@@ -319,6 +377,11 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr
319 return; 377 return;
320 } 378 }
321 379
380 + if (isCtrlMsgMonitor) {
381 + // start to monitor the outgoing control messages
382 + sw.addEventListener(outMsgListener);
383 + }
384 +
322 ChassisId cId = new ChassisId(dpid.value()); 385 ChassisId cId = new ChassisId(dpid.value());
323 386
324 SparseAnnotations annotations = DefaultAnnotations.builder() 387 SparseAnnotations annotations = DefaultAnnotations.builder()
...@@ -359,6 +422,14 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr ...@@ -359,6 +422,14 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr
359 if (collector != null) { 422 if (collector != null) {
360 collector.stop(); 423 collector.stop();
361 } 424 }
425 +
426 + OpenFlowSwitch sw = controller.getSwitch(dpid);
427 + if (sw != null) {
428 + if (isCtrlMsgMonitor) {
429 + // stop monitoring the outgoing control messages
430 + sw.removeEventListener(outMsgListener);
431 + }
432 + }
362 } 433 }
363 434
364 @Override 435 @Override
......
...@@ -398,6 +398,14 @@ public class OpenFlowDeviceProviderTest { ...@@ -398,6 +398,14 @@ public class OpenFlowDeviceProviderTest {
398 return "1.2.3.4:1"; 398 return "1.2.3.4:1";
399 } 399 }
400 400
401 + @Override
402 + public void addEventListener(OpenFlowEventListener listener) {
403 + }
404 +
405 + @Override
406 + public void removeEventListener(OpenFlowEventListener listener) {
407 + }
408 +
401 } 409 }
402 410
403 } 411 }
......
...@@ -408,5 +408,13 @@ public class OpenFlowGroupProviderTest { ...@@ -408,5 +408,13 @@ public class OpenFlowGroupProviderTest {
408 return null; 408 return null;
409 } 409 }
410 410
411 + @Override
412 + public void addEventListener(OpenFlowEventListener listener) {
413 + }
414 +
415 + @Override
416 + public void removeEventListener(OpenFlowEventListener listener) {
417 + }
418 +
411 } 419 }
412 } 420 }
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -425,6 +425,14 @@ public class OpenFlowPacketProviderTest { ...@@ -425,6 +425,14 @@ public class OpenFlowPacketProviderTest {
425 return "1.2.3.4:1"; 425 return "1.2.3.4:1";
426 } 426 }
427 427
428 + @Override
429 + public void addEventListener(OpenFlowEventListener listener) {
430 + }
431 +
432 + @Override
433 + public void removeEventListener(OpenFlowEventListener listener) {
434 + }
435 +
428 436
429 } 437 }
430 438
......