blob: 4cfb9e7ac0e6bef2983fb0640c918d7af08571ab [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
pingping-lin9af35cd2014-09-05 15:22:39 -0700135 Set<SwitchPort> blacklistSwitchPorts = new HashSet<SwitchPort>();
136 Set<SwitchPort> externalSwitchPorts = configService.getExternalSwitchPorts();
137 if (externalSwitchPorts != null) {
138 blacklistSwitchPorts.addAll(externalSwitchPorts);
139 }
pingping-lin0426dee2014-08-27 15:03:17 -0700140 blacklistSwitchPorts.add(inSwitchPort);
141
Jonathan Harte6e63732014-04-16 14:29:49 -0700142 BroadcastPacketOutNotification notification =
143 new BroadcastPacketOutNotification(eth.serialize(), 0,
pingping-lin0426dee2014-08-27 15:03:17 -0700144 blacklistSwitchPorts);
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700145
Jonathan Harte6e63732014-04-16 14:29:49 -0700146 long dstMac = eth.getDestinationMAC().toLong();
147 packetOutEventChannel.addTransientEntry(dstMac, notification);
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700148 }
149
150 @Override
151 public String getName() {
Jonathan Harte6e63732014-04-16 14:29:49 -0700152 return "packetmodule";
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700153 }
154
155 @Override
156 public boolean isCallbackOrderingPrereq(OFType type, String name) {
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700157 return false;
158 }
159
160 @Override
161 public boolean isCallbackOrderingPostreq(OFType type, String name) {
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700162 return false;
163 }
164
165 @Override
166 public Command receive(IOFSwitch sw, OFMessage msg,
167 FloodlightContext cntx) {
168 if (!(msg instanceof OFPacketIn)) {
169 return Command.CONTINUE;
170 }
171
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700172 Ethernet eth = IFloodlightProviderService.bcStore.
173 get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
Yuta HIGUCHIa507baf2014-08-22 13:42:40 -0700174 // FIXME losing port number precision
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700175 short inport = (short) cntx.getStorage()
176 .get(IFloodlightProviderService.CONTEXT_PI_INPORT);
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700177
Jonathan Harte37e4e22014-05-13 19:12:02 -0700178 Switch topologySwitch;
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700179 Port inPort;
180 try {
Yuta HIGUCHId92b10c2014-08-25 09:30:28 -0700181 mutableTopology.acquireReadLock();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700182 Dpid dpid = new Dpid(sw.getId());
Yuta HIGUCHIa507baf2014-08-22 13:42:40 -0700183 PortNumber p = PortNumber.uint16(inport);
Yuta HIGUCHId92b10c2014-08-25 09:30:28 -0700184 topologySwitch = mutableTopology.getSwitch(dpid);
185 inPort = mutableTopology.getPort(dpid, p);
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700186 } finally {
Yuta HIGUCHId92b10c2014-08-25 09:30:28 -0700187 mutableTopology.releaseReadLock();
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700188 }
189
Jonathan Harte37e4e22014-05-13 19:12:02 -0700190 if (topologySwitch == null || inPort == null) {
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700191 // We can't send packets for switches or ports that aren't in the
Jonathan Harte37e4e22014-05-13 19:12:02 -0700192 // topology yet
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700193 return Command.CONTINUE;
194 }
195
196 for (IPacketListener listener : listeners) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700197 listener.receive(topologySwitch, inPort, eth);
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700198 }
199
200 return Command.CONTINUE;
201 }
202
203 @Override
204 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
205 List<Class<? extends IFloodlightService>> services = new ArrayList<>();
206 services.add(IPacketService.class);
207 return services;
208 }
209
210 @Override
211 public Map<Class<? extends IFloodlightService>, IFloodlightService>
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700212 getServiceImpls() {
213
214 Map<Class<? extends IFloodlightService>, IFloodlightService> serviceImpls = new HashMap<>();
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700215 serviceImpls.put(IPacketService.class, this);
216 return serviceImpls;
217 }
218
219 @Override
220 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
221 List<Class<? extends IFloodlightService>> dependencies = new ArrayList<>();
222 dependencies.add(IFloodlightProviderService.class);
Jonathan Harte37e4e22014-05-13 19:12:02 -0700223 dependencies.add(ITopologyService.class);
Jonathan Harte6e63732014-04-16 14:29:49 -0700224 dependencies.add(IDatagridService.class);
225 dependencies.add(IFlowPusherService.class);
pingping-lin0426dee2014-08-27 15:03:17 -0700226 dependencies.add(IConfigInfoService.class);
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700227 return dependencies;
228 }
229
230 @Override
231 public void init(FloodlightModuleContext context)
232 throws FloodlightModuleException {
233 floodlightProvider =
234 context.getServiceImpl(IFloodlightProviderService.class);
Yuta HIGUCHId92b10c2014-08-25 09:30:28 -0700235 mutableTopology = context.getServiceImpl(ITopologyService.class)
Jonathan Harte37e4e22014-05-13 19:12:02 -0700236 .getTopology();
Jonathan Harte6e63732014-04-16 14:29:49 -0700237 datagrid = context.getServiceImpl(IDatagridService.class);
238 flowPusher = context.getServiceImpl(IFlowPusherService.class);
pingping-lin0426dee2014-08-27 15:03:17 -0700239 configService = context.getServiceImpl(IConfigInfoService.class);
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700240 }
241
242 @Override
243 public void startUp(FloodlightModuleContext context) {
244 floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
Jonathan Harte6e63732014-04-16 14:29:49 -0700245 packetOutEventChannel = datagrid.addListener(PACKET_OUT_CHANNEL_NAME,
246 packetOutEventHandler,
247 Long.class,
248 PacketOutNotification.class);
249 }
250
Jonathan Harte6e63732014-04-16 14:29:49 -0700251 private void sendPacketToSwitches(Multimap<Long, Short> outPorts,
252 byte[] packetData) {
253 for (Long dpid : outPorts.keySet()) {
Jonathan Harte6e63732014-04-16 14:29:49 -0700254 IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
255
256 if (sw == null) {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700257 log.warn("Switch {} not found when sending packet", dpid);
258 continue;
Jonathan Harte6e63732014-04-16 14:29:49 -0700259 }
260
Jonathan Harta213bce2014-08-11 15:44:07 -0700261 OFFactory factory = sw.getFactory();
262
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700263 List<OFAction> actions = new ArrayList<>();
264 for (Short port : outPorts.get(dpid)) {
265 actions.add(factory.actions().output(OFPort.of(port), Short.MAX_VALUE));
266 }
267
268 OFPacketOut po = factory.buildPacketOut()
269 .setData(packetData)
270 .setActions(actions)
271 .build();
272
Jonathan Hart5302b6c2014-08-13 15:57:59 -0700273 flowPusher.add(new Dpid(sw.getId()), po);
Jonathan Harte6e63732014-04-16 14:29:49 -0700274 }
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700275 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700276
Jonathan Hart1f75cae2014-04-09 17:24:09 -0700277}