blob: 2bed63960b1e50cc59a9441b14a10c8ef5ae07ea [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;
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;
Jonathan Harte37e4e22014-05-13 19:12:02 -070052 private Topology topology;
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) {
Jonathan Hartf5bd2582014-04-09 17:43:41 -070070 Multimap<Long, Short> localPorts = HashMultimap.create();
71 for (IOFSwitch sw : floodlightProvider.getSwitches().values()) {
72 for (OFPhysicalPort port : sw.getEnabledPorts()) {
73 localPorts.put(sw.getId(), port.getPortNumber());
74 }
75 }
Jonathan Harte6e63732014-04-16 14:29:49 -070076 Multimap<Long, Short> outPorts = value.calculateOutPorts(
Jonathan Harte37e4e22014-05-13 19:12:02 -070077 localPorts, topology);
Jonathan Harte6e63732014-04-16 14:29:49 -070078 sendPacketToSwitches(outPorts, value.getPacketData());
79 }
80
81 @Override
82 public void entryUpdated(PacketOutNotification value) {
83 entryAdded(value);
84 }
85
86 @Override
87 public void entryRemoved(PacketOutNotification value) {
88 // Not used
89 }
90 }
Jonathan Hart1f75cae2014-04-09 17:24:09 -070091
92 public PacketModule() {
93 listeners = new CopyOnWriteArrayList<>();
94 }
95
96 @Override
97 public void registerPacketListener(IPacketListener listener) {
98 listeners.addIfAbsent(listener);
99 }
100
101 @Override
Jonathan Harte3702f22014-04-29 02:56:56 -0700102 public void sendPacket(Ethernet eth, SwitchPort switchPort) {
Jonathan Harte6e63732014-04-16 14:29:49 -0700103 SinglePacketOutNotification notification =
104 new SinglePacketOutNotification(eth.serialize(), 0,
105 switchPort.dpid().value(), switchPort.port().value());
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700106
Jonathan Harte6e63732014-04-16 14:29:49 -0700107 // TODO We shouldn't care what the destination MAC is
108 long dstMac = eth.getDestinationMAC().toLong();
109 packetOutEventChannel.addTransientEntry(dstMac, notification);
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700110 }
111
112 @Override
Jonathan Harte3702f22014-04-29 02:56:56 -0700113 public void sendPacket(Ethernet eth, List<SwitchPort> switchPorts) {
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700114 // TODO Auto-generated method stub
Jonathan Harte3702f22014-04-29 02:56:56 -0700115 throw new UnsupportedOperationException("Not yet implemented");
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700116 }
117
118 @Override
Jonathan Harte3702f22014-04-29 02:56:56 -0700119 public void broadcastPacketOutEdge(Ethernet eth) {
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700120 // TODO Auto-generated method stub
Jonathan Harte3702f22014-04-29 02:56:56 -0700121 throw new UnsupportedOperationException("Not yet implemented");
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700122 }
123
124 @Override
Jonathan Harte3702f22014-04-29 02:56:56 -0700125 public void broadcastPacketOutEdge(Ethernet eth, SwitchPort inSwitchPort) {
Jonathan Harte6e63732014-04-16 14:29:49 -0700126 BroadcastPacketOutNotification notification =
127 new BroadcastPacketOutNotification(eth.serialize(), 0,
128 inSwitchPort.dpid().value(), inSwitchPort.port().value());
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700129
Jonathan Harte6e63732014-04-16 14:29:49 -0700130 long dstMac = eth.getDestinationMAC().toLong();
131 packetOutEventChannel.addTransientEntry(dstMac, notification);
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700132 }
133
134 @Override
135 public String getName() {
Jonathan Harte6e63732014-04-16 14:29:49 -0700136 return "packetmodule";
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700137 }
138
139 @Override
140 public boolean isCallbackOrderingPrereq(OFType type, String name) {
141 // TODO Auto-generated method stub
142 return false;
143 }
144
145 @Override
146 public boolean isCallbackOrderingPostreq(OFType type, String name) {
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700147 return false;
148 }
149
150 @Override
151 public Command receive(IOFSwitch sw, OFMessage msg,
152 FloodlightContext cntx) {
153 if (!(msg instanceof OFPacketIn)) {
154 return Command.CONTINUE;
155 }
156
157 OFPacketIn pi = (OFPacketIn) msg;
158
159 Ethernet eth = IFloodlightProviderService.bcStore.
160 get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
161
Jonathan Harte37e4e22014-05-13 19:12:02 -0700162 Switch topologySwitch;
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700163 Port inPort;
164 try {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700165 topology.acquireReadLock();
166 topologySwitch = topology.getSwitch(sw.getId());
167 inPort = topology.getPort(sw.getId(), (long) pi.getInPort());
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700168 } finally {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700169 topology.releaseReadLock();
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700170 }
171
Jonathan Harte37e4e22014-05-13 19:12:02 -0700172 if (topologySwitch == null || inPort == null) {
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700173 // We can't send packets for switches or ports that aren't in the
Jonathan Harte37e4e22014-05-13 19:12:02 -0700174 // topology yet
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700175 return Command.CONTINUE;
176 }
177
178 for (IPacketListener listener : listeners) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700179 listener.receive(topologySwitch, inPort, eth);
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700180 }
181
182 return Command.CONTINUE;
183 }
184
185 @Override
186 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
187 List<Class<? extends IFloodlightService>> services = new ArrayList<>();
188 services.add(IPacketService.class);
189 return services;
190 }
191
192 @Override
193 public Map<Class<? extends IFloodlightService>, IFloodlightService>
Jonathan Harte6e63732014-04-16 14:29:49 -0700194 getServiceImpls() {
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700195 Map<Class<? extends IFloodlightService>, IFloodlightService>
Jonathan Harte6e63732014-04-16 14:29:49 -0700196 serviceImpls = new HashMap<>();
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700197 serviceImpls.put(IPacketService.class, this);
198 return serviceImpls;
199 }
200
201 @Override
202 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
203 List<Class<? extends IFloodlightService>> dependencies = new ArrayList<>();
204 dependencies.add(IFloodlightProviderService.class);
Jonathan Harte37e4e22014-05-13 19:12:02 -0700205 dependencies.add(ITopologyService.class);
Jonathan Harte6e63732014-04-16 14:29:49 -0700206 dependencies.add(IDatagridService.class);
207 dependencies.add(IFlowPusherService.class);
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700208 return dependencies;
209 }
210
211 @Override
212 public void init(FloodlightModuleContext context)
213 throws FloodlightModuleException {
214 floodlightProvider =
215 context.getServiceImpl(IFloodlightProviderService.class);
Jonathan Harte37e4e22014-05-13 19:12:02 -0700216 topology = context.getServiceImpl(ITopologyService.class)
217 .getTopology();
Jonathan Harte6e63732014-04-16 14:29:49 -0700218 datagrid = context.getServiceImpl(IDatagridService.class);
219 flowPusher = context.getServiceImpl(IFlowPusherService.class);
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700220 }
221
222 @Override
223 public void startUp(FloodlightModuleContext context) {
224 floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
Jonathan Harte6e63732014-04-16 14:29:49 -0700225
226 packetOutEventChannel = datagrid.addListener(PACKET_OUT_CHANNEL_NAME,
227 packetOutEventHandler,
228 Long.class,
229 PacketOutNotification.class);
230 }
231
Jonathan Harte6e63732014-04-16 14:29:49 -0700232 private void sendPacketToSwitches(Multimap<Long, Short> outPorts,
233 byte[] packetData) {
234 for (Long dpid : outPorts.keySet()) {
235 OFPacketOut po = new OFPacketOut();
236 po.setInPort(OFPort.OFPP_NONE)
237 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
238 .setPacketData(packetData);
239
240 List<OFAction> actions = new ArrayList<OFAction>();
241 for (Short port : outPorts.get(dpid)) {
242 actions.add(new OFActionOutput(port));
243 }
244
245 po.setActions(actions);
246 short actionsLength = (short)
247 (actions.size() * OFActionOutput.MINIMUM_LENGTH);
248 po.setActionsLength(actionsLength);
249 po.setLengthU(OFPacketOut.MINIMUM_LENGTH + actionsLength
250 + packetData.length);
251
252 IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
253
254 if (sw == null) {
255 log.warn("Switch not found when sending packet");
256 return;
257 }
258
259 flowPusher.add(sw, po);
260 }
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700261 }
262}