blob: 27bfbb59d18c389945a94a951f1bcacc99d617d5 [file] [log] [blame]
Jonathan Hart1f75cae2014-04-09 17:24:09 -07001package net.onrc.onos.core.packetservice;
2
3import java.util.ArrayList;
4import java.util.Collection;
5import java.util.HashMap;
6import java.util.List;
7import java.util.Map;
8import java.util.concurrent.CopyOnWriteArrayList;
9
10import net.floodlightcontroller.core.FloodlightContext;
11import net.floodlightcontroller.core.IFloodlightProviderService;
12import net.floodlightcontroller.core.IOFMessageListener;
13import net.floodlightcontroller.core.IOFSwitch;
14import net.floodlightcontroller.core.module.FloodlightModuleContext;
15import net.floodlightcontroller.core.module.FloodlightModuleException;
16import net.floodlightcontroller.core.module.IFloodlightModule;
17import net.floodlightcontroller.core.module.IFloodlightService;
18import net.onrc.onos.api.packet.IPacketListener;
19import net.onrc.onos.api.packet.IPacketService;
Jonathan Harte6e63732014-04-16 14:29:49 -070020import net.onrc.onos.core.datagrid.IDatagridService;
21import net.onrc.onos.core.datagrid.IEventChannel;
22import net.onrc.onos.core.datagrid.IEventChannelListener;
23import net.onrc.onos.core.flowprogrammer.IFlowPusherService;
Jonathan Hart1f75cae2014-04-09 17:24:09 -070024import net.onrc.onos.core.packet.Ethernet;
25import net.onrc.onos.core.topology.INetworkGraphService;
26import net.onrc.onos.core.topology.NetworkGraph;
27import net.onrc.onos.core.topology.Port;
28import net.onrc.onos.core.topology.Switch;
Jonathan Harte6e63732014-04-16 14:29:49 -070029import net.onrc.onos.core.util.SwitchPort;
Jonathan Hart1f75cae2014-04-09 17:24:09 -070030
31import org.openflow.protocol.OFMessage;
32import org.openflow.protocol.OFPacketIn;
Jonathan Harte6e63732014-04-16 14:29:49 -070033import org.openflow.protocol.OFPacketOut;
34import org.openflow.protocol.OFPhysicalPort;
35import org.openflow.protocol.OFPort;
Jonathan Hart1f75cae2014-04-09 17:24:09 -070036import org.openflow.protocol.OFType;
Jonathan Harte6e63732014-04-16 14:29:49 -070037import org.openflow.protocol.action.OFAction;
38import org.openflow.protocol.action.OFActionOutput;
39import org.slf4j.Logger;
40import org.slf4j.LoggerFactory;
41
42import com.google.common.collect.HashMultimap;
43import com.google.common.collect.Multimap;
Jonathan Hart1f75cae2014-04-09 17:24:09 -070044
45public class PacketModule implements IOFMessageListener, IPacketService,
46 IFloodlightModule {
Jonathan Harte6e63732014-04-16 14:29:49 -070047 private static final Logger log = LoggerFactory.getLogger(PacketModule.class);
Jonathan Hart1f75cae2014-04-09 17:24:09 -070048
49 private final CopyOnWriteArrayList<IPacketListener> listeners;
50
51 private IFloodlightProviderService floodlightProvider;
52 private NetworkGraph networkGraph;
Jonathan Harte6e63732014-04-16 14:29:49 -070053 private IDatagridService datagrid;
54 private IFlowPusherService flowPusher;
55
56 private IEventChannel<Long, PacketOutNotification>
57 packetOutEventChannel;
58
59 private static final String PACKET_OUT_CHANNEL_NAME =
60 "onos.packet_out";
61
62 private PacketOutEventHandler packetOutEventHandler =
63 new PacketOutEventHandler();
64
65 private class PacketOutEventHandler implements
66 IEventChannelListener<Long, PacketOutNotification> {
67
68 @Override
69 public void entryAdded(PacketOutNotification value) {
70 Multimap<Long, Short> outPorts = value.calculateOutPorts(
71 findLocalEdgePorts());
72 sendPacketToSwitches(outPorts, value.getPacketData());
73 }
74
75 @Override
76 public void entryUpdated(PacketOutNotification value) {
77 entryAdded(value);
78 }
79
80 @Override
81 public void entryRemoved(PacketOutNotification value) {
82 // Not used
83 }
84 }
Jonathan Hart1f75cae2014-04-09 17:24:09 -070085
86 public PacketModule() {
87 listeners = new CopyOnWriteArrayList<>();
88 }
89
90 @Override
91 public void registerPacketListener(IPacketListener listener) {
92 listeners.addIfAbsent(listener);
93 }
94
95 @Override
Jonathan Harte6e63732014-04-16 14:29:49 -070096 public void sendPacket(SwitchPort switchPort, Ethernet eth) {
97 SinglePacketOutNotification notification =
98 new SinglePacketOutNotification(eth.serialize(), 0,
99 switchPort.dpid().value(), switchPort.port().value());
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700100
Jonathan Harte6e63732014-04-16 14:29:49 -0700101 // TODO We shouldn't care what the destination MAC is
102 long dstMac = eth.getDestinationMAC().toLong();
103 packetOutEventChannel.addTransientEntry(dstMac, notification);
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700104 }
105
106 @Override
Jonathan Harte6e63732014-04-16 14:29:49 -0700107 public void sendPacket(List<SwitchPort> switchPorts, Ethernet eth) {
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700108 // TODO Auto-generated method stub
109
110 }
111
112 @Override
113 public void broadcastPacket(Ethernet eth) {
114 // TODO Auto-generated method stub
115
116 }
117
118 @Override
Jonathan Harte6e63732014-04-16 14:29:49 -0700119 public void broadcastPacket(Ethernet eth, SwitchPort inSwitchPort) {
120 BroadcastPacketOutNotification notification =
121 new BroadcastPacketOutNotification(eth.serialize(), 0,
122 inSwitchPort.dpid().value(), inSwitchPort.port().value());
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700123
Jonathan Harte6e63732014-04-16 14:29:49 -0700124 long dstMac = eth.getDestinationMAC().toLong();
125 packetOutEventChannel.addTransientEntry(dstMac, notification);
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700126 }
127
128 @Override
129 public String getName() {
Jonathan Harte6e63732014-04-16 14:29:49 -0700130 return "packetmodule";
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700131 }
132
133 @Override
134 public boolean isCallbackOrderingPrereq(OFType type, String name) {
135 // TODO Auto-generated method stub
136 return false;
137 }
138
139 @Override
140 public boolean isCallbackOrderingPostreq(OFType type, String name) {
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700141 return false;
142 }
143
144 @Override
145 public Command receive(IOFSwitch sw, OFMessage msg,
146 FloodlightContext cntx) {
147 if (!(msg instanceof OFPacketIn)) {
148 return Command.CONTINUE;
149 }
150
151 OFPacketIn pi = (OFPacketIn) msg;
152
153 Ethernet eth = IFloodlightProviderService.bcStore.
154 get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
155
156 Switch networkGraphSwitch;
157 Port inPort;
158 try {
159 networkGraph.acquireReadLock();
160 networkGraphSwitch = networkGraph.getSwitch(sw.getId());
161 inPort = networkGraph.getPort(sw.getId(), (long) pi.getInPort());
162 } finally {
163 networkGraph.releaseReadLock();
164 }
165
166 if (networkGraphSwitch == null || inPort == null) {
167 return Command.CONTINUE;
168 }
169
170 for (IPacketListener listener : listeners) {
171 listener.receive(networkGraphSwitch, inPort, eth);
172 }
173
174 return Command.CONTINUE;
175 }
176
177 @Override
178 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
179 List<Class<? extends IFloodlightService>> services = new ArrayList<>();
180 services.add(IPacketService.class);
181 return services;
182 }
183
184 @Override
185 public Map<Class<? extends IFloodlightService>, IFloodlightService>
Jonathan Harte6e63732014-04-16 14:29:49 -0700186 getServiceImpls() {
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700187 Map<Class<? extends IFloodlightService>, IFloodlightService>
Jonathan Harte6e63732014-04-16 14:29:49 -0700188 serviceImpls = new HashMap<>();
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700189 serviceImpls.put(IPacketService.class, this);
190 return serviceImpls;
191 }
192
193 @Override
194 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
195 List<Class<? extends IFloodlightService>> dependencies = new ArrayList<>();
196 dependencies.add(IFloodlightProviderService.class);
197 dependencies.add(INetworkGraphService.class);
Jonathan Harte6e63732014-04-16 14:29:49 -0700198 dependencies.add(IDatagridService.class);
199 dependencies.add(IFlowPusherService.class);
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700200 return dependencies;
201 }
202
203 @Override
204 public void init(FloodlightModuleContext context)
205 throws FloodlightModuleException {
206 floodlightProvider =
207 context.getServiceImpl(IFloodlightProviderService.class);
208 networkGraph = context.getServiceImpl(INetworkGraphService.class)
209 .getNetworkGraph();
Jonathan Harte6e63732014-04-16 14:29:49 -0700210 datagrid = context.getServiceImpl(IDatagridService.class);
211 flowPusher = context.getServiceImpl(IFlowPusherService.class);
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700212 }
213
214 @Override
215 public void startUp(FloodlightModuleContext context) {
216 floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
Jonathan Harte6e63732014-04-16 14:29:49 -0700217
218 packetOutEventChannel = datagrid.addListener(PACKET_OUT_CHANNEL_NAME,
219 packetOutEventHandler,
220 Long.class,
221 PacketOutNotification.class);
222 }
223
224 private Multimap<Long, Short> findLocalEdgePorts() {
225 Multimap<Long, Short> edgePorts = HashMultimap.create();
226 Map<Long, IOFSwitch> localSwitches = floodlightProvider.getSwitches();
227 for (IOFSwitch sw : localSwitches.values()) {
228 for (OFPhysicalPort localPort : sw.getEnabledPorts()) {
229 Port globalPort =
230 networkGraph.getPort(sw.getId(), (long) localPort.getPortNumber());
231 if (globalPort.getOutgoingLink() == null) {
232 edgePorts.put(sw.getId(), localPort.getPortNumber());
233 }
234 }
235 }
236 return edgePorts;
237 }
238
239 private void sendPacketToSwitches(Multimap<Long, Short> outPorts,
240 byte[] packetData) {
241 for (Long dpid : outPorts.keySet()) {
242 OFPacketOut po = new OFPacketOut();
243 po.setInPort(OFPort.OFPP_NONE)
244 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
245 .setPacketData(packetData);
246
247 List<OFAction> actions = new ArrayList<OFAction>();
248 for (Short port : outPorts.get(dpid)) {
249 actions.add(new OFActionOutput(port));
250 }
251
252 po.setActions(actions);
253 short actionsLength = (short)
254 (actions.size() * OFActionOutput.MINIMUM_LENGTH);
255 po.setActionsLength(actionsLength);
256 po.setLengthU(OFPacketOut.MINIMUM_LENGTH + actionsLength
257 + packetData.length);
258
259 IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
260
261 if (sw == null) {
262 log.warn("Switch not found when sending packet");
263 return;
264 }
265
266 flowPusher.add(sw, po);
267 }
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700268 }
269}