blob: c0acd5a46f948af86e1341fc46c05b35c27325a8 [file] [log] [blame]
Thomas Vachuska781d18b2014-10-27 10:31:25 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2014-present Open Networking Foundation
Thomas Vachuska781d18b2014-10-27 10:31:25 -07003 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07004 * 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
Thomas Vachuska781d18b2014-10-27 10:31:25 -07007 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07008 * 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.
Thomas Vachuska781d18b2014-10-27 10:31:25 -070015 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.provider.of.packet.impl;
Ayaka Koshibe96ca09d2014-09-19 12:06:14 -070017
alshabibb452fd72015-04-22 20:46:20 -070018import com.google.common.collect.Lists;
19import com.google.common.collect.Sets;
Ayaka Koshibe96ca09d2014-09-19 12:06:14 -070020import org.junit.After;
21import org.junit.Before;
22import org.junit.Test;
alshabibb452fd72015-04-22 20:46:20 -070023import org.onlab.packet.ARP;
24import org.onlab.packet.Ethernet;
Marc De Leenheerb9311372015-07-09 11:36:49 -070025import org.onosproject.net.Device;
Brian O'Connorabafb502014-12-02 22:26:20 -080026import org.onosproject.net.DeviceId;
27import org.onosproject.net.PortNumber;
28import org.onosproject.net.flow.DefaultTrafficTreatment;
29import org.onosproject.net.flow.TrafficTreatment;
30import org.onosproject.net.flow.instructions.Instruction;
31import org.onosproject.net.flow.instructions.Instructions;
32import org.onosproject.net.packet.DefaultOutboundPacket;
33import org.onosproject.net.packet.OutboundPacket;
34import org.onosproject.net.packet.PacketContext;
35import org.onosproject.net.packet.PacketProvider;
36import org.onosproject.net.packet.PacketProviderRegistry;
37import org.onosproject.net.packet.PacketProviderService;
38import org.onosproject.net.provider.ProviderId;
39import org.onosproject.openflow.controller.DefaultOpenFlowPacketContext;
40import org.onosproject.openflow.controller.Dpid;
41import org.onosproject.openflow.controller.OpenFlowController;
42import org.onosproject.openflow.controller.OpenFlowEventListener;
Jian Lia78cdb22016-04-21 13:03:58 -070043import org.onosproject.openflow.controller.OpenFlowMessageListener;
Brian O'Connorabafb502014-12-02 22:26:20 -080044import org.onosproject.openflow.controller.OpenFlowPacketContext;
45import org.onosproject.openflow.controller.OpenFlowSwitch;
46import org.onosproject.openflow.controller.OpenFlowSwitchListener;
47import org.onosproject.openflow.controller.PacketListener;
48import org.onosproject.openflow.controller.RoleState;
Thiago Santos11d10622019-01-30 14:44:32 -080049import org.projectfloodlight.openflow.protocol.OFActionType;
Ayaka Koshibe96ca09d2014-09-19 12:06:14 -070050import org.projectfloodlight.openflow.protocol.OFFactory;
51import org.projectfloodlight.openflow.protocol.OFMessage;
Jordi Ortizaa8de492016-12-01 00:21:36 +010052import org.projectfloodlight.openflow.protocol.OFMeterFeatures;
Ayaka Koshibe96ca09d2014-09-19 12:06:14 -070053import org.projectfloodlight.openflow.protocol.OFPacketIn;
54import org.projectfloodlight.openflow.protocol.OFPacketInReason;
Thiago Santos11d10622019-01-30 14:44:32 -080055import org.projectfloodlight.openflow.protocol.OFPacketOut;
Ayaka Koshibe96ca09d2014-09-19 12:06:14 -070056import org.projectfloodlight.openflow.protocol.OFPortDesc;
Thiago Santos11d10622019-01-30 14:44:32 -080057import org.projectfloodlight.openflow.protocol.OFType;
58import org.projectfloodlight.openflow.protocol.action.OFAction;
59import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
Ayaka Koshibe96ca09d2014-09-19 12:06:14 -070060import org.projectfloodlight.openflow.protocol.ver10.OFFactoryVer10;
61import org.projectfloodlight.openflow.types.MacAddress;
62import org.projectfloodlight.openflow.types.OFBufferId;
63import org.projectfloodlight.openflow.types.OFPort;
64
alshabibb452fd72015-04-22 20:46:20 -070065import java.nio.ByteBuffer;
66import java.util.ArrayList;
67import java.util.List;
68import java.util.Set;
Marc De Leenheer8aba62f2017-04-25 14:33:37 -070069import java.util.concurrent.CompletableFuture;
alshabibb452fd72015-04-22 20:46:20 -070070
71import static org.junit.Assert.*;
Ayaka Koshibe96ca09d2014-09-19 12:06:14 -070072
73
74public class OpenFlowPacketProviderTest {
75
76 private static final int PN1 = 100;
77 private static final int PN2 = 200;
78 private static final int PN3 = 300;
79 private static final short VLANID = (short) 100;
Thiago Santos11d10622019-01-30 14:44:32 -080080 private static final int IN_PORT_PN = 1;
Ayaka Koshibe96ca09d2014-09-19 12:06:14 -070081
82 private static final DeviceId DID = DeviceId.deviceId("of:1");
83 private static final DeviceId DID_MISSING = DeviceId.deviceId("of:2");
84 private static final DeviceId DID_WRONG = DeviceId.deviceId("test:1");
85 private static final PortNumber P1 = PortNumber.portNumber(PN1);
86 private static final PortNumber P2 = PortNumber.portNumber(PN2);
87 private static final PortNumber P3 = PortNumber.portNumber(PN3);
Thiago Santos11d10622019-01-30 14:44:32 -080088 private static final PortNumber IN_PORT = PortNumber.portNumber(IN_PORT_PN);
Ayaka Koshibe96ca09d2014-09-19 12:06:14 -070089
90 private static final Instruction INST1 = Instructions.createOutput(P1);
91 private static final Instruction INST2 = Instructions.createOutput(P2);
92 private static final Instruction INST3 = Instructions.createOutput(P3);
Thiago Santosa4a17cb2019-01-30 14:23:58 -080093 private static final Instruction INST_ALL = Instructions.createOutput(PortNumber.ALL);
Ayaka Koshibe96ca09d2014-09-19 12:06:14 -070094
95 private static final OFPortDesc PD1 = portDesc(PN1);
96 private static final OFPortDesc PD2 = portDesc(PN2);
Thiago Santosa4a17cb2019-01-30 14:23:58 -080097 private static final OFPortDesc PD_ALL = portDesc((int) PortNumber.ALL.toLong());
Ayaka Koshibe96ca09d2014-09-19 12:06:14 -070098
99 private static final List<OFPortDesc> PLIST = Lists.newArrayList(PD1, PD2);
100 private static final TrafficTreatment TR = treatment(INST1, INST2);
Thiago Santosa4a17cb2019-01-30 14:23:58 -0800101 private static final List<OFPortDesc> PLIST_ALL = Lists.newArrayList(PD_ALL);
102 private static final TrafficTreatment TR_ALL = treatment(INST_ALL);
Ayaka Koshibe96ca09d2014-09-19 12:06:14 -0700103 private static final TrafficTreatment TR_MISSING = treatment(INST1, INST3);
104
Jian Li68c4fc42016-01-11 16:07:03 -0800105 private static final byte[] ANY = new byte[] {0, 0, 0, 0};
Yuta HIGUCHI10681f62014-09-21 17:49:46 -0700106
Ayaka Koshibe96ca09d2014-09-19 12:06:14 -0700107 private final OpenFlowPacketProvider provider = new OpenFlowPacketProvider();
108 private final TestPacketRegistry registry = new TestPacketRegistry();
109 private final TestController controller = new TestController();
110
Ayaka Koshibe0380d4c2014-09-19 16:03:07 -0700111 private final TestOpenFlowSwitch sw = new TestOpenFlowSwitch();
Ayaka Koshibe96ca09d2014-09-19 12:06:14 -0700112
113 @Before
114 public void startUp() {
115 provider.providerRegistry = registry;
116 provider.controller = controller;
117 provider.activate();
118 assertNotNull("listener should be registered", registry.listener);
119 }
120
121 @After
122 public void teardown() {
123 provider.deactivate();
124 assertNull("listeners shouldn't be registered", registry.listener);
125 provider.controller = null;
126 provider.providerRegistry = null;
127 }
128
129 @Test(expected = IllegalArgumentException.class)
Ayaka Koshibe91c9bc72014-09-19 12:52:24 -0700130 public void wrongScheme() {
Ayaka Koshibe96ca09d2014-09-19 12:06:14 -0700131 sw.setRole(RoleState.MASTER);
Ayaka Koshibe96ca09d2014-09-19 12:06:14 -0700132 OutboundPacket schemeFailPkt = outPacket(DID_WRONG, TR, null);
133 provider.emit(schemeFailPkt);
134 assertEquals("message sent incorrectly", 0, sw.sent.size());
135 }
136
137 @Test
138 public void emit() {
139
140 MacAddress mac1 = MacAddress.of("00:00:00:11:00:01");
141 MacAddress mac2 = MacAddress.of("00:00:00:22:00:02");
142
143 ARP arp = new ARP();
Yuta HIGUCHI10681f62014-09-21 17:49:46 -0700144 arp.setSenderProtocolAddress(ANY)
Ayaka Koshibe96ca09d2014-09-19 12:06:14 -0700145 .setSenderHardwareAddress(mac1.getBytes())
146 .setTargetHardwareAddress(mac2.getBytes())
Yuta HIGUCHI10681f62014-09-21 17:49:46 -0700147 .setTargetProtocolAddress(ANY)
Ayaka Koshibe96ca09d2014-09-19 12:06:14 -0700148 .setHardwareType((short) 0)
149 .setProtocolType((short) 0)
150 .setHardwareAddressLength((byte) 6)
151 .setProtocolAddressLength((byte) 4)
152 .setOpCode((byte) 0);
153
154 Ethernet eth = new Ethernet();
155 eth.setVlanID(VLANID)
156 .setEtherType(Ethernet.TYPE_ARP)
157 .setSourceMACAddress("00:00:00:11:00:01")
158 .setDestinationMACAddress("00:00:00:22:00:02")
159 .setPayload(arp);
160
161 //the should-be working setup.
162 OutboundPacket passPkt = outPacket(DID, TR, eth);
163 sw.setRole(RoleState.MASTER);
164 provider.emit(passPkt);
165 assertEquals("invalid switch", sw, controller.current);
166 assertEquals("message not sent", PLIST.size(), sw.sent.size());
167 sw.sent.clear();
168
Thiago Santos11d10622019-01-30 14:44:32 -0800169 //Send with different IN_PORT
170 OutboundPacket inPortPkt = outPacket(DID, TR_ALL, eth, IN_PORT);
Thiago Santosa4a17cb2019-01-30 14:23:58 -0800171 sw.setRole(RoleState.MASTER);
172 provider.emit(inPortPkt);
173 assertEquals("invalid switch", sw, controller.current);
174 assertEquals("message not sent", PLIST_ALL.size(), sw.sent.size());
Thiago Santos11d10622019-01-30 14:44:32 -0800175 OFMessage ofMessage = sw.sent.get(0);
176 assertEquals("Wrong OF message type", OFType.PACKET_OUT, ofMessage.getType());
177 OFPacketOut packetOut = (OFPacketOut) ofMessage;
178 assertEquals("Wrong in port", OFPort.of(IN_PORT_PN), packetOut.getInPort());
179 assertEquals("Unexpected number of actions", 1, packetOut.getActions().size());
180 OFAction ofAction = packetOut.getActions().get(0);
181 assertEquals("Packet out action should be type output", OFActionType.OUTPUT, ofAction.getType());
182 OFActionOutput ofActionOutput = (OFActionOutput) ofAction;
183 assertEquals("Output should be ALL", OFPort.ALL, ofActionOutput.getPort());
Thiago Santosa4a17cb2019-01-30 14:23:58 -0800184 sw.sent.clear();
185
Ayaka Koshibe96ca09d2014-09-19 12:06:14 -0700186 //wrong Role
alshabib6eb438a2014-10-01 16:39:37 -0700187 //sw.setRole(RoleState.SLAVE);
188 //provider.emit(passPkt);
189 //assertEquals("invalid switch", sw, controller.current);
190 //assertEquals("message sent incorrectly", 0, sw.sent.size());
Ayaka Koshibe96ca09d2014-09-19 12:06:14 -0700191
alshabib6eb438a2014-10-01 16:39:37 -0700192 //sw.setRole(RoleState.MASTER);
Ayaka Koshibe96ca09d2014-09-19 12:06:14 -0700193
194 //missing switch
195 OutboundPacket swFailPkt = outPacket(DID_MISSING, TR, eth);
196 provider.emit(swFailPkt);
197 assertNull("invalid switch", controller.current);
198 assertEquals("message sent incorrectly", 0, sw.sent.size());
199
200 //to missing port
alshabibb5522ff2014-09-29 19:20:00 -0700201 //OutboundPacket portFailPkt = outPacket(DID, TR_MISSING, eth);
202 //provider.emit(portFailPkt);
203 //assertEquals("extra message sent", 1, sw.sent.size());
Ayaka Koshibe96ca09d2014-09-19 12:06:14 -0700204
205 }
206
207 @Test
208 public void handlePacket() {
209 OFPacketIn pkt = sw.factory().buildPacketIn()
210 .setBufferId(OFBufferId.NO_BUFFER)
211 .setInPort(OFPort.NO_MASK)
212 .setReason(OFPacketInReason.INVALID_TTL)
213 .build();
214
215 controller.processPacket(null, pkt);
216 assertNotNull("message unprocessed", registry.ctx);
217
218 }
219
220 private static OFPortDesc portDesc(int port) {
221 OFPortDesc.Builder builder = OFFactoryVer10.INSTANCE.buildPortDesc();
222 builder.setPortNo(OFPort.of(port));
223
224 return builder.build();
225 }
226
Yuta HIGUCHIe7e71a82018-05-18 16:36:43 -0700227 private static TrafficTreatment treatment(Instruction... insts) {
tom9a693fd2014-10-03 11:32:19 -0700228 TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder();
Ayaka Koshibe96ca09d2014-09-19 12:06:14 -0700229 for (Instruction i : insts) {
230 builder.add(i);
231 }
232 return builder.build();
233 }
234
235 private static OutboundPacket outPacket(
236 DeviceId d, TrafficTreatment t, Ethernet e) {
237 ByteBuffer buf = null;
238 if (e != null) {
239 buf = ByteBuffer.wrap(e.serialize());
240 }
241 return new DefaultOutboundPacket(d, t, buf);
242 }
243
Thiago Santosa4a17cb2019-01-30 14:23:58 -0800244 private OutboundPacket outPacket(DeviceId d, TrafficTreatment t, Ethernet e,
245 PortNumber inPort) {
246 ByteBuffer buf = null;
247 if (e != null) {
248 buf = ByteBuffer.wrap(e.serialize());
249 }
250 return new DefaultOutboundPacket(d, t, buf, inPort);
251 }
252
253
Ayaka Koshibe96ca09d2014-09-19 12:06:14 -0700254 private class TestPacketRegistry implements PacketProviderRegistry {
255
256 PacketProvider listener = null;
257 PacketContext ctx = null;
258
259 @Override
260 public PacketProviderService register(PacketProvider provider) {
261 listener = provider;
262 return new TestPacketProviderService();
263 }
264
265 @Override
266 public void unregister(PacketProvider provider) {
267 listener = null;
268 }
269
270 @Override
271 public Set<ProviderId> getProviders() {
272 return Sets.newHashSet(listener.id());
273 }
274
275 private class TestPacketProviderService implements PacketProviderService {
276
277 @Override
278 public PacketProvider provider() {
279 return null;
280 }
281
282 @Override
283 public void processPacket(PacketContext context) {
284 ctx = context;
285 }
286
287 }
288 }
289
290 private class TestController implements OpenFlowController {
291
Ayaka Koshibe96ca09d2014-09-19 12:06:14 -0700292 PacketListener pktListener;
293 OpenFlowSwitch current;
294
295 @Override
296 public Iterable<OpenFlowSwitch> getSwitches() {
297 return null;
298 }
299
300 @Override
301 public Iterable<OpenFlowSwitch> getMasterSwitches() {
302 return null;
303 }
304
305 @Override
306 public Iterable<OpenFlowSwitch> getEqualSwitches() {
307 return null;
308 }
309
310 @Override
311 public OpenFlowSwitch getSwitch(Dpid dpid) {
312 if (dpid.equals(Dpid.dpid(DID.uri()))) {
313 current = sw;
314 } else {
315 current = null;
316 }
317 return current;
318 }
319
320 @Override
321 public OpenFlowSwitch getMasterSwitch(Dpid dpid) {
322 return null;
323 }
324
325 @Override
326 public OpenFlowSwitch getEqualSwitch(Dpid dpid) {
327 return null;
328 }
329
330 @Override
331 public void addListener(OpenFlowSwitchListener listener) {
332 }
333
334 @Override
335 public void removeListener(OpenFlowSwitchListener listener) {
336 }
337
338 @Override
Jian Lia78cdb22016-04-21 13:03:58 -0700339 public void addMessageListener(OpenFlowMessageListener listener) {
340
341 }
342
343 @Override
344 public void removeMessageListener(OpenFlowMessageListener listener) {
345
346 }
347
348 @Override
Ayaka Koshibe96ca09d2014-09-19 12:06:14 -0700349 public void addPacketListener(int priority, PacketListener listener) {
Ayaka Koshibe96ca09d2014-09-19 12:06:14 -0700350 pktListener = listener;
351 }
352
353 @Override
354 public void removePacketListener(PacketListener listener) {
355 }
356
357 @Override
358 public void addEventListener(OpenFlowEventListener listener) {
359 }
360
361 @Override
362 public void removeEventListener(OpenFlowEventListener listener) {
363 }
364
365 @Override
366 public void write(Dpid dpid, OFMessage msg) {
367 }
368
369 @Override
Marc De Leenheer8aba62f2017-04-25 14:33:37 -0700370 public CompletableFuture<OFMessage> writeResponse(Dpid dpid, OFMessage msg) {
371 return null;
372 }
373
374 @Override
Ayaka Koshibe96ca09d2014-09-19 12:06:14 -0700375 public void processPacket(Dpid dpid, OFMessage msg) {
376 OpenFlowPacketContext pktCtx =
377 DefaultOpenFlowPacketContext.
378 packetContextFromPacketIn(sw, (OFPacketIn) msg);
379 pktListener.handlePacket(pktCtx);
380 }
381
382 @Override
383 public void setRole(Dpid dpid, RoleState role) {
384 }
385
386 }
387
Ayaka Koshibe96ca09d2014-09-19 12:06:14 -0700388 private class TestOpenFlowSwitch implements OpenFlowSwitch {
389
Ayaka Koshibe96ca09d2014-09-19 12:06:14 -0700390 RoleState state;
Yuta HIGUCHIe7e71a82018-05-18 16:36:43 -0700391 List<OFMessage> sent = new ArrayList<>();
Ayaka Koshibe96ca09d2014-09-19 12:06:14 -0700392 OFFactory factory = OFFactoryVer10.INSTANCE;
393
Ayaka Koshibe96ca09d2014-09-19 12:06:14 -0700394 @Override
395 public void sendMsg(OFMessage msg) {
396 sent.add(msg);
397 }
398
399 @Override
400 public void sendMsg(List<OFMessage> msgs) {
401 }
402
403 @Override
404 public void handleMessage(OFMessage fromSwitch) {
405 }
406
407 @Override
408 public void setRole(RoleState role) {
409 state = role;
410 }
411
412 @Override
413 public RoleState getRole() {
414 return state;
415 }
416
417 @Override
418 public List<OFPortDesc> getPorts() {
Ayaka Koshibe0380d4c2014-09-19 16:03:07 -0700419 return PLIST;
Ayaka Koshibe96ca09d2014-09-19 12:06:14 -0700420 }
421
422 @Override
Jordi Ortizaa8de492016-12-01 00:21:36 +0100423 public OFMeterFeatures getMeterFeatures() {
424 return null;
425 }
426
427 @Override
Ayaka Koshibe96ca09d2014-09-19 12:06:14 -0700428 public OFFactory factory() {
429 return factory;
430 }
431
432 @Override
433 public String getStringId() {
434 return null;
435 }
436
437 @Override
438 public long getId() {
439 return 0;
440 }
441
442 @Override
Ray Milkeyd3edd032015-01-16 11:38:58 -0800443 public String manufacturerDescription() {
Ayaka Koshibe96ca09d2014-09-19 12:06:14 -0700444 return null;
445 }
446
447 @Override
448 public String datapathDescription() {
449 return null;
450 }
451
452 @Override
453 public String hardwareDescription() {
454 return null;
455 }
456
457 @Override
458 public String softwareDescription() {
459 return null;
460 }
461
462 @Override
463 public String serialNumber() {
464 return null;
465 }
466
467 @Override
Yuta HIGUCHI69a27352014-10-31 15:48:37 -0700468 public boolean isConnected() {
469 return true;
470 }
471
472 @Override
Ayaka Koshibe96ca09d2014-09-19 12:06:14 -0700473 public void disconnectSwitch() {
474 }
475
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700476 @Override
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700477 public void returnRoleReply(RoleState requested, RoleState reponse) {
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700478 }
Marc De Leenheerb9311372015-07-09 11:36:49 -0700479 @Override
480 public Device.Type deviceType() {
481 return Device.Type.SWITCH;
482 }
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700483
Ray Milkeye53f1712015-01-16 09:17:16 -0800484 @Override
485 public String channelId() {
486 return "1.2.3.4:1";
487 }
Ayaka Koshibe96ca09d2014-09-19 12:06:14 -0700488 }
489
490}