blob: 9cf618af1dfc0ef6739bb29a493de8cb99171dcb [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;
pingping-lin0426dee2014-08-27 15:03:17 -07006import java.util.HashSet;
Jonathan Hart1f75cae2014-04-09 17:24:09 -07007import java.util.List;
8import java.util.Map;
pingping-lin0426dee2014-08-27 15:03:17 -07009import java.util.Set;
Jonathan Hart1f75cae2014-04-09 17:24:09 -070010import java.util.concurrent.CopyOnWriteArrayList;
11
12import net.floodlightcontroller.core.FloodlightContext;
13import net.floodlightcontroller.core.IFloodlightProviderService;
14import net.floodlightcontroller.core.IOFMessageListener;
15import net.floodlightcontroller.core.IOFSwitch;
16import net.floodlightcontroller.core.module.FloodlightModuleContext;
17import net.floodlightcontroller.core.module.FloodlightModuleException;
18import net.floodlightcontroller.core.module.IFloodlightModule;
19import net.floodlightcontroller.core.module.IFloodlightService;
20import net.onrc.onos.api.packet.IPacketListener;
21import net.onrc.onos.api.packet.IPacketService;
Jonathan Harte6e63732014-04-16 14:29:49 -070022import net.onrc.onos.core.datagrid.IDatagridService;
23import net.onrc.onos.core.datagrid.IEventChannel;
24import net.onrc.onos.core.datagrid.IEventChannelListener;
25import net.onrc.onos.core.flowprogrammer.IFlowPusherService;
pingping-lin0426dee2014-08-27 15:03:17 -070026import net.onrc.onos.core.main.config.IConfigInfoService;
Jonathan Hart1f75cae2014-04-09 17:24:09 -070027import net.onrc.onos.core.packet.Ethernet;
Jonathan Harte37e4e22014-05-13 19:12:02 -070028import net.onrc.onos.core.topology.ITopologyService;
Jonathan Hart1f75cae2014-04-09 17:24:09 -070029import net.onrc.onos.core.topology.Port;
30import net.onrc.onos.core.topology.Switch;
Yuta HIGUCHId92b10c2014-08-25 09:30:28 -070031import net.onrc.onos.core.topology.MutableTopology;
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -070032import net.onrc.onos.core.util.Dpid;
33import net.onrc.onos.core.util.PortNumber;
Jonathan Harte6e63732014-04-16 14:29:49 -070034import net.onrc.onos.core.util.SwitchPort;
Jonathan Hart1f75cae2014-04-09 17:24:09 -070035
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070036import org.projectfloodlight.openflow.protocol.OFFactory;
37import org.projectfloodlight.openflow.protocol.OFMessage;
38import org.projectfloodlight.openflow.protocol.OFPacketIn;
39import org.projectfloodlight.openflow.protocol.OFPacketOut;
40import org.projectfloodlight.openflow.protocol.OFPortDesc;
41import org.projectfloodlight.openflow.protocol.OFType;
42import org.projectfloodlight.openflow.protocol.action.OFAction;
43import org.projectfloodlight.openflow.types.OFPort;
Jonathan Harte6e63732014-04-16 14:29:49 -070044import org.slf4j.Logger;
45import org.slf4j.LoggerFactory;
46
47import com.google.common.collect.HashMultimap;
48import com.google.common.collect.Multimap;
Jonathan Hart1f75cae2014-04-09 17:24:09 -070049
50public class PacketModule implements IOFMessageListener, IPacketService,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070051 IFloodlightModule {
Jonathan Harte6e63732014-04-16 14:29:49 -070052 private static final Logger log = LoggerFactory.getLogger(PacketModule.class);
Jonathan Hart1f75cae2014-04-09 17:24:09 -070053
54 private final CopyOnWriteArrayList<IPacketListener> listeners;
55
56 private IFloodlightProviderService floodlightProvider;
Yuta HIGUCHId92b10c2014-08-25 09:30:28 -070057 private MutableTopology mutableTopology;
Jonathan Harte6e63732014-04-16 14:29:49 -070058 private IDatagridService datagrid;
59 private IFlowPusherService flowPusher;
pingping-lin0426dee2014-08-27 15:03:17 -070060 private IConfigInfoService configService;
Jonathan Harte6e63732014-04-16 14:29:49 -070061
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070062 private IEventChannel<Long, PacketOutNotification> packetOutEventChannel;
Jonathan Harte6e63732014-04-16 14:29:49 -070063
64 private static final String PACKET_OUT_CHANNEL_NAME =
65 "onos.packet_out";
66
67 private PacketOutEventHandler packetOutEventHandler =
68 new PacketOutEventHandler();
69
70 private class PacketOutEventHandler implements
71 IEventChannelListener<Long, PacketOutNotification> {
72
73 @Override
74 public void entryAdded(PacketOutNotification value) {
Jonathan Hartf5bd2582014-04-09 17:43:41 -070075 Multimap<Long, Short> localPorts = HashMultimap.create();
pingping-lin0426dee2014-08-27 15:03:17 -070076
Jonathan Hartf5bd2582014-04-09 17:43:41 -070077 for (IOFSwitch sw : floodlightProvider.getSwitches().values()) {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070078 for (OFPortDesc port : sw.getEnabledPorts()) {
79 // XXX S fix this to int
80 localPorts.put(sw.getId(), port.getPortNo().getShortPortNumber());
Jonathan Hartf5bd2582014-04-09 17:43:41 -070081 }
82 }
pingping-lin0426dee2014-08-27 15:03:17 -070083
Jonathan Harte6e63732014-04-16 14:29:49 -070084 Multimap<Long, Short> outPorts = value.calculateOutPorts(
Yuta HIGUCHId92b10c2014-08-25 09:30:28 -070085 localPorts, mutableTopology);
Jonathan Harte6e63732014-04-16 14:29:49 -070086 sendPacketToSwitches(outPorts, value.getPacketData());
87 }
88
89 @Override
90 public void entryUpdated(PacketOutNotification value) {
91 entryAdded(value);
92 }
93
94 @Override
95 public void entryRemoved(PacketOutNotification value) {
96 // Not used
97 }
98 }
Jonathan Hart1f75cae2014-04-09 17:24:09 -070099
100 public PacketModule() {
101 listeners = new CopyOnWriteArrayList<>();
102 }
103
104 @Override
105 public void registerPacketListener(IPacketListener listener) {
106 listeners.addIfAbsent(listener);
107 }
108
109 @Override
Jonathan Harte3702f22014-04-29 02:56:56 -0700110 public void sendPacket(Ethernet eth, SwitchPort switchPort) {
Jonathan Harte6e63732014-04-16 14:29:49 -0700111 SinglePacketOutNotification notification =
112 new SinglePacketOutNotification(eth.serialize(), 0,
Pavlin Radoslavov3d322f42014-08-18 14:58:55 -0700113 switchPort.getDpid().value(), switchPort.getPortNumber().shortValue());
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700114
Jonathan Harte6e63732014-04-16 14:29:49 -0700115 // TODO We shouldn't care what the destination MAC is
116 long dstMac = eth.getDestinationMAC().toLong();
117 packetOutEventChannel.addTransientEntry(dstMac, notification);
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700118 }
119
120 @Override
Jonathan Harte3702f22014-04-29 02:56:56 -0700121 public void sendPacket(Ethernet eth, List<SwitchPort> switchPorts) {
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
pingping-lin0426dee2014-08-27 15:03:17 -0700127 public void broadcastPacketOutInternalEdge(Ethernet eth) {
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700128 // TODO Auto-generated method stub
Jonathan Harte3702f22014-04-29 02:56:56 -0700129 throw new UnsupportedOperationException("Not yet implemented");
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700130 }
131
132 @Override
pingping-lin0426dee2014-08-27 15:03:17 -0700133 public void broadcastPacketOutInternalEdge(Ethernet eth, SwitchPort inSwitchPort) {
134
135 Set<SwitchPort> blacklistSwitchPorts = new HashSet<SwitchPort>(configService
136 .getExternalSwitchPorts());
137 blacklistSwitchPorts.add(inSwitchPort);
138
Jonathan Harte6e63732014-04-16 14:29:49 -0700139 BroadcastPacketOutNotification notification =
140 new BroadcastPacketOutNotification(eth.serialize(), 0,
pingping-lin0426dee2014-08-27 15:03:17 -0700141 blacklistSwitchPorts);
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700142
Jonathan Harte6e63732014-04-16 14:29:49 -0700143 long dstMac = eth.getDestinationMAC().toLong();
144 packetOutEventChannel.addTransientEntry(dstMac, notification);
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700145 }
146
147 @Override
148 public String getName() {
Jonathan Harte6e63732014-04-16 14:29:49 -0700149 return "packetmodule";
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700150 }
151
152 @Override
153 public boolean isCallbackOrderingPrereq(OFType type, String name) {
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700154 return false;
155 }
156
157 @Override
158 public boolean isCallbackOrderingPostreq(OFType type, String name) {
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700159 return false;
160 }
161
162 @Override
163 public Command receive(IOFSwitch sw, OFMessage msg,
164 FloodlightContext cntx) {
165 if (!(msg instanceof OFPacketIn)) {
166 return Command.CONTINUE;
167 }
168
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700169 Ethernet eth = IFloodlightProviderService.bcStore.
170 get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
Yuta HIGUCHIa507baf2014-08-22 13:42:40 -0700171 // FIXME losing port number precision
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700172 short inport = (short) cntx.getStorage()
173 .get(IFloodlightProviderService.CONTEXT_PI_INPORT);
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700174
Jonathan Harte37e4e22014-05-13 19:12:02 -0700175 Switch topologySwitch;
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700176 Port inPort;
177 try {
Yuta HIGUCHId92b10c2014-08-25 09:30:28 -0700178 mutableTopology.acquireReadLock();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700179 Dpid dpid = new Dpid(sw.getId());
Yuta HIGUCHIa507baf2014-08-22 13:42:40 -0700180 PortNumber p = PortNumber.uint16(inport);
Yuta HIGUCHId92b10c2014-08-25 09:30:28 -0700181 topologySwitch = mutableTopology.getSwitch(dpid);
182 inPort = mutableTopology.getPort(dpid, p);
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700183 } finally {
Yuta HIGUCHId92b10c2014-08-25 09:30:28 -0700184 mutableTopology.releaseReadLock();
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700185 }
186
Jonathan Harte37e4e22014-05-13 19:12:02 -0700187 if (topologySwitch == null || inPort == null) {
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700188 // We can't send packets for switches or ports that aren't in the
Jonathan Harte37e4e22014-05-13 19:12:02 -0700189 // topology yet
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700190 return Command.CONTINUE;
191 }
192
193 for (IPacketListener listener : listeners) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700194 listener.receive(topologySwitch, inPort, eth);
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700195 }
196
197 return Command.CONTINUE;
198 }
199
200 @Override
201 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
202 List<Class<? extends IFloodlightService>> services = new ArrayList<>();
203 services.add(IPacketService.class);
204 return services;
205 }
206
207 @Override
208 public Map<Class<? extends IFloodlightService>, IFloodlightService>
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700209 getServiceImpls() {
210
211 Map<Class<? extends IFloodlightService>, IFloodlightService> serviceImpls = new HashMap<>();
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700212 serviceImpls.put(IPacketService.class, this);
213 return serviceImpls;
214 }
215
216 @Override
217 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
218 List<Class<? extends IFloodlightService>> dependencies = new ArrayList<>();
219 dependencies.add(IFloodlightProviderService.class);
Jonathan Harte37e4e22014-05-13 19:12:02 -0700220 dependencies.add(ITopologyService.class);
Jonathan Harte6e63732014-04-16 14:29:49 -0700221 dependencies.add(IDatagridService.class);
222 dependencies.add(IFlowPusherService.class);
pingping-lin0426dee2014-08-27 15:03:17 -0700223 dependencies.add(IConfigInfoService.class);
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700224 return dependencies;
225 }
226
227 @Override
228 public void init(FloodlightModuleContext context)
229 throws FloodlightModuleException {
230 floodlightProvider =
231 context.getServiceImpl(IFloodlightProviderService.class);
Yuta HIGUCHId92b10c2014-08-25 09:30:28 -0700232 mutableTopology = context.getServiceImpl(ITopologyService.class)
Jonathan Harte37e4e22014-05-13 19:12:02 -0700233 .getTopology();
Jonathan Harte6e63732014-04-16 14:29:49 -0700234 datagrid = context.getServiceImpl(IDatagridService.class);
235 flowPusher = context.getServiceImpl(IFlowPusherService.class);
pingping-lin0426dee2014-08-27 15:03:17 -0700236 configService = context.getServiceImpl(IConfigInfoService.class);
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700237 }
238
239 @Override
240 public void startUp(FloodlightModuleContext context) {
241 floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
Jonathan Harte6e63732014-04-16 14:29:49 -0700242 packetOutEventChannel = datagrid.addListener(PACKET_OUT_CHANNEL_NAME,
243 packetOutEventHandler,
244 Long.class,
245 PacketOutNotification.class);
246 }
247
Jonathan Harte6e63732014-04-16 14:29:49 -0700248 private void sendPacketToSwitches(Multimap<Long, Short> outPorts,
249 byte[] packetData) {
250 for (Long dpid : outPorts.keySet()) {
Jonathan Harte6e63732014-04-16 14:29:49 -0700251 IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
252
253 if (sw == null) {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700254 log.warn("Switch {} not found when sending packet", dpid);
255 continue;
Jonathan Harte6e63732014-04-16 14:29:49 -0700256 }
257
Jonathan Harta213bce2014-08-11 15:44:07 -0700258 OFFactory factory = sw.getFactory();
259
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700260 List<OFAction> actions = new ArrayList<>();
261 for (Short port : outPorts.get(dpid)) {
262 actions.add(factory.actions().output(OFPort.of(port), Short.MAX_VALUE));
263 }
264
265 OFPacketOut po = factory.buildPacketOut()
266 .setData(packetData)
267 .setActions(actions)
268 .build();
269
Jonathan Hart5302b6c2014-08-13 15:57:59 -0700270 flowPusher.add(new Dpid(sw.getId()), po);
Jonathan Harte6e63732014-04-16 14:29:49 -0700271 }
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700272 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700273
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700274}