blob: 9a03fed0b59117a0ac30b765d0cdb769fd745fae [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;
Jonathan Harte37e4e22014-05-13 19:12:02 -070025import net.onrc.onos.core.topology.ITopologyService;
Jonathan Hart1f75cae2014-04-09 17:24:09 -070026import net.onrc.onos.core.topology.Port;
27import net.onrc.onos.core.topology.Switch;
Jonathan Harte37e4e22014-05-13 19:12:02 -070028import net.onrc.onos.core.topology.Topology;
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -070029import net.onrc.onos.core.util.Dpid;
30import net.onrc.onos.core.util.PortNumber;
Jonathan Harte6e63732014-04-16 14:29:49 -070031import net.onrc.onos.core.util.SwitchPort;
Jonathan Hart1f75cae2014-04-09 17:24:09 -070032
33import org.openflow.protocol.OFMessage;
34import org.openflow.protocol.OFPacketIn;
Jonathan Harte6e63732014-04-16 14:29:49 -070035import org.openflow.protocol.OFPacketOut;
36import org.openflow.protocol.OFPhysicalPort;
37import org.openflow.protocol.OFPort;
Jonathan Hart1f75cae2014-04-09 17:24:09 -070038import org.openflow.protocol.OFType;
Jonathan Harte6e63732014-04-16 14:29:49 -070039import org.openflow.protocol.action.OFAction;
40import org.openflow.protocol.action.OFActionOutput;
41import org.slf4j.Logger;
42import org.slf4j.LoggerFactory;
43
44import com.google.common.collect.HashMultimap;
45import com.google.common.collect.Multimap;
Jonathan Hart1f75cae2014-04-09 17:24:09 -070046
47public class PacketModule implements IOFMessageListener, IPacketService,
48 IFloodlightModule {
Jonathan Harte6e63732014-04-16 14:29:49 -070049 private static final Logger log = LoggerFactory.getLogger(PacketModule.class);
Jonathan Hart1f75cae2014-04-09 17:24:09 -070050
51 private final CopyOnWriteArrayList<IPacketListener> listeners;
52
53 private IFloodlightProviderService floodlightProvider;
Jonathan Harte37e4e22014-05-13 19:12:02 -070054 private Topology topology;
Jonathan Harte6e63732014-04-16 14:29:49 -070055 private IDatagridService datagrid;
56 private IFlowPusherService flowPusher;
57
58 private IEventChannel<Long, PacketOutNotification>
59 packetOutEventChannel;
60
61 private static final String PACKET_OUT_CHANNEL_NAME =
62 "onos.packet_out";
63
64 private PacketOutEventHandler packetOutEventHandler =
65 new PacketOutEventHandler();
66
67 private class PacketOutEventHandler implements
68 IEventChannelListener<Long, PacketOutNotification> {
69
70 @Override
71 public void entryAdded(PacketOutNotification value) {
Jonathan Hartf5bd2582014-04-09 17:43:41 -070072 Multimap<Long, Short> localPorts = HashMultimap.create();
73 for (IOFSwitch sw : floodlightProvider.getSwitches().values()) {
74 for (OFPhysicalPort port : sw.getEnabledPorts()) {
75 localPorts.put(sw.getId(), port.getPortNumber());
76 }
77 }
Jonathan Harte6e63732014-04-16 14:29:49 -070078 Multimap<Long, Short> outPorts = value.calculateOutPorts(
Jonathan Harte37e4e22014-05-13 19:12:02 -070079 localPorts, topology);
Jonathan Harte6e63732014-04-16 14:29:49 -070080 sendPacketToSwitches(outPorts, value.getPacketData());
81 }
82
83 @Override
84 public void entryUpdated(PacketOutNotification value) {
85 entryAdded(value);
86 }
87
88 @Override
89 public void entryRemoved(PacketOutNotification value) {
90 // Not used
91 }
92 }
Jonathan Hart1f75cae2014-04-09 17:24:09 -070093
94 public PacketModule() {
95 listeners = new CopyOnWriteArrayList<>();
96 }
97
98 @Override
99 public void registerPacketListener(IPacketListener listener) {
100 listeners.addIfAbsent(listener);
101 }
102
103 @Override
Jonathan Harte3702f22014-04-29 02:56:56 -0700104 public void sendPacket(Ethernet eth, SwitchPort switchPort) {
Jonathan Harte6e63732014-04-16 14:29:49 -0700105 SinglePacketOutNotification notification =
106 new SinglePacketOutNotification(eth.serialize(), 0,
107 switchPort.dpid().value(), switchPort.port().value());
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700108
Jonathan Harte6e63732014-04-16 14:29:49 -0700109 // TODO We shouldn't care what the destination MAC is
110 long dstMac = eth.getDestinationMAC().toLong();
111 packetOutEventChannel.addTransientEntry(dstMac, notification);
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700112 }
113
114 @Override
Jonathan Harte3702f22014-04-29 02:56:56 -0700115 public void sendPacket(Ethernet eth, List<SwitchPort> switchPorts) {
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700116 // TODO Auto-generated method stub
Jonathan Harte3702f22014-04-29 02:56:56 -0700117 throw new UnsupportedOperationException("Not yet implemented");
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700118 }
119
120 @Override
Jonathan Harte3702f22014-04-29 02:56:56 -0700121 public void broadcastPacketOutEdge(Ethernet eth) {
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700122 // TODO Auto-generated method stub
Jonathan Harte3702f22014-04-29 02:56:56 -0700123 throw new UnsupportedOperationException("Not yet implemented");
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700124 }
125
126 @Override
Jonathan Harte3702f22014-04-29 02:56:56 -0700127 public void broadcastPacketOutEdge(Ethernet eth, SwitchPort inSwitchPort) {
Jonathan Harte6e63732014-04-16 14:29:49 -0700128 BroadcastPacketOutNotification notification =
129 new BroadcastPacketOutNotification(eth.serialize(), 0,
130 inSwitchPort.dpid().value(), inSwitchPort.port().value());
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700131
Jonathan Harte6e63732014-04-16 14:29:49 -0700132 long dstMac = eth.getDestinationMAC().toLong();
133 packetOutEventChannel.addTransientEntry(dstMac, notification);
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700134 }
135
136 @Override
137 public String getName() {
Jonathan Harte6e63732014-04-16 14:29:49 -0700138 return "packetmodule";
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700139 }
140
141 @Override
142 public boolean isCallbackOrderingPrereq(OFType type, String name) {
143 // TODO Auto-generated method stub
144 return false;
145 }
146
147 @Override
148 public boolean isCallbackOrderingPostreq(OFType type, String name) {
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700149 return false;
150 }
151
152 @Override
153 public Command receive(IOFSwitch sw, OFMessage msg,
154 FloodlightContext cntx) {
155 if (!(msg instanceof OFPacketIn)) {
156 return Command.CONTINUE;
157 }
158
159 OFPacketIn pi = (OFPacketIn) msg;
160
161 Ethernet eth = IFloodlightProviderService.bcStore.
162 get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
163
Jonathan Harte37e4e22014-05-13 19:12:02 -0700164 Switch topologySwitch;
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700165 Port inPort;
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700166 final Dpid dpid = new Dpid(sw.getId());
167 topology.acquireReadLock();
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700168 try {
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700169 topologySwitch = topology.getSwitch(dpid);
170 inPort = topology.getPort(dpid, new PortNumber(pi.getInPort()));
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700171 } finally {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700172 topology.releaseReadLock();
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700173 }
174
Jonathan Harte37e4e22014-05-13 19:12:02 -0700175 if (topologySwitch == null || inPort == null) {
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700176 // We can't send packets for switches or ports that aren't in the
Jonathan Harte37e4e22014-05-13 19:12:02 -0700177 // topology yet
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700178 return Command.CONTINUE;
179 }
180
181 for (IPacketListener listener : listeners) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700182 listener.receive(topologySwitch, inPort, eth);
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700183 }
184
185 return Command.CONTINUE;
186 }
187
188 @Override
189 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
190 List<Class<? extends IFloodlightService>> services = new ArrayList<>();
191 services.add(IPacketService.class);
192 return services;
193 }
194
195 @Override
196 public Map<Class<? extends IFloodlightService>, IFloodlightService>
Jonathan Harte6e63732014-04-16 14:29:49 -0700197 getServiceImpls() {
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700198 Map<Class<? extends IFloodlightService>, IFloodlightService>
Jonathan Harte6e63732014-04-16 14:29:49 -0700199 serviceImpls = new HashMap<>();
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700200 serviceImpls.put(IPacketService.class, this);
201 return serviceImpls;
202 }
203
204 @Override
205 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
206 List<Class<? extends IFloodlightService>> dependencies = new ArrayList<>();
207 dependencies.add(IFloodlightProviderService.class);
Jonathan Harte37e4e22014-05-13 19:12:02 -0700208 dependencies.add(ITopologyService.class);
Jonathan Harte6e63732014-04-16 14:29:49 -0700209 dependencies.add(IDatagridService.class);
210 dependencies.add(IFlowPusherService.class);
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700211 return dependencies;
212 }
213
214 @Override
215 public void init(FloodlightModuleContext context)
216 throws FloodlightModuleException {
217 floodlightProvider =
218 context.getServiceImpl(IFloodlightProviderService.class);
Jonathan Harte37e4e22014-05-13 19:12:02 -0700219 topology = context.getServiceImpl(ITopologyService.class)
220 .getTopology();
Jonathan Harte6e63732014-04-16 14:29:49 -0700221 datagrid = context.getServiceImpl(IDatagridService.class);
222 flowPusher = context.getServiceImpl(IFlowPusherService.class);
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700223 }
224
225 @Override
226 public void startUp(FloodlightModuleContext context) {
227 floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
Jonathan Harte6e63732014-04-16 14:29:49 -0700228
229 packetOutEventChannel = datagrid.addListener(PACKET_OUT_CHANNEL_NAME,
230 packetOutEventHandler,
231 Long.class,
232 PacketOutNotification.class);
233 }
234
Jonathan Harte6e63732014-04-16 14:29:49 -0700235 private void sendPacketToSwitches(Multimap<Long, Short> outPorts,
236 byte[] packetData) {
237 for (Long dpid : outPorts.keySet()) {
238 OFPacketOut po = new OFPacketOut();
239 po.setInPort(OFPort.OFPP_NONE)
240 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
241 .setPacketData(packetData);
242
243 List<OFAction> actions = new ArrayList<OFAction>();
244 for (Short port : outPorts.get(dpid)) {
245 actions.add(new OFActionOutput(port));
246 }
247
248 po.setActions(actions);
249 short actionsLength = (short)
250 (actions.size() * OFActionOutput.MINIMUM_LENGTH);
251 po.setActionsLength(actionsLength);
252 po.setLengthU(OFPacketOut.MINIMUM_LENGTH + actionsLength
253 + packetData.length);
254
255 IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
256
257 if (sw == null) {
258 log.warn("Switch not found when sending packet");
259 return;
260 }
261
262 flowPusher.add(sw, po);
263 }
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700264 }
265}