blob: ce79994cfdf69bf2e4dbc1ef6885cbbd51542f01 [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;
Yuta HIGUCHId92b10c2014-08-25 09:30:28 -070028import net.onrc.onos.core.topology.MutableTopology;
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;
Yuta HIGUCHId92b10c2014-08-25 09:30:28 -070054 private MutableTopology mutableTopology;
Jonathan Harte6e63732014-04-16 14:29:49 -070055 private IDatagridService datagrid;
56 private IFlowPusherService flowPusher;
57
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070058 private IEventChannel<Long, PacketOutNotification> packetOutEventChannel;
Jonathan Harte6e63732014-04-16 14:29:49 -070059
60 private static final String PACKET_OUT_CHANNEL_NAME =
61 "onos.packet_out";
62
63 private PacketOutEventHandler packetOutEventHandler =
64 new PacketOutEventHandler();
65
66 private class PacketOutEventHandler implements
67 IEventChannelListener<Long, PacketOutNotification> {
68
69 @Override
70 public void entryAdded(PacketOutNotification value) {
Jonathan Hartf5bd2582014-04-09 17:43:41 -070071 Multimap<Long, Short> localPorts = HashMultimap.create();
72 for (IOFSwitch sw : floodlightProvider.getSwitches().values()) {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070073 for (OFPortDesc port : sw.getEnabledPorts()) {
74 // XXX S fix this to int
75 localPorts.put(sw.getId(), port.getPortNo().getShortPortNumber());
Jonathan Hartf5bd2582014-04-09 17:43:41 -070076 }
77 }
Jonathan Harte6e63732014-04-16 14:29:49 -070078 Multimap<Long, Short> outPorts = value.calculateOutPorts(
Yuta HIGUCHId92b10c2014-08-25 09:30:28 -070079 localPorts, mutableTopology);
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,
Pavlin Radoslavov3d322f42014-08-18 14:58:55 -0700107 switchPort.getDpid().value(), switchPort.getPortNumber().shortValue());
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,
Pavlin Radoslavov3d322f42014-08-18 14:58:55 -0700130 inSwitchPort.getDpid().value(), inSwitchPort.getPortNumber().shortValue());
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) {
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700143 return false;
144 }
145
146 @Override
147 public boolean isCallbackOrderingPostreq(OFType type, String name) {
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700148 return false;
149 }
150
151 @Override
152 public Command receive(IOFSwitch sw, OFMessage msg,
153 FloodlightContext cntx) {
154 if (!(msg instanceof OFPacketIn)) {
155 return Command.CONTINUE;
156 }
157
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700158 Ethernet eth = IFloodlightProviderService.bcStore.
159 get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
Yuta HIGUCHIa507baf2014-08-22 13:42:40 -0700160 // FIXME losing port number precision
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 {
Yuta HIGUCHId92b10c2014-08-25 09:30:28 -0700167 mutableTopology.acquireReadLock();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700168 Dpid dpid = new Dpid(sw.getId());
Yuta HIGUCHIa507baf2014-08-22 13:42:40 -0700169 PortNumber p = PortNumber.uint16(inport);
Yuta HIGUCHId92b10c2014-08-25 09:30:28 -0700170 topologySwitch = mutableTopology.getSwitch(dpid);
171 inPort = mutableTopology.getPort(dpid, p);
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700172 } finally {
Yuta HIGUCHId92b10c2014-08-25 09:30:28 -0700173 mutableTopology.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);
Yuta HIGUCHId92b10c2014-08-25 09:30:28 -0700220 mutableTopology = context.getServiceImpl(ITopologyService.class)
Jonathan Harte37e4e22014-05-13 19:12:02 -0700221 .getTopology();
Jonathan Harte6e63732014-04-16 14:29:49 -0700222 datagrid = context.getServiceImpl(IDatagridService.class);
223 flowPusher = context.getServiceImpl(IFlowPusherService.class);
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700224 }
225
226 @Override
227 public void startUp(FloodlightModuleContext context) {
228 floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
Jonathan Harte6e63732014-04-16 14:29:49 -0700229 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()) {
Jonathan Harte6e63732014-04-16 14:29:49 -0700238 IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
239
240 if (sw == null) {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700241 log.warn("Switch {} not found when sending packet", dpid);
242 continue;
Jonathan Harte6e63732014-04-16 14:29:49 -0700243 }
244
Jonathan Harta213bce2014-08-11 15:44:07 -0700245 OFFactory factory = sw.getFactory();
246
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700247 List<OFAction> actions = new ArrayList<>();
248 for (Short port : outPorts.get(dpid)) {
249 actions.add(factory.actions().output(OFPort.of(port), Short.MAX_VALUE));
250 }
251
252 OFPacketOut po = factory.buildPacketOut()
253 .setData(packetData)
254 .setActions(actions)
255 .build();
256
Jonathan Harte6e63732014-04-16 14:29:49 -0700257 flowPusher.add(sw, po);
258 }
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700259 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700260
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700261}