blob: a68a1b8734fca292dddedb3121d76ef64b7fe346 [file] [log] [blame]
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001/**
2* Copyright 2011, Big Switch Networks, Inc.
3* Originally created by David Erickson, Stanford University
4*
5* Licensed under the Apache License, Version 2.0 (the "License"); you may
6* not use this file except in compliance with the License. You may obtain
7* a copy of the License at
8*
9* http://www.apache.org/licenses/LICENSE-2.0
10*
11* Unless required by applicable law or agreed to in writing, software
12* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14* License for the specific language governing permissions and limitations
15* under the License.
16**/
17
18package net.floodlightcontroller.learningswitch;
19
20import static org.easymock.EasyMock.createMock;
21import static org.easymock.EasyMock.expect;
22import static org.easymock.EasyMock.replay;
23import static org.easymock.EasyMock.verify;
24
25import java.util.ArrayList;
26import java.util.Arrays;
27import java.util.Collection;
28
29import net.floodlightcontroller.core.IOFMessageListener;
30import net.floodlightcontroller.core.IOFSwitch;
31import net.floodlightcontroller.core.module.FloodlightTestModuleLoader;
32import net.floodlightcontroller.core.module.IFloodlightModule;
33import net.floodlightcontroller.core.test.MockFloodlightProvider;
34import net.floodlightcontroller.packet.Data;
35import net.floodlightcontroller.packet.Ethernet;
36import net.floodlightcontroller.packet.IPacket;
37import net.floodlightcontroller.packet.IPv4;
38import net.floodlightcontroller.packet.UDP;
39import net.floodlightcontroller.test.FloodlightTestCase;
40
41import org.junit.Before;
42import org.junit.Test;
43import org.openflow.protocol.OFFlowMod;
44import org.openflow.protocol.OFMatch;
45import org.openflow.protocol.OFMessage;
46import org.openflow.protocol.OFPacketIn;
47import org.openflow.protocol.OFPacketIn.OFPacketInReason;
48import org.openflow.protocol.OFPacketOut;
49import org.openflow.protocol.OFPort;
50import org.openflow.protocol.OFType;
51import org.openflow.protocol.action.OFAction;
52import org.openflow.protocol.action.OFActionOutput;
53
54/**
55 *
56 * @author David Erickson (daviderickson@cs.stanford.edu)
57 */
58public class LearningSwitchTest extends FloodlightTestCase {
59 protected OFPacketIn packetIn;
60 protected IPacket testPacket;
61 protected byte[] testPacketSerialized;
62 protected IPacket broadcastPacket;
63 protected byte[] broadcastPacketSerialized;
64 protected IPacket testPacketReply;
65 protected byte[] testPacketReplySerialized;
66 private LearningSwitch learningSwitch;
67
68 @Before
69 public void setUp() throws Exception {
70 super.setUp();
71 FloodlightTestModuleLoader fml = new FloodlightTestModuleLoader();
72 Collection<Class<? extends IFloodlightModule>> mods
73 = new ArrayList<Class<? extends IFloodlightModule>>();
74 mods.add(LearningSwitch.class);
75 fml.setupModules(mods, null);
76 learningSwitch = (LearningSwitch) fml.getModuleByName(LearningSwitch.class);
77 mockFloodlightProvider =
78 (MockFloodlightProvider) fml.getModuleByName(MockFloodlightProvider.class);
79
80 // Build our test packet
81 this.testPacket = new Ethernet()
82 .setDestinationMACAddress("00:11:22:33:44:55")
83 .setSourceMACAddress("00:44:33:22:11:00")
84 .setVlanID((short) 42)
85 .setEtherType(Ethernet.TYPE_IPv4)
86 .setPayload(
87 new IPv4()
88 .setTtl((byte) 128)
89 .setSourceAddress("192.168.1.1")
90 .setDestinationAddress("192.168.1.2")
91 .setPayload(new UDP()
92 .setSourcePort((short) 5000)
93 .setDestinationPort((short) 5001)
94 .setPayload(new Data(new byte[] {0x01}))));
95 this.testPacketSerialized = testPacket.serialize();
96 // Build a broadcast packet
97 this.broadcastPacket = new Ethernet()
98 .setDestinationMACAddress("FF:FF:FF:FF:FF:FF")
99 .setSourceMACAddress("00:44:33:22:11:00")
100 .setVlanID((short) 42)
101 .setEtherType(Ethernet.TYPE_IPv4)
102 .setPayload(
103 new IPv4()
104 .setTtl((byte) 128)
105 .setSourceAddress("192.168.1.1")
106 .setDestinationAddress("192.168.255.255")
107 .setPayload(new UDP()
108 .setSourcePort((short) 5000)
109 .setDestinationPort((short) 5001)
110 .setPayload(new Data(new byte[] {0x01}))));
111
112 this.broadcastPacketSerialized = broadcastPacket.serialize();
113 this.testPacketReply = new Ethernet()
114 .setDestinationMACAddress("00:44:33:22:11:00")
115 .setSourceMACAddress("00:11:22:33:44:55")
116 .setVlanID((short) 42)
117 .setEtherType(Ethernet.TYPE_IPv4)
118 .setPayload(
119 new IPv4()
120 .setTtl((byte) 128)
121 .setSourceAddress("192.168.1.2")
122 .setDestinationAddress("192.168.1.1")
123 .setPayload(new UDP()
124 .setSourcePort((short) 5001)
125 .setDestinationPort((short) 5000)
126 .setPayload(new Data(new byte[] {0x02}))));
127 this.testPacketReplySerialized = testPacketReply.serialize();
128
129 // Build the PacketIn
130 this.packetIn = ((OFPacketIn) mockFloodlightProvider.getOFMessageFactory().getMessage(OFType.PACKET_IN))
131 .setBufferId(-1)
132 .setInPort((short) 1)
133 .setPacketData(this.testPacketSerialized)
134 .setReason(OFPacketInReason.NO_MATCH)
135 .setTotalLength((short) this.testPacketSerialized.length);
136 }
137
138 @Test
139 public void testFlood() throws Exception {
140 // build our expected flooded packetOut
141 OFPacketOut po = new OFPacketOut()
142 .setActions(Arrays.asList(new OFAction[] {new OFActionOutput().setPort(OFPort.OFPP_FLOOD.getValue())}))
143 .setActionsLength((short) OFActionOutput.MINIMUM_LENGTH)
144 .setBufferId(-1)
145 .setInPort((short)1)
146 .setPacketData(this.testPacketSerialized);
147 po.setLengthU(OFPacketOut.MINIMUM_LENGTH + po.getActionsLengthU()
148 + this.testPacketSerialized.length);
149
150 // Mock up our expected behavior
151 IOFSwitch mockSwitch = createMock(IOFSwitch.class);
152 expect(mockSwitch.getStringId()).andReturn("00:11:22:33:44:55:66:77").anyTimes();
153 mockSwitch.write(po, null);
154
155 // Start recording the replay on the mocks
156 replay(mockSwitch);
157 // Get the listener and trigger the packet in
158 IOFMessageListener listener = mockFloodlightProvider.getListeners().get(
159 OFType.PACKET_IN).get(0);
160 // Make sure it's the right listener
161 listener.receive(mockSwitch, this.packetIn, parseAndAnnotate(this.packetIn));
162
163 // Verify the replay matched our expectations
164 short result = learningSwitch.getFromPortMap(mockSwitch, Ethernet.toLong(Ethernet.toMACAddress("00:44:33:22:11:00")), (short) 42).shortValue();
165 verify(mockSwitch);
166
167 // Verify the MAC table inside the switch
168 assertEquals(1, result);
169 }
170
171 @Test
172 public void testFlowMod() throws Exception {
173 // tweak the test packet in since we need a bufferId
174 this.packetIn.setBufferId(50);
175
176 // build expected flow mods
177 OFMessage fm1 = ((OFFlowMod) mockFloodlightProvider.getOFMessageFactory().getMessage(OFType.FLOW_MOD))
178 .setActions(Arrays.asList(new OFAction[] {
179 new OFActionOutput().setPort((short) 2).setMaxLength((short) -1)}))
180 .setBufferId(50)
181 .setCommand(OFFlowMod.OFPFC_ADD)
182 .setIdleTimeout((short) 5)
183 .setMatch(new OFMatch()
184 .loadFromPacket(testPacketSerialized, (short) 1)
185 .setWildcards(OFMatch.OFPFW_NW_PROTO | OFMatch.OFPFW_TP_SRC | OFMatch.OFPFW_TP_DST
186 | OFMatch.OFPFW_NW_TOS))
187 .setOutPort(OFPort.OFPP_NONE.getValue())
188 .setCookie(1L << 52)
189 .setPriority((short) 100)
190 .setFlags((short)(1 << 0))
191 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
192 OFMessage fm2 = ((OFFlowMod) mockFloodlightProvider.getOFMessageFactory().getMessage(OFType.FLOW_MOD))
193 .setActions(Arrays.asList(new OFAction[] {
194 new OFActionOutput().setPort((short) 1).setMaxLength((short) -1)}))
195 .setBufferId(-1)
196 .setCommand(OFFlowMod.OFPFC_ADD)
197 .setIdleTimeout((short) 5)
198 .setMatch(new OFMatch()
199 .loadFromPacket(testPacketReplySerialized, (short) 2)
200 .setWildcards(OFMatch.OFPFW_NW_PROTO | OFMatch.OFPFW_TP_SRC | OFMatch.OFPFW_TP_DST
201 | OFMatch.OFPFW_NW_TOS))
202 .setOutPort(OFPort.OFPP_NONE.getValue())
203 .setCookie(1L << 52)
204 .setPriority((short) 100)
205 .setFlags((short)(1 << 0))
206 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
207
208 // Mock up our expected behavior
209 IOFSwitch mockSwitch = createMock(IOFSwitch.class);
210 expect(mockSwitch.getId()).andReturn(1L).anyTimes();
211 expect(mockSwitch.getAttribute(IOFSwitch.PROP_FASTWILDCARDS)).andReturn((Integer) (OFMatch.OFPFW_IN_PORT | OFMatch.OFPFW_NW_PROTO
212 | OFMatch.OFPFW_TP_SRC | OFMatch.OFPFW_TP_DST | OFMatch.OFPFW_NW_SRC_ALL
213 | OFMatch.OFPFW_NW_DST_ALL | OFMatch.OFPFW_NW_TOS));
214 mockSwitch.write(fm1, null);
215 mockSwitch.write(fm2, null);
216
217 // Start recording the replay on the mocks
218 replay(mockSwitch);
219
220 // Populate the MAC table
221 learningSwitch.addToPortMap(mockSwitch,
222 Ethernet.toLong(Ethernet.toMACAddress("00:11:22:33:44:55")), (short) 42, (short) 2);
223
224 // Get the listener and trigger the packet in
225 IOFMessageListener listener = mockFloodlightProvider.getListeners().get(
226 OFType.PACKET_IN).get(0);
227 listener.receive(mockSwitch, this.packetIn, parseAndAnnotate(this.packetIn));
228
229 // Verify the replay matched our expectations
230 short result = learningSwitch.getFromPortMap(mockSwitch, Ethernet.toLong(Ethernet.toMACAddress("00:44:33:22:11:00")), (short) 42).shortValue();
231 verify(mockSwitch);
232
233 // Verify the MAC table inside the switch
234 assertEquals(1, result);
235 }
236}