blob: f33f98657140597183a497d6d51d924316c2b5d3 [file] [log] [blame]
Jonathan Hart1caaa932013-11-04 15:28:28 -08001package net.onrc.onos.ofcontroller.forwarding;
2
Jonathan Hart41d1e912013-11-24 16:50:25 -08003import java.io.IOException;
Jonathan Harte93aed42013-12-05 18:39:50 -08004import java.util.ArrayList;
5import java.util.Collection;
Jonathan Hart1caaa932013-11-04 15:28:28 -08006import java.util.Iterator;
Jonathan Harte93aed42013-12-05 18:39:50 -08007import java.util.List;
8import java.util.Map;
Jonathan Hart1caaa932013-11-04 15:28:28 -08009
10import net.floodlightcontroller.core.FloodlightContext;
11import net.floodlightcontroller.core.IFloodlightProviderService;
12import net.floodlightcontroller.core.IOFMessageListener;
13import net.floodlightcontroller.core.IOFSwitch;
Jonathan Harte93aed42013-12-05 18:39:50 -080014import net.floodlightcontroller.core.module.FloodlightModuleContext;
15import net.floodlightcontroller.core.module.IFloodlightModule;
16import net.floodlightcontroller.core.module.IFloodlightService;
Jonathan Hart1caaa932013-11-04 15:28:28 -080017import net.floodlightcontroller.packet.Ethernet;
18import net.floodlightcontroller.util.MACAddress;
Jonathan Hartdc3ad702013-11-14 11:34:59 -080019import net.onrc.onos.datagrid.IDatagridService;
Jonathan Hart1caaa932013-11-04 15:28:28 -080020import net.onrc.onos.ofcontroller.core.IDeviceStorage;
21import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IDeviceObject;
22import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IPortObject;
23import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
24import net.onrc.onos.ofcontroller.core.internal.DeviceStorageImpl;
Jonathan Hart1caaa932013-11-04 15:28:28 -080025import net.onrc.onos.ofcontroller.flowmanager.IFlowService;
26import net.onrc.onos.ofcontroller.topology.TopologyManager;
27import net.onrc.onos.ofcontroller.util.CallerId;
28import net.onrc.onos.ofcontroller.util.DataPath;
29import net.onrc.onos.ofcontroller.util.Dpid;
Jonathan Hart4fb16d82013-11-07 22:41:32 -080030import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
Jonathan Hart1caaa932013-11-04 15:28:28 -080031import net.onrc.onos.ofcontroller.util.FlowId;
32import net.onrc.onos.ofcontroller.util.FlowPath;
33import net.onrc.onos.ofcontroller.util.FlowPathType;
34import net.onrc.onos.ofcontroller.util.FlowPathUserState;
35import net.onrc.onos.ofcontroller.util.Port;
36import net.onrc.onos.ofcontroller.util.SwitchPort;
37
38import org.openflow.protocol.OFMessage;
39import org.openflow.protocol.OFPacketIn;
Jonathan Hart41d1e912013-11-24 16:50:25 -080040import org.openflow.protocol.OFPacketOut;
41import org.openflow.protocol.OFPort;
Jonathan Hart1caaa932013-11-04 15:28:28 -080042import org.openflow.protocol.OFType;
Jonathan Hart41d1e912013-11-24 16:50:25 -080043import org.openflow.protocol.action.OFAction;
44import org.openflow.protocol.action.OFActionOutput;
Jonathan Hart1caaa932013-11-04 15:28:28 -080045import org.openflow.util.HexString;
46import org.slf4j.Logger;
47import org.slf4j.LoggerFactory;
48
Jonathan Harte93aed42013-12-05 18:39:50 -080049public class Forwarding implements IOFMessageListener, IFloodlightModule {
Jonathan Hart1caaa932013-11-04 15:28:28 -080050 private final static Logger log = LoggerFactory.getLogger(Forwarding.class);
51
52 private IFloodlightProviderService floodlightProvider;
53 private IFlowService flowService;
Jonathan Hartdc3ad702013-11-14 11:34:59 -080054 private IDatagridService datagridService;
Jonathan Hart1caaa932013-11-04 15:28:28 -080055
56 private IDeviceStorage deviceStorage;
57 private TopologyManager topologyService;
58
59 public Forwarding() {
60
61 }
62
Jonathan Harte93aed42013-12-05 18:39:50 -080063 @Override
64 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
65 return null;
66 }
67
68 @Override
69 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
70 return null;
71 }
72
73 @Override
74 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
75 List<Class<? extends IFloodlightService>> dependencies =
76 new ArrayList<Class<? extends IFloodlightService>>();
77 dependencies.add(IFloodlightProviderService.class);
78 dependencies.add(IFlowService.class);
79 dependencies.add(IDatagridService.class);
80 return dependencies;
81 }
82
83 @Override
84 public void init(FloodlightModuleContext context) {
85 this.floodlightProvider =
86 context.getServiceImpl(IFloodlightProviderService.class);
87 this.flowService = context.getServiceImpl(IFlowService.class);
88 this.datagridService = context.getServiceImpl(IDatagridService.class);
Jonathan Hart1caaa932013-11-04 15:28:28 -080089
90 floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
91
92 deviceStorage = new DeviceStorageImpl();
93 deviceStorage.init("");
94 topologyService = new TopologyManager();
95 topologyService.init("");
96 }
97
Jonathan Harte93aed42013-12-05 18:39:50 -080098 @Override
99 public void startUp(FloodlightModuleContext context) {
Jonathan Hart1caaa932013-11-04 15:28:28 -0800100 // no-op
101 }
102
103 @Override
104 public String getName() {
105 return "onosforwarding";
106 }
107
108 @Override
109 public boolean isCallbackOrderingPrereq(OFType type, String name) {
110 return (type == OFType.PACKET_IN) &&
111 (name.equals("devicemanager") || name.equals("proxyarpmanager"));
112 }
113
114 @Override
115 public boolean isCallbackOrderingPostreq(OFType type, String name) {
116 return false;
117 }
118
119 @Override
120 public Command receive(
121 IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
122
123 if (msg.getType() != OFType.PACKET_IN) {
124 return Command.CONTINUE;
125 }
126
127 OFPacketIn pi = (OFPacketIn) msg;
128
129 Ethernet eth = IFloodlightProviderService.bcStore.
130 get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
131
Jonathan Hart4fb16d82013-11-07 22:41:32 -0800132 // We only want to handle unicast IPv4
133 if (eth.isBroadcast() || eth.isMulticast() ||
134 eth.getEtherType() != Ethernet.TYPE_IPv4) {
Jonathan Hart1caaa932013-11-04 15:28:28 -0800135 return Command.CONTINUE;
136 }
137
138 handlePacketIn(sw, pi, eth);
139
140 return Command.STOP;
141 }
142
143 private void handlePacketIn(IOFSwitch sw, OFPacketIn pi, Ethernet eth) {
144 String destinationMac = HexString.toHexString(eth.getDestinationMACAddress());
145
146 IDeviceObject deviceObject = deviceStorage.getDeviceByMac(
147 destinationMac);
148
149 if (deviceObject == null) {
150 log.debug("No device entry found for {}", destinationMac);
151 return;
152 }
153
154 Iterator<IPortObject> ports = deviceObject.getAttachedPorts().iterator();
155 if (!ports.hasNext()) {
156 log.debug("No attachment point found for device {}", destinationMac);
157 return;
158 }
159 IPortObject portObject = ports.next();
160 short destinationPort = portObject.getNumber();
161 ISwitchObject switchObject = portObject.getSwitch();
162 long destinationDpid = HexString.toLong(switchObject.getDPID());
163
Jonathan Hart41d1e912013-11-24 16:50:25 -0800164 // TODO SwitchPort, Dpid and Port should probably be immutable
165 // (also, are Dpid and Port are even necessary?)
Jonathan Hart1caaa932013-11-04 15:28:28 -0800166 SwitchPort srcSwitchPort = new SwitchPort(
167 new Dpid(sw.getId()), new Port(pi.getInPort()));
168 SwitchPort dstSwitchPort = new SwitchPort(
169 new Dpid(destinationDpid), new Port(destinationPort));
Jonathan Hartdc3ad702013-11-14 11:34:59 -0800170
171 MACAddress srcMacAddress = MACAddress.valueOf(eth.getSourceMACAddress());
172 MACAddress dstMacAddress = MACAddress.valueOf(eth.getDestinationMACAddress());
Jonathan Hart1caaa932013-11-04 15:28:28 -0800173
Jonathan Hartdc3ad702013-11-14 11:34:59 -0800174 if (flowExists(srcSwitchPort, srcMacAddress,
175 dstSwitchPort, dstMacAddress)) {
176 log.debug("Not adding flow because it already exists");
177
Jonathan Hart41d1e912013-11-24 16:50:25 -0800178 // TODO check reverse flow as well
179
180 DataPath shortestPath =
181 topologyService.getDatabaseShortestPath(srcSwitchPort, dstSwitchPort);
182
183 if (shortestPath == null || shortestPath.flowEntries().isEmpty()) {
184 log.warn("No path found between {} and {} - not handling packet",
185 srcSwitchPort, dstSwitchPort);
186 return;
187 }
188
189 Port outPort = shortestPath.flowEntries().get(0).outPort();
190 forwardPacket(pi, sw, outPort.value());
191 return;
192 }
193
194 // Calculate a shortest path before pushing flow mods.
195 // This will be used later by the packet-out processing, but it uses
196 // the database so will be slow, and we should do it before flow mods.
197 DataPath shortestPath =
198 topologyService.getDatabaseShortestPath(srcSwitchPort, dstSwitchPort);
199
200 if (shortestPath == null || shortestPath.flowEntries().isEmpty()) {
201 log.warn("No path found between {} and {} - not handling packet",
202 srcSwitchPort, dstSwitchPort);
Jonathan Hart1caaa932013-11-04 15:28:28 -0800203 return;
204 }
205
Jonathan Hartdc3ad702013-11-14 11:34:59 -0800206 log.debug("Adding new flow between {} at {} and {} at {}",
207 new Object[]{srcMacAddress, srcSwitchPort, dstMacAddress, dstSwitchPort});
208
Jonathan Hart1caaa932013-11-04 15:28:28 -0800209
Jonathan Hart4fb16d82013-11-07 22:41:32 -0800210 DataPath dataPath = new DataPath();
211 dataPath.setSrcPort(srcSwitchPort);
212 dataPath.setDstPort(dstSwitchPort);
213
Jonathan Hart41d1e912013-11-24 16:50:25 -0800214 CallerId callerId = new CallerId("Forwarding");
215
Jonathan Hart48c2d312013-12-05 19:09:59 -0800216 //FlowId flowId = new FlowId(flowService.getNextFlowEntryId());
Jonathan Hart1caaa932013-11-04 15:28:28 -0800217 FlowPath flowPath = new FlowPath();
Jonathan Hart48c2d312013-12-05 19:09:59 -0800218 //flowPath.setFlowId(flowId);
Jonathan Hart41d1e912013-11-24 16:50:25 -0800219 flowPath.setInstallerId(callerId);
Jonathan Hart48c2d312013-12-05 19:09:59 -0800220
Jonathan Hart1caaa932013-11-04 15:28:28 -0800221 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
222 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
Jonathan Hart4fb16d82013-11-07 22:41:32 -0800223 flowPath.setFlowEntryMatch(new FlowEntryMatch());
Jonathan Hart1caaa932013-11-04 15:28:28 -0800224 flowPath.flowEntryMatch().enableSrcMac(srcMacAddress);
225 flowPath.flowEntryMatch().enableDstMac(dstMacAddress);
226 // For now just forward IPv4 packets. This prevents accidentally
Jonathan Hart41d1e912013-11-24 16:50:25 -0800227 // forwarding other stuff like ARP.
Jonathan Hart1caaa932013-11-04 15:28:28 -0800228 flowPath.flowEntryMatch().enableEthernetFrameType(Ethernet.TYPE_IPv4);
Jonathan Hart4fb16d82013-11-07 22:41:32 -0800229 flowPath.setDataPath(dataPath);
Jonathan Hart48c2d312013-12-05 19:09:59 -0800230
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800231 FlowId flowId = flowService.addFlow(flowPath);
Jonathan Hart48c2d312013-12-05 19:09:59 -0800232 //flowService.addFlow(flowPath, flowId);
Jonathan Hart4fb16d82013-11-07 22:41:32 -0800233
Jonathan Hart41d1e912013-11-24 16:50:25 -0800234
235 DataPath reverseDataPath = new DataPath();
236 // Reverse the ports for the reverse path
237 reverseDataPath.setSrcPort(dstSwitchPort);
238 reverseDataPath.setDstPort(srcSwitchPort);
239
Jonathan Hart48c2d312013-12-05 19:09:59 -0800240 //FlowId reverseFlowId = new FlowId(flowService.getNextFlowEntryId());
Jonathan Hart41d1e912013-11-24 16:50:25 -0800241 // TODO implement copy constructor for FlowPath
242 FlowPath reverseFlowPath = new FlowPath();
Jonathan Hart48c2d312013-12-05 19:09:59 -0800243 //reverseFlowPath.setFlowId(reverseFlowId);
Jonathan Hart41d1e912013-11-24 16:50:25 -0800244 reverseFlowPath.setInstallerId(callerId);
245 reverseFlowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
246 reverseFlowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
247 reverseFlowPath.setFlowEntryMatch(new FlowEntryMatch());
248 // Reverse the MAC addresses for the reverse path
249 reverseFlowPath.flowEntryMatch().enableSrcMac(dstMacAddress);
250 reverseFlowPath.flowEntryMatch().enableDstMac(srcMacAddress);
251 reverseFlowPath.flowEntryMatch().enableEthernetFrameType(Ethernet.TYPE_IPv4);
252 reverseFlowPath.setDataPath(reverseDataPath);
253 reverseFlowPath.dataPath().srcPort().dpid().toString();
254
255 // TODO what happens if no path exists?
Jonathan Hart48c2d312013-12-05 19:09:59 -0800256 //flowService.addFlow(reverseFlowPath, reverseFlowId);
257 FlowId reverseFlowId = flowService.addFlow(reverseFlowPath);
Jonathan Hart41d1e912013-11-24 16:50:25 -0800258
Jonathan Hart41d1e912013-11-24 16:50:25 -0800259 Port outPort = shortestPath.flowEntries().get(0).outPort();
260 forwardPacket(pi, sw, outPort.value());
Jonathan Hart1caaa932013-11-04 15:28:28 -0800261 }
Jonathan Hartdc3ad702013-11-14 11:34:59 -0800262
263 private boolean flowExists(SwitchPort srcPort, MACAddress srcMac,
264 SwitchPort dstPort, MACAddress dstMac) {
265 for (FlowPath flow : datagridService.getAllFlows()) {
266 FlowEntryMatch match = flow.flowEntryMatch();
267 // TODO implement FlowEntryMatch.equals();
268 // This is painful to do properly without support in the FlowEntryMatch
269 boolean same = true;
270 if (!match.srcMac().equals(srcMac) ||
271 !match.dstMac().equals(dstMac)) {
272 same = false;
273 }
274 if (!flow.dataPath().srcPort().equals(srcPort) ||
275 !flow.dataPath().dstPort().equals(dstPort)) {
276 same = false;
277 }
278
279 if (same) {
280 log.debug("found flow entry that's the same {}-{}:::{}-{}",
281 new Object[] {srcPort, srcMac, dstPort, dstMac});
282 return true;
283 }
284 }
285
286 return false;
287 }
Jonathan Hart1caaa932013-11-04 15:28:28 -0800288
Jonathan Hart41d1e912013-11-24 16:50:25 -0800289 private void forwardPacket(OFPacketIn pi, IOFSwitch sw, short port) {
290 List<OFAction> actions = new ArrayList<OFAction>(1);
291 actions.add(new OFActionOutput(port));
292
293 OFPacketOut po = new OFPacketOut();
294 po.setInPort(OFPort.OFPP_NONE)
295 .setInPort(pi.getInPort())
296 .setActions(actions)
297 .setActionsLength((short)OFActionOutput.MINIMUM_LENGTH)
298 .setLengthU(OFPacketOut.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
299
300 if (sw.getBuffers() == 0) {
301 po.setBufferId(OFPacketOut.BUFFER_ID_NONE)
302 .setPacketData(pi.getPacketData())
303 .setLengthU(po.getLengthU() + po.getPacketData().length);
304 }
305 else {
306 po.setBufferId(pi.getBufferId());
307 }
308
309 try {
310 sw.write(po, null);
311 sw.flush();
312 } catch (IOException e) {
313 log.error("Error writing packet out to switch: {}", e);
314 }
315 }
Jonathan Hart1caaa932013-11-04 15:28:28 -0800316}