blob: 63143cdf72b282eccd6e9a6a7913b30bba00ecbf [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
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070033import org.projectfloodlight.openflow.protocol.OFFactory;
34import org.projectfloodlight.openflow.protocol.OFMessage;
35import org.projectfloodlight.openflow.protocol.OFPacketIn;
36import org.projectfloodlight.openflow.protocol.OFPacketOut;
37import org.projectfloodlight.openflow.protocol.OFPortDesc;
38import org.projectfloodlight.openflow.protocol.OFType;
39import org.projectfloodlight.openflow.protocol.action.OFAction;
40import org.projectfloodlight.openflow.types.OFPort;
Jonathan Harte6e63732014-04-16 14:29:49 -070041import 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,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070048 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;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070057 private OFFactory factory;
Jonathan Harte6e63732014-04-16 14:29:49 -070058
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070059 private IEventChannel<Long, PacketOutNotification> packetOutEventChannel;
Jonathan Harte6e63732014-04-16 14:29:49 -070060
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()) {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070074 for (OFPortDesc port : sw.getEnabledPorts()) {
75 // XXX S fix this to int
76 localPorts.put(sw.getId(), port.getPortNo().getShortPortNumber());
Jonathan Hartf5bd2582014-04-09 17:43:41 -070077 }
78 }
Jonathan Harte6e63732014-04-16 14:29:49 -070079 Multimap<Long, Short> outPorts = value.calculateOutPorts(
Jonathan Harte37e4e22014-05-13 19:12:02 -070080 localPorts, topology);
Jonathan Harte6e63732014-04-16 14:29:49 -070081 sendPacketToSwitches(outPorts, value.getPacketData());
82 }
83
84 @Override
85 public void entryUpdated(PacketOutNotification value) {
86 entryAdded(value);
87 }
88
89 @Override
90 public void entryRemoved(PacketOutNotification value) {
91 // Not used
92 }
93 }
Jonathan Hart1f75cae2014-04-09 17:24:09 -070094
95 public PacketModule() {
96 listeners = new CopyOnWriteArrayList<>();
97 }
98
99 @Override
100 public void registerPacketListener(IPacketListener listener) {
101 listeners.addIfAbsent(listener);
102 }
103
104 @Override
Jonathan Harte3702f22014-04-29 02:56:56 -0700105 public void sendPacket(Ethernet eth, SwitchPort switchPort) {
Jonathan Harte6e63732014-04-16 14:29:49 -0700106 SinglePacketOutNotification notification =
107 new SinglePacketOutNotification(eth.serialize(), 0,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700108 switchPort.dpid().value(), switchPort.port().shortValue());
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700109
Jonathan Harte6e63732014-04-16 14:29:49 -0700110 // TODO We shouldn't care what the destination MAC is
111 long dstMac = eth.getDestinationMAC().toLong();
112 packetOutEventChannel.addTransientEntry(dstMac, notification);
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700113 }
114
115 @Override
Jonathan Harte3702f22014-04-29 02:56:56 -0700116 public void sendPacket(Ethernet eth, List<SwitchPort> switchPorts) {
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700117 // TODO Auto-generated method stub
Jonathan Harte3702f22014-04-29 02:56:56 -0700118 throw new UnsupportedOperationException("Not yet implemented");
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700119 }
120
121 @Override
Jonathan Harte3702f22014-04-29 02:56:56 -0700122 public void broadcastPacketOutEdge(Ethernet eth) {
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700123 // TODO Auto-generated method stub
Jonathan Harte3702f22014-04-29 02:56:56 -0700124 throw new UnsupportedOperationException("Not yet implemented");
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700125 }
126
127 @Override
Jonathan Harte3702f22014-04-29 02:56:56 -0700128 public void broadcastPacketOutEdge(Ethernet eth, SwitchPort inSwitchPort) {
Jonathan Harte6e63732014-04-16 14:29:49 -0700129 BroadcastPacketOutNotification notification =
130 new BroadcastPacketOutNotification(eth.serialize(), 0,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700131 inSwitchPort.dpid().value(), inSwitchPort.port().shortValue());
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700132
Jonathan Harte6e63732014-04-16 14:29:49 -0700133 long dstMac = eth.getDestinationMAC().toLong();
134 packetOutEventChannel.addTransientEntry(dstMac, notification);
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700135 }
136
137 @Override
138 public String getName() {
Jonathan Harte6e63732014-04-16 14:29:49 -0700139 return "packetmodule";
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700140 }
141
142 @Override
143 public boolean isCallbackOrderingPrereq(OFType type, String name) {
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700144 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
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700159 Ethernet eth = IFloodlightProviderService.bcStore.
160 get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700161 short inport = (short) cntx.getStorage()
162 .get(IFloodlightProviderService.CONTEXT_PI_INPORT);
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700163
Jonathan Harte37e4e22014-05-13 19:12:02 -0700164 Switch topologySwitch;
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700165 Port inPort;
166 try {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700167 topology.acquireReadLock();
168 Dpid dpid = new Dpid(sw.getId());
169 PortNumber p = new PortNumber(inport);
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700170 topologySwitch = topology.getSwitch(dpid);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700171 inPort = topology.getPort(dpid, p);
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700172 } finally {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700173 topology.releaseReadLock();
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700174 }
175
Jonathan Harte37e4e22014-05-13 19:12:02 -0700176 if (topologySwitch == null || inPort == null) {
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700177 // We can't send packets for switches or ports that aren't in the
Jonathan Harte37e4e22014-05-13 19:12:02 -0700178 // topology yet
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700179 return Command.CONTINUE;
180 }
181
182 for (IPacketListener listener : listeners) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700183 listener.receive(topologySwitch, inPort, eth);
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700184 }
185
186 return Command.CONTINUE;
187 }
188
189 @Override
190 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
191 List<Class<? extends IFloodlightService>> services = new ArrayList<>();
192 services.add(IPacketService.class);
193 return services;
194 }
195
196 @Override
197 public Map<Class<? extends IFloodlightService>, IFloodlightService>
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700198 getServiceImpls() {
199
200 Map<Class<? extends IFloodlightService>, IFloodlightService> serviceImpls = new HashMap<>();
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700201 serviceImpls.put(IPacketService.class, this);
202 return serviceImpls;
203 }
204
205 @Override
206 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
207 List<Class<? extends IFloodlightService>> dependencies = new ArrayList<>();
208 dependencies.add(IFloodlightProviderService.class);
Jonathan Harte37e4e22014-05-13 19:12:02 -0700209 dependencies.add(ITopologyService.class);
Jonathan Harte6e63732014-04-16 14:29:49 -0700210 dependencies.add(IDatagridService.class);
211 dependencies.add(IFlowPusherService.class);
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700212 return dependencies;
213 }
214
215 @Override
216 public void init(FloodlightModuleContext context)
217 throws FloodlightModuleException {
218 floodlightProvider =
219 context.getServiceImpl(IFloodlightProviderService.class);
Jonathan Harte37e4e22014-05-13 19:12:02 -0700220 topology = context.getServiceImpl(ITopologyService.class)
221 .getTopology();
Jonathan Harte6e63732014-04-16 14:29:49 -0700222 datagrid = context.getServiceImpl(IDatagridService.class);
223 flowPusher = context.getServiceImpl(IFlowPusherService.class);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700224 factory = floodlightProvider.getOFMessageFactory_10();
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700225 }
226
227 @Override
228 public void startUp(FloodlightModuleContext context) {
229 floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
Jonathan Harte6e63732014-04-16 14:29:49 -0700230 packetOutEventChannel = datagrid.addListener(PACKET_OUT_CHANNEL_NAME,
231 packetOutEventHandler,
232 Long.class,
233 PacketOutNotification.class);
234 }
235
Jonathan Harte6e63732014-04-16 14:29:49 -0700236 private void sendPacketToSwitches(Multimap<Long, Short> outPorts,
237 byte[] packetData) {
238 for (Long dpid : outPorts.keySet()) {
Jonathan Harte6e63732014-04-16 14:29:49 -0700239 IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
240
241 if (sw == null) {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700242 log.warn("Switch {} not found when sending packet", dpid);
243 continue;
Jonathan Harte6e63732014-04-16 14:29:49 -0700244 }
245
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700246 List<OFAction> actions = new ArrayList<>();
247 for (Short port : outPorts.get(dpid)) {
248 actions.add(factory.actions().output(OFPort.of(port), Short.MAX_VALUE));
249 }
250
251 OFPacketOut po = factory.buildPacketOut()
252 .setData(packetData)
253 .setActions(actions)
254 .build();
255
Jonathan Harte6e63732014-04-16 14:29:49 -0700256 flowPusher.add(sw, po);
257 }
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700258 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700259
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700260}