tom

Merge remote-tracking branch 'origin/master'

...@@ -5,8 +5,9 @@ import org.projectfloodlight.openflow.types.OFPort; ...@@ -5,8 +5,9 @@ import org.projectfloodlight.openflow.types.OFPort;
5 5
6 /** 6 /**
7 * A representation of a packet context which allows any provider 7 * A representation of a packet context which allows any provider
8 - * to view the packet in event but may block the response to the 8 + * to view a packet in event, but may block the response to the
9 - * event if blocked has been called. 9 + * event if blocked has been called. This packet context can be used
10 + * to react to the packet in event with a packet out.
10 */ 11 */
11 public interface OpenFlowPacketContext { 12 public interface OpenFlowPacketContext {
12 13
......
...@@ -3,6 +3,7 @@ package org.onlab.onos.provider.of.packet.impl; ...@@ -3,6 +3,7 @@ package org.onlab.onos.provider.of.packet.impl;
3 import static org.slf4j.LoggerFactory.getLogger; 3 import static org.slf4j.LoggerFactory.getLogger;
4 4
5 import java.nio.ByteBuffer; 5 import java.nio.ByteBuffer;
6 +import java.util.Collections;
6 7
7 import org.apache.felix.scr.annotations.Activate; 8 import org.apache.felix.scr.annotations.Activate;
8 import org.apache.felix.scr.annotations.Component; 9 import org.apache.felix.scr.annotations.Component;
...@@ -12,6 +13,8 @@ import org.apache.felix.scr.annotations.ReferenceCardinality; ...@@ -12,6 +13,8 @@ import org.apache.felix.scr.annotations.ReferenceCardinality;
12 import org.onlab.onos.net.ConnectPoint; 13 import org.onlab.onos.net.ConnectPoint;
13 import org.onlab.onos.net.DeviceId; 14 import org.onlab.onos.net.DeviceId;
14 import org.onlab.onos.net.PortNumber; 15 import org.onlab.onos.net.PortNumber;
16 +import org.onlab.onos.net.flow.instructions.Instruction;
17 +import org.onlab.onos.net.flow.instructions.Instructions.OutputInstruction;
15 import org.onlab.onos.net.packet.DefaultInboundPacket; 18 import org.onlab.onos.net.packet.DefaultInboundPacket;
16 import org.onlab.onos.net.packet.OutboundPacket; 19 import org.onlab.onos.net.packet.OutboundPacket;
17 import org.onlab.onos.net.packet.PacketProvider; 20 import org.onlab.onos.net.packet.PacketProvider;
...@@ -22,9 +25,20 @@ import org.onlab.onos.net.provider.ProviderId; ...@@ -22,9 +25,20 @@ import org.onlab.onos.net.provider.ProviderId;
22 import org.onlab.onos.openflow.controller.Dpid; 25 import org.onlab.onos.openflow.controller.Dpid;
23 import org.onlab.onos.openflow.controller.OpenFlowController; 26 import org.onlab.onos.openflow.controller.OpenFlowController;
24 import org.onlab.onos.openflow.controller.OpenFlowPacketContext; 27 import org.onlab.onos.openflow.controller.OpenFlowPacketContext;
28 +import org.onlab.onos.openflow.controller.OpenFlowSwitch;
25 import org.onlab.onos.openflow.controller.PacketListener; 29 import org.onlab.onos.openflow.controller.PacketListener;
30 +import org.onlab.packet.Ethernet;
31 +import org.projectfloodlight.openflow.protocol.OFPacketOut;
32 +import org.projectfloodlight.openflow.protocol.OFPortDesc;
33 +import org.projectfloodlight.openflow.protocol.action.OFAction;
34 +import org.projectfloodlight.openflow.protocol.ver10.OFFactoryVer10;
35 +import org.projectfloodlight.openflow.types.OFBufferId;
36 +import org.projectfloodlight.openflow.types.OFPort;
26 import org.slf4j.Logger; 37 import org.slf4j.Logger;
27 38
39 +import static org.onlab.onos.openflow.controller.RoleState.*;
40 +
41 +
28 /** 42 /**
29 * Provider which uses an OpenFlow controller to detect network 43 * Provider which uses an OpenFlow controller to detect network
30 * infrastructure links. 44 * infrastructure links.
...@@ -68,9 +82,61 @@ public class OpenFlowPacketProvider extends AbstractProvider implements PacketPr ...@@ -68,9 +82,61 @@ public class OpenFlowPacketProvider extends AbstractProvider implements PacketPr
68 82
69 @Override 83 @Override
70 public void emit(OutboundPacket packet) { 84 public void emit(OutboundPacket packet) {
85 + DeviceId devId = packet.sendThrough();
86 + String scheme = devId.toString().split(":")[0];
87 +
88 + if (!scheme.equals(this.id().scheme())) {
89 + throw new IllegalArgumentException(
90 + "Don't know how to handle Device with scheme " + scheme);
91 + }
92 +
93 + Dpid dpid = Dpid.dpid(devId.uri());
94 + OpenFlowSwitch sw = controller.getSwitch(dpid);
95 + if (sw == null) {
96 + log.warn("Device {} isn't available?", devId);
97 + return;
98 + } else if (sw.getRole().equals(SLAVE)) {
99 + log.warn("Can't write to Device {} as slave", devId);
100 + return;
101 + }
71 102
103 + Ethernet eth = new Ethernet();
104 + eth.deserialize(packet.data().array(), 0, packet.data().array().length);
105 + OFPortDesc p = null;
106 + for (Instruction inst : packet.treatment().instructions()) {
107 + if (inst.type().equals(Instruction.Type.OUTPUT)) {
108 + p = portDesc(((OutputInstruction) inst).port());
109 + if (!sw.getPorts().contains(p)) {
110 + log.warn("Tried to write out non-existint port {}", p.getPortNo());
111 + continue;
112 + }
113 + OFPacketOut po = packetOut(sw, eth, p.getPortNo());
114 + sw.sendMsg(po);
115 + }
116 + }
117 +
118 + }
119 +
120 + private OFPortDesc portDesc(PortNumber port) {
121 + OFPortDesc.Builder builder = OFFactoryVer10.INSTANCE.buildPortDesc();
122 + builder.setPortNo(OFPort.of((int) port.toLong()));
123 +
124 + return builder.build();
72 } 125 }
73 126
127 + private OFPacketOut packetOut(OpenFlowSwitch sw, Ethernet eth, OFPort out) {
128 + OFPacketOut.Builder builder = sw.factory().buildPacketOut();
129 + OFAction act = sw.factory().actions()
130 + .buildOutput()
131 + .setPort(out)
132 + .build();
133 + return builder
134 + .setBufferId(OFBufferId.NO_BUFFER)
135 + .setInPort(OFPort.NO_MASK)
136 + .setActions(Collections.singletonList(act))
137 + .setData(eth.serialize())
138 + .build();
139 + }
74 140
75 /** 141 /**
76 * Internal Packet Provider implementation. 142 * Internal Packet Provider implementation.
......
1 +package org.onlab.onos.provider.of.packet.impl;
2 +
3 +import static org.junit.Assert.assertEquals;
4 +import static org.junit.Assert.assertNotNull;
5 +import static org.junit.Assert.assertNull;
6 +
7 +import java.nio.ByteBuffer;
8 +import java.util.ArrayList;
9 +import java.util.List;
10 +import java.util.Set;
11 +
12 +import org.junit.After;
13 +import org.junit.Before;
14 +import org.junit.Test;
15 +import org.onlab.onos.net.DeviceId;
16 +import org.onlab.onos.net.PortNumber;
17 +import org.onlab.onos.net.flow.DefaultTrafficTreatment;
18 +import org.onlab.onos.net.flow.TrafficTreatment;
19 +import org.onlab.onos.net.flow.instructions.Instruction;
20 +import org.onlab.onos.net.flow.instructions.Instructions;
21 +import org.onlab.onos.net.packet.DefaultOutboundPacket;
22 +import org.onlab.onos.net.packet.OutboundPacket;
23 +import org.onlab.onos.net.packet.PacketContext;
24 +import org.onlab.onos.net.packet.PacketProvider;
25 +import org.onlab.onos.net.packet.PacketProviderRegistry;
26 +import org.onlab.onos.net.packet.PacketProviderService;
27 +import org.onlab.onos.net.provider.ProviderId;
28 +import org.onlab.onos.openflow.controller.DefaultOpenFlowPacketContext;
29 +import org.onlab.onos.openflow.controller.Dpid;
30 +import org.onlab.onos.openflow.controller.OpenFlowController;
31 +import org.onlab.onos.openflow.controller.OpenFlowEventListener;
32 +import org.onlab.onos.openflow.controller.OpenFlowPacketContext;
33 +import org.onlab.onos.openflow.controller.OpenFlowSwitch;
34 +import org.onlab.onos.openflow.controller.OpenFlowSwitchListener;
35 +import org.onlab.onos.openflow.controller.PacketListener;
36 +import org.onlab.onos.openflow.controller.RoleState;
37 +import org.onlab.packet.ARP;
38 +import org.onlab.packet.Ethernet;
39 +import org.onlab.packet.IpAddress;
40 +import org.projectfloodlight.openflow.protocol.OFFactory;
41 +import org.projectfloodlight.openflow.protocol.OFMessage;
42 +import org.projectfloodlight.openflow.protocol.OFPacketIn;
43 +import org.projectfloodlight.openflow.protocol.OFPacketInReason;
44 +import org.projectfloodlight.openflow.protocol.OFPortDesc;
45 +import org.projectfloodlight.openflow.protocol.ver10.OFFactoryVer10;
46 +import org.projectfloodlight.openflow.types.MacAddress;
47 +import org.projectfloodlight.openflow.types.OFBufferId;
48 +import org.projectfloodlight.openflow.types.OFPort;
49 +
50 +import com.google.common.collect.Lists;
51 +import com.google.common.collect.Sets;
52 +
53 +
54 +public class OpenFlowPacketProviderTest {
55 +
56 + private static final int PN1 = 100;
57 + private static final int PN2 = 200;
58 + private static final int PN3 = 300;
59 + private static final short VLANID = (short) 100;
60 +
61 + private static final DeviceId DID = DeviceId.deviceId("of:1");
62 + private static final DeviceId DID_MISSING = DeviceId.deviceId("of:2");
63 + private static final DeviceId DID_WRONG = DeviceId.deviceId("test:1");
64 + private static final PortNumber P1 = PortNumber.portNumber(PN1);
65 + private static final PortNumber P2 = PortNumber.portNumber(PN2);
66 + private static final PortNumber P3 = PortNumber.portNumber(PN3);
67 +
68 + private static final Instruction INST1 = Instructions.createOutput(P1);
69 + private static final Instruction INST2 = Instructions.createOutput(P2);
70 + private static final Instruction INST3 = Instructions.createOutput(P3);
71 +
72 + private static final OFPortDesc PD1 = portDesc(PN1);
73 + private static final OFPortDesc PD2 = portDesc(PN2);
74 +
75 + private static final List<OFPortDesc> PLIST = Lists.newArrayList(PD1, PD2);
76 + private static final TrafficTreatment TR = treatment(INST1, INST2);
77 + private static final TrafficTreatment TR_MISSING = treatment(INST1, INST3);
78 +
79 + private final OpenFlowPacketProvider provider = new OpenFlowPacketProvider();
80 + private final TestPacketRegistry registry = new TestPacketRegistry();
81 + private final TestController controller = new TestController();
82 +
83 + private final TestOpenFlowSwitch sw = new TestOpenFlowSwitch(PLIST);
84 +
85 + @Before
86 + public void startUp() {
87 + provider.providerRegistry = registry;
88 + provider.controller = controller;
89 + provider.activate();
90 + assertNotNull("listener should be registered", registry.listener);
91 + }
92 +
93 + @After
94 + public void teardown() {
95 + provider.deactivate();
96 + assertNull("listeners shouldn't be registered", registry.listener);
97 + provider.controller = null;
98 + provider.providerRegistry = null;
99 + }
100 +
101 + @Test(expected = IllegalArgumentException.class)
102 + public void wrongScheme() {
103 + sw.setRole(RoleState.MASTER);
104 + OutboundPacket schemeFailPkt = outPacket(DID_WRONG, TR, null);
105 + provider.emit(schemeFailPkt);
106 + assertEquals("message sent incorrectly", 0, sw.sent.size());
107 + }
108 +
109 + @Test
110 + public void emit() {
111 +
112 + MacAddress mac1 = MacAddress.of("00:00:00:11:00:01");
113 + MacAddress mac2 = MacAddress.of("00:00:00:22:00:02");
114 +
115 + ARP arp = new ARP();
116 + arp.setSenderProtocolAddress(IpAddress.ANY)
117 + .setSenderHardwareAddress(mac1.getBytes())
118 + .setTargetHardwareAddress(mac2.getBytes())
119 + .setTargetProtocolAddress(IpAddress.ANY)
120 + .setHardwareType((short) 0)
121 + .setProtocolType((short) 0)
122 + .setHardwareAddressLength((byte) 6)
123 + .setProtocolAddressLength((byte) 4)
124 + .setOpCode((byte) 0);
125 +
126 + Ethernet eth = new Ethernet();
127 + eth.setVlanID(VLANID)
128 + .setEtherType(Ethernet.TYPE_ARP)
129 + .setSourceMACAddress("00:00:00:11:00:01")
130 + .setDestinationMACAddress("00:00:00:22:00:02")
131 + .setPayload(arp);
132 +
133 + //the should-be working setup.
134 + OutboundPacket passPkt = outPacket(DID, TR, eth);
135 + sw.setRole(RoleState.MASTER);
136 + provider.emit(passPkt);
137 + assertEquals("invalid switch", sw, controller.current);
138 + assertEquals("message not sent", PLIST.size(), sw.sent.size());
139 + sw.sent.clear();
140 +
141 + //wrong Role
142 + sw.setRole(RoleState.SLAVE);
143 + provider.emit(passPkt);
144 + assertEquals("invalid switch", sw, controller.current);
145 + assertEquals("message sent incorrectly", 0, sw.sent.size());
146 +
147 + sw.setRole(RoleState.MASTER);
148 +
149 + //missing switch
150 + OutboundPacket swFailPkt = outPacket(DID_MISSING, TR, eth);
151 + provider.emit(swFailPkt);
152 + assertNull("invalid switch", controller.current);
153 + assertEquals("message sent incorrectly", 0, sw.sent.size());
154 +
155 + //to missing port
156 + OutboundPacket portFailPkt = outPacket(DID, TR_MISSING, eth);
157 + provider.emit(portFailPkt);
158 + assertEquals("extra message sent", 1, sw.sent.size());
159 +
160 + }
161 +
162 + @Test
163 + public void handlePacket() {
164 + OFPacketIn pkt = sw.factory().buildPacketIn()
165 + .setBufferId(OFBufferId.NO_BUFFER)
166 + .setInPort(OFPort.NO_MASK)
167 + .setReason(OFPacketInReason.INVALID_TTL)
168 + .build();
169 +
170 + controller.processPacket(null, pkt);
171 + assertNotNull("message unprocessed", registry.ctx);
172 +
173 + }
174 +
175 + private static OFPortDesc portDesc(int port) {
176 + OFPortDesc.Builder builder = OFFactoryVer10.INSTANCE.buildPortDesc();
177 + builder.setPortNo(OFPort.of(port));
178 +
179 + return builder.build();
180 + }
181 +
182 + private static TrafficTreatment treatment(Instruction ... insts) {
183 + TrafficTreatment.Builder builder = new DefaultTrafficTreatment.Builder();
184 + for (Instruction i : insts) {
185 + builder.add(i);
186 + }
187 + return builder.build();
188 + }
189 +
190 + private static OutboundPacket outPacket(
191 + DeviceId d, TrafficTreatment t, Ethernet e) {
192 + ByteBuffer buf = null;
193 + if (e != null) {
194 + buf = ByteBuffer.wrap(e.serialize());
195 + }
196 + return new DefaultOutboundPacket(d, t, buf);
197 + }
198 +
199 + private class TestPacketRegistry implements PacketProviderRegistry {
200 +
201 + PacketProvider listener = null;
202 + PacketContext ctx = null;
203 +
204 + @Override
205 + public PacketProviderService register(PacketProvider provider) {
206 + listener = provider;
207 + return new TestPacketProviderService();
208 + }
209 +
210 + @Override
211 + public void unregister(PacketProvider provider) {
212 + listener = null;
213 + }
214 +
215 + @Override
216 + public Set<ProviderId> getProviders() {
217 + return Sets.newHashSet(listener.id());
218 + }
219 +
220 + private class TestPacketProviderService implements PacketProviderService {
221 +
222 + @Override
223 + public PacketProvider provider() {
224 + return null;
225 + }
226 +
227 + @Override
228 + public void processPacket(PacketContext context) {
229 + ctx = context;
230 + }
231 +
232 + }
233 + }
234 +
235 + private class TestController implements OpenFlowController {
236 +
237 + PacketListener pktListener;
238 + OpenFlowSwitch current;
239 +
240 + @Override
241 + public Iterable<OpenFlowSwitch> getSwitches() {
242 + return null;
243 + }
244 +
245 + @Override
246 + public Iterable<OpenFlowSwitch> getMasterSwitches() {
247 + return null;
248 + }
249 +
250 + @Override
251 + public Iterable<OpenFlowSwitch> getEqualSwitches() {
252 + return null;
253 + }
254 +
255 + @Override
256 + public OpenFlowSwitch getSwitch(Dpid dpid) {
257 + if (dpid.equals(Dpid.dpid(DID.uri()))) {
258 + current = sw;
259 + } else {
260 + current = null;
261 + }
262 + return current;
263 + }
264 +
265 + @Override
266 + public OpenFlowSwitch getMasterSwitch(Dpid dpid) {
267 + return null;
268 + }
269 +
270 + @Override
271 + public OpenFlowSwitch getEqualSwitch(Dpid dpid) {
272 + return null;
273 + }
274 +
275 + @Override
276 + public void addListener(OpenFlowSwitchListener listener) {
277 + }
278 +
279 + @Override
280 + public void removeListener(OpenFlowSwitchListener listener) {
281 + }
282 +
283 + @Override
284 + public void addPacketListener(int priority, PacketListener listener) {
285 + pktListener = listener;
286 + }
287 +
288 + @Override
289 + public void removePacketListener(PacketListener listener) {
290 + }
291 +
292 + @Override
293 + public void addEventListener(OpenFlowEventListener listener) {
294 + }
295 +
296 + @Override
297 + public void removeEventListener(OpenFlowEventListener listener) {
298 + }
299 +
300 + @Override
301 + public void write(Dpid dpid, OFMessage msg) {
302 + }
303 +
304 + @Override
305 + public void processPacket(Dpid dpid, OFMessage msg) {
306 + OpenFlowPacketContext pktCtx =
307 + DefaultOpenFlowPacketContext.
308 + packetContextFromPacketIn(sw, (OFPacketIn) msg);
309 + pktListener.handlePacket(pktCtx);
310 + }
311 +
312 + @Override
313 + public void setRole(Dpid dpid, RoleState role) {
314 + }
315 +
316 + }
317 +
318 + private class TestOpenFlowSwitch implements OpenFlowSwitch {
319 +
320 + List<OFPortDesc> ports;
321 + RoleState state;
322 + List<OFMessage> sent = new ArrayList<OFMessage>();
323 + OFFactory factory = OFFactoryVer10.INSTANCE;
324 +
325 + TestOpenFlowSwitch(List<OFPortDesc> p) {
326 + ports = p;
327 + }
328 +
329 + @Override
330 + public void sendMsg(OFMessage msg) {
331 + sent.add(msg);
332 + }
333 +
334 + @Override
335 + public void sendMsg(List<OFMessage> msgs) {
336 + }
337 +
338 + @Override
339 + public void handleMessage(OFMessage fromSwitch) {
340 + }
341 +
342 + @Override
343 + public void setRole(RoleState role) {
344 + state = role;
345 + }
346 +
347 + @Override
348 + public RoleState getRole() {
349 + return state;
350 + }
351 +
352 + @Override
353 + public List<OFPortDesc> getPorts() {
354 + return ports;
355 + }
356 +
357 + @Override
358 + public OFFactory factory() {
359 + return factory;
360 + }
361 +
362 + @Override
363 + public String getStringId() {
364 + return null;
365 + }
366 +
367 + @Override
368 + public long getId() {
369 + return 0;
370 + }
371 +
372 + @Override
373 + public String manfacturerDescription() {
374 + return null;
375 + }
376 +
377 + @Override
378 + public String datapathDescription() {
379 + return null;
380 + }
381 +
382 + @Override
383 + public String hardwareDescription() {
384 + return null;
385 + }
386 +
387 + @Override
388 + public String softwareDescription() {
389 + return null;
390 + }
391 +
392 + @Override
393 + public String serialNumber() {
394 + return null;
395 + }
396 +
397 + @Override
398 + public void disconnectSwitch() {
399 + }
400 +
401 + }
402 +
403 +}