blob: 89ce633f26106d3231261340f49da825e5a54d1c [file] [log] [blame]
Sangho Shin2f263692014-09-15 14:09:41 -07001package net.onrc.onos.apps.segmentrouting;
2
Sangho Shin9c0f4c32014-09-26 16:02:38 -07003import java.io.IOException;
Sangho Shin1aa93542014-09-22 09:49:44 -07004import java.net.Inet4Address;
5import java.net.InetAddress;
6import java.net.UnknownHostException;
Sangho Shin2f263692014-09-15 14:09:41 -07007import java.util.ArrayList;
8import java.util.Collection;
Srikanth Vavilapalli363f1dc2014-09-22 14:30:23 -07009import java.util.HashMap;
Sangho Shin2f263692014-09-15 14:09:41 -070010import java.util.Iterator;
11import java.util.List;
12import java.util.Map;
Sangho Shin61535402014-10-01 11:37:14 -070013import java.util.concurrent.ConcurrentLinkedQueue;
Sangho Shin11d4e0f2014-09-30 12:00:33 -070014import java.util.concurrent.ExecutionException;
Sangho Shin43cee112014-09-25 16:43:34 -070015import java.util.concurrent.ScheduledExecutorService;
16import java.util.concurrent.TimeUnit;
Sangho Shin11d4e0f2014-09-30 12:00:33 -070017import java.util.concurrent.TimeoutException;
Sangho Shin2f263692014-09-15 14:09:41 -070018
19import net.floodlightcontroller.core.IFloodlightProviderService;
Sangho Shin9c0f4c32014-09-26 16:02:38 -070020import net.floodlightcontroller.core.IOF13Switch;
Sangho Shin0df01982014-09-25 17:11:18 -070021import net.floodlightcontroller.core.IOF13Switch.NeighborSet;
Sangho Shin11d4e0f2014-09-30 12:00:33 -070022import net.floodlightcontroller.core.internal.OFBarrierReplyFuture;
Sangho Shin2f263692014-09-15 14:09:41 -070023import net.floodlightcontroller.core.module.FloodlightModuleContext;
24import net.floodlightcontroller.core.module.FloodlightModuleException;
25import net.floodlightcontroller.core.module.IFloodlightModule;
26import net.floodlightcontroller.core.module.IFloodlightService;
Sangho Shin43cee112014-09-25 16:43:34 -070027import net.floodlightcontroller.core.util.SingletonTask;
28import net.floodlightcontroller.threadpool.IThreadPoolService;
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070029import net.onrc.onos.api.packet.IPacketListener;
Sangho Shin2f263692014-09-15 14:09:41 -070030import net.onrc.onos.api.packet.IPacketService;
31import net.onrc.onos.core.flowprogrammer.IFlowPusherService;
32import net.onrc.onos.core.main.config.IConfigInfoService;
Sangho Shin43cee112014-09-25 16:43:34 -070033import net.onrc.onos.core.matchaction.MatchAction;
34import net.onrc.onos.core.matchaction.MatchActionId;
35import net.onrc.onos.core.matchaction.MatchActionOperationEntry;
36import net.onrc.onos.core.matchaction.action.Action;
37import net.onrc.onos.core.matchaction.action.CopyTtlInAction;
38import net.onrc.onos.core.matchaction.action.CopyTtlOutAction;
39import net.onrc.onos.core.matchaction.action.DecMplsTtlAction;
40import net.onrc.onos.core.matchaction.action.DecNwTtlAction;
41import net.onrc.onos.core.matchaction.action.GroupAction;
42import net.onrc.onos.core.matchaction.action.PopMplsAction;
43import net.onrc.onos.core.matchaction.action.PushMplsAction;
44import net.onrc.onos.core.matchaction.action.SetMplsIdAction;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -070045import net.onrc.onos.core.matchaction.match.Ipv4Match;
Sangho Shin43cee112014-09-25 16:43:34 -070046import net.onrc.onos.core.matchaction.match.Match;
47import net.onrc.onos.core.matchaction.match.MplsMatch;
Sangho Shin2f263692014-09-15 14:09:41 -070048import net.onrc.onos.core.packet.ARP;
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070049import net.onrc.onos.core.packet.Ethernet;
50import net.onrc.onos.core.packet.IPv4;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070051import net.onrc.onos.core.topology.ITopologyListener;
Sangho Shin1aa93542014-09-22 09:49:44 -070052import net.onrc.onos.core.topology.ITopologyService;
Sangho Shinc8d2f592014-09-30 16:53:57 -070053import net.onrc.onos.core.topology.LinkData;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070054import net.onrc.onos.core.topology.MutableTopology;
Sangho Shineb083032014-09-22 16:11:34 -070055import net.onrc.onos.core.topology.Port;
Sangho Shinc8d2f592014-09-30 16:53:57 -070056import net.onrc.onos.core.topology.PortData;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070057import net.onrc.onos.core.topology.Switch;
Sangho Shin1aa93542014-09-22 09:49:44 -070058import net.onrc.onos.core.topology.TopologyEvents;
Srikanth Vavilapalli363f1dc2014-09-22 14:30:23 -070059import net.onrc.onos.core.util.Dpid;
Sangho Shin43cee112014-09-25 16:43:34 -070060import net.onrc.onos.core.util.IPv4Net;
61import net.onrc.onos.core.util.SwitchPort;
Sangho Shin2f263692014-09-15 14:09:41 -070062
Sangho Shin43cee112014-09-25 16:43:34 -070063import org.json.JSONArray;
64import org.json.JSONException;
Saurav Dasbc594a42014-09-25 20:13:50 -070065import org.projectfloodlight.openflow.types.EthType;
Sangho Shin2f263692014-09-15 14:09:41 -070066import org.projectfloodlight.openflow.types.IPv4Address;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070067import org.projectfloodlight.openflow.util.HexString;
Sangho Shin2f263692014-09-15 14:09:41 -070068import org.slf4j.Logger;
69import org.slf4j.LoggerFactory;
70
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070071public class SegmentRoutingManager implements IFloodlightModule,
Sangho Shinac5ee2b2014-09-28 21:27:20 -070072 ITopologyListener, IPacketListener {
Sangho Shin2f263692014-09-15 14:09:41 -070073
74 private static final Logger log = LoggerFactory
75 .getLogger(SegmentRoutingManager.class);
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070076 private ITopologyService topologyService;
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070077 private IPacketService packetService;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070078 private MutableTopology mutableTopology;
Sangho Shin61535402014-10-01 11:37:14 -070079 private ConcurrentLinkedQueue<IPv4> ipPacketQueue;
Sangho Shin2f263692014-09-15 14:09:41 -070080
81 private List<ArpEntry> arpEntries;
Sangho Shineb083032014-09-22 16:11:34 -070082 private ArpHandler arpHandler;
83 private GenericIpHandler ipHandler;
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070084 private IcmpHandler icmpHandler;
Sangho Shin43cee112014-09-25 16:43:34 -070085 private IThreadPoolService threadPool;
86 private SingletonTask discoveryTask;
Sangho Shin9c0f4c32014-09-26 16:02:38 -070087 private IFloodlightProviderService floodlightProvider;
Sangho Shin2f263692014-09-15 14:09:41 -070088
89 @Override
90 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
91 // TODO Auto-generated method stub
92 return null;
93 }
94
95 @Override
96 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
97 // TODO Auto-generated method stub
98 return null;
99 }
100
101 @Override
102 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
103 Collection<Class<? extends IFloodlightService>> l = new ArrayList<Class<? extends IFloodlightService>>();
104
105 l.add(IFloodlightProviderService.class);
106 l.add(IConfigInfoService.class);
107 l.add(ITopologyService.class);
108 l.add(IPacketService.class);
109 l.add(IFlowPusherService.class);
110 l.add(ITopologyService.class);
111
112 return l;
113
114 }
115
116 @Override
117 public void init(FloodlightModuleContext context) throws FloodlightModuleException {
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700118 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Sangho Shineb083032014-09-22 16:11:34 -0700119 arpHandler = new ArpHandler(context, this);
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700120 icmpHandler = new IcmpHandler(context, this);
Sangho Shineb083032014-09-22 16:11:34 -0700121 ipHandler = new GenericIpHandler(context, this);
Sangho Shin2f263692014-09-15 14:09:41 -0700122 arpEntries = new ArrayList<ArpEntry>();
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700123 topologyService = context.getServiceImpl(ITopologyService.class);
Sangho Shin43cee112014-09-25 16:43:34 -0700124 threadPool = context.getServiceImpl(IThreadPoolService.class);
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700125 mutableTopology = topologyService.getTopology();
126 topologyService.addListener(this, false);
Sangho Shin61535402014-10-01 11:37:14 -0700127 ipPacketQueue = new ConcurrentLinkedQueue<IPv4>();
Sangho Shin2f263692014-09-15 14:09:41 -0700128
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700129 this.packetService = context.getServiceImpl(IPacketService.class);
130 packetService.registerPacketListener(this);
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700131
Sangho Shin2f263692014-09-15 14:09:41 -0700132 }
133
134 @Override
135 public void startUp(FloodlightModuleContext context) throws FloodlightModuleException {
Sangho Shinc8d2f592014-09-30 16:53:57 -0700136 ScheduledExecutorService ses = threadPool.getScheduledExecutor();
Sangho Shin2f263692014-09-15 14:09:41 -0700137
Sangho Shinc8d2f592014-09-30 16:53:57 -0700138 discoveryTask = new SingletonTask(ses, new Runnable() {
139 @Override
140 public void run() {
141 populateEcmpRoutingRules();
142 }
143 });
Sangho Shin2f263692014-09-15 14:09:41 -0700144 }
145
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700146 @Override
147 public void receive(Switch sw, Port inPort, Ethernet payload) {
148 if (payload.getEtherType() == Ethernet.TYPE_ARP)
149 arpHandler.processPacketIn(sw, inPort, payload);
150 if (payload.getEtherType() == Ethernet.TYPE_IPV4) {
Sangho Shin463bee52014-09-29 15:14:43 -0700151 addPacket((IPv4)payload.getPayload());
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700152 if (((IPv4)payload.getPayload()).getProtocol() == IPv4.PROTOCOL_ICMP)
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700153 icmpHandler.processPacketIn(sw, inPort, payload);
154 else
155 ipHandler.processPacketIn(sw, inPort, payload);
156 }
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700157 else {
158 log.debug("{}", payload.toString());
159 }
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700160 }
Sangho Shin2f263692014-09-15 14:09:41 -0700161 /**
162 * Update ARP Cache using ARP packets
163 * It is used to set destination MAC address to forward packets to known hosts.
164 * But, it will be replace with Host information of Topology service later.
165 *
166 * @param arp APR packets to use for updating ARP entries
167 */
168 public void updateArpCache(ARP arp) {
169
170 ArpEntry arpEntry = new ArpEntry(arp.getSenderHardwareAddress(), arp.getSenderProtocolAddress());
171 // TODO: Need to check the duplication
172 arpEntries.add(arpEntry);
173 }
174
175 /**
176 * Get MAC address to known hosts
177 *
178 * @param destinationAddress IP address to get MAC address
179 * @return MAC Address to given IP address
180 */
181 public byte[] getMacAddressFromIpAddress(int destinationAddress) {
182
183 // Can't we get the host IP address from the TopologyService ??
184
185 Iterator<ArpEntry> iterator = arpEntries.iterator();
186
187 IPv4Address ipAddress = IPv4Address.of(destinationAddress);
188 byte[] ipAddressInByte = ipAddress.getBytes();
189
190 while (iterator.hasNext() ) {
191 ArpEntry arpEntry = iterator.next();
192 byte[] address = arpEntry.targetIpAddress;
193
194 IPv4Address a = IPv4Address.of(address);
195 IPv4Address b = IPv4Address.of(ipAddressInByte);
196
197 if ( a.equals(b)) {
198 log.debug("Found an arp entry");
199 return arpEntry.targetMacAddress;
200 }
201 }
202
203 return null;
204 }
205
Sangho Shineb083032014-09-22 16:11:34 -0700206 /**
207 * Send an ARP request via ArpHandler
208 * @param destinationAddress
209 * @param sw
210 * @param inPort
211 *
212 */
213 public void sendArpRequest(Switch sw, int destinationAddress, Port inPort) {
214 arpHandler.sendArpRequest(sw, destinationAddress, inPort);
215 }
Sangho Shin2f263692014-09-15 14:09:41 -0700216
217 /**
218 * Temporary class to to keep ARP entry
219 *
220 */
221 private class ArpEntry {
222
223 byte[] targetMacAddress;
224 byte[] targetIpAddress;
225
226 private ArpEntry(byte[] macAddress, byte[] ipAddress) {
227 this.targetMacAddress = macAddress;
228 this.targetIpAddress = ipAddress;
229 }
Sangho Shin2f263692014-09-15 14:09:41 -0700230 }
Sangho Shineb083032014-09-22 16:11:34 -0700231
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700232 /**
233 * Topology events that have been generated.
234 *
235 * @param topologyEvents the generated Topology Events
236 * @see TopologyEvents
237 */
238 public void topologyEvents(TopologyEvents topologyEvents)
239 {
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700240
241 Collection<LinkData> linkEntriesAdded =
242 topologyEvents.getAddedLinkDataEntries();
243 if (!linkEntriesAdded.isEmpty()) {
244 processLinkAdd(linkEntriesAdded);
245 }
246
247 Collection<PortData> PortEntriesAdded =
248 topologyEvents.getAddedPortDataEntries();
249 if (linkEntriesAdded != null) {
250 processPortAdd(PortEntriesAdded);
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700251 }
Sangho Shinc8d2f592014-09-30 16:53:57 -0700252
253 Collection<PortData> portEntries =
254 topologyEvents.getRemovedPortDataEntries();
255 if (!portEntries.isEmpty()) {
Sangho Shin61535402014-10-01 11:37:14 -0700256 processPortRemoval(portEntries);
Sangho Shinc8d2f592014-09-30 16:53:57 -0700257 }
258
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700259 Collection<LinkData> linkEntriesRemoved =
Sangho Shinc8d2f592014-09-30 16:53:57 -0700260 topologyEvents.getRemovedLinkDataEntries();
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700261 if (!linkEntriesRemoved.isEmpty()) {
262 processLinkRemoval(linkEntriesRemoved);
Sangho Shin61535402014-10-01 11:37:14 -0700263 }
264 }
Sangho Shinc8d2f592014-09-30 16:53:57 -0700265
Sangho Shin61535402014-10-01 11:37:14 -0700266 /**
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700267 * Report ports newly added to driver
268 *
269 * @param portEntries
270 */
271 private void processPortAdd(Collection<PortData> portEntries) {
272 //TODO: do we need to add ports slowly?
273 for (PortData port: portEntries) {
274 Dpid dpid = port.getDpid();
275 int portNo = (int) port.getPortNumber().value();
276
277 IOF13Switch sw13 = (IOF13Switch)floodlightProvider.getMasterSwitch(
278 getSwId(port.getDpid().toString()));
279 //sw13.addPort(portNo);
280 log.debug("Add port {} to switch {}", portNo, dpid.toString());
281 }
282 }
283
284 /**
285 * Reports ports of new links to driver and recalculate ECMP SPG
286 *
287 * @param linkEntries
288 */
289 private void processLinkAdd(Collection<LinkData> linkEntries) {
290
291 // TODO: How to determine this link was broken before and back now
292 // If so, we need to ad the link slowly...
293 // Or, just add any new or restored link slowly ???
294 for (LinkData link: linkEntries) {
295 SwitchPort srcPort = link.getSrc();
296 SwitchPort dstPort = link.getDst();
297
298 IOF13Switch sw13src = (IOF13Switch)floodlightProvider.getMasterSwitch(
299 getSwId(srcPort.getDpid().toString()));
300 IOF13Switch sw13dst = (IOF13Switch)floodlightProvider.getMasterSwitch(
301 getSwId(srcPort.getDpid().toString()));
302 //sw13src.addPort(srcPort);
303 //sw13dst.addPort(dstPort);
304
305 }
306 discoveryTask.reschedule(1, TimeUnit.SECONDS);
307 }
308
309 /**
Sangho Shin61535402014-10-01 11:37:14 -0700310 * Check if all links are gone b/w the two switches.
311 * If all links are gone, then we need to recalculate the path.
312 * Otherwise, just report link failure to the driver.
313 *
314 * @param linkEntries
315 */
316 private void processLinkRemoval(Collection<LinkData> linkEntries) {
317 for (LinkData link: linkEntries) {
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700318 SwitchPort srcPort = link.getSrc();
319 SwitchPort dstPort = link.getDst();
Sangho Shinc8d2f592014-09-30 16:53:57 -0700320
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700321 IOF13Switch sw13src = (IOF13Switch)floodlightProvider.getMasterSwitch(
322 getSwId(srcPort.getDpid().toString()));
323 IOF13Switch sw13dst = (IOF13Switch)floodlightProvider.getMasterSwitch(
324 getSwId(srcPort.getDpid().toString()));
325 //sw13src.addPort(srcPort);
326 //sw13dst.addPort(dstPort);
327
328 Switch srcSwitch = mutableTopology.getSwitch(srcPort.getDpid());
329 if (srcSwitch.getLinkToNeighbor(dstPort.getDpid()) == null) {
Sangho Shin61535402014-10-01 11:37:14 -0700330 discoveryTask.reschedule(1, TimeUnit.SECONDS);
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700331 log.debug("All links are gone b/w {} and {}",srcPort.getDpid(),
332 srcPort.getDpid());
Sangho Shinc8d2f592014-09-30 16:53:57 -0700333 }
334 }
Sangho Shin61535402014-10-01 11:37:14 -0700335 }
Sangho Shinc8d2f592014-09-30 16:53:57 -0700336
Sangho Shin61535402014-10-01 11:37:14 -0700337 /**
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700338 * report ports removed to the driver immediately
Sangho Shin61535402014-10-01 11:37:14 -0700339 *
340 * @param portEntries
341 */
342 private void processPortRemoval(Collection<PortData> portEntries) {
343 for (PortData port: portEntries) {
344 Dpid dpid = port.getDpid();
345 int portNo = (int) port.getPortNumber().value();
346
347 IOF13Switch sw13 = (IOF13Switch)floodlightProvider.getMasterSwitch(
348 getSwId(port.getDpid().toString()));
349 //sw13.removePort(portNo);
350 log.debug("Remove port {} from switch {}", portNo, dpid.toString());
351 }
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700352 }
Sangho Shin1aa93542014-09-22 09:49:44 -0700353
354 /**
Sangho Shin43cee112014-09-25 16:43:34 -0700355 * Populate routing rules walking through the ECMP shortest paths
Sangho Shin1aa93542014-09-22 09:49:44 -0700356 *
Sangho Shin1aa93542014-09-22 09:49:44 -0700357 */
Sangho Shin43cee112014-09-25 16:43:34 -0700358 private void populateEcmpRoutingRules() {
Sangho Shin1aa93542014-09-22 09:49:44 -0700359
Sangho Shin43cee112014-09-25 16:43:34 -0700360 Iterable<Switch> switches= mutableTopology.getSwitches();
361 for (Switch sw : switches) {
362 ECMPShortestPathGraph ecmpSPG = new ECMPShortestPathGraph(sw);
363 log.debug("ECMPShortestPathGraph is computed for switch {}",
364 HexString.toHexString(sw.getDpid().value()));
Sangho Shin1aa93542014-09-22 09:49:44 -0700365
Sangho Shin43cee112014-09-25 16:43:34 -0700366 HashMap<Integer, HashMap<Switch,ArrayList<ArrayList<Dpid>>>> switchVia =
367 ecmpSPG.getAllLearnedSwitchesAndVia();
368 for (Integer itrIdx: switchVia.keySet()){
369 log.debug("ECMPShortestPathGraph:Switches learned in "
370 + "Iteration{} from switch {}:",
371 itrIdx,
372 HexString.toHexString(sw.getDpid().value()));
373 HashMap<Switch, ArrayList<ArrayList<Dpid>>> swViaMap =
374 switchVia.get(itrIdx);
375 for (Switch targetSw: swViaMap.keySet()){
376 log.debug("ECMPShortestPathGraph:****switch {} via:",
377 HexString.toHexString(targetSw.getDpid().value()));
378 String destSw = sw.getDpid().toString();
379 List<String> fwdToSw = new ArrayList<String>();
380
381 int i=0;
382 for (ArrayList<Dpid> via:swViaMap.get(targetSw)){
383 log.debug("ECMPShortestPathGraph:******{}) {}",++i,via);
384 if (via.isEmpty()) {
385 fwdToSw.add(destSw);
386 }
387 else {
388 fwdToSw.add(via.get(0).toString());
389 }
390 }
391 setRoutingRule(targetSw, destSw, fwdToSw);
392 }
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700393
394 // Send Barrier Message and make sure all rules are set
395 // before we set the rules to next routers
396 IOF13Switch sw13 = (IOF13Switch)floodlightProvider.getMasterSwitch(
397 getSwId(sw.getDpid().toString()));
398 try {
399 OFBarrierReplyFuture replyFuture = sw13.sendBarrier();
400 replyFuture.get(10, TimeUnit.SECONDS);
401 } catch (IOException e) {
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700402 e.printStackTrace();
403 }
404 catch (InterruptedException | ExecutionException | TimeoutException e) {
405 log.error("Barrier message not received for sw: {}", sw.getDpid());
406 e.printStackTrace();
407 }
Sangho Shineb083032014-09-22 16:11:34 -0700408 }
409 }
Sangho Shin43cee112014-09-25 16:43:34 -0700410 }
411
412 /**
413 *
414 * Set routing rules in targetSw
415 * {forward packets to fwdToSw switches in order to send packets to destSw}
416 * - If the target switch is an edge router and final destnation switch is also
417 * an edge router, then set IP forwarding rules to subnets
418 * - If only the target switch is an edge router, then set IP forwarding rule to
419 * the transit router loopback IP address
420 * - If the target is a transit router, then just set the MPLS forwarding rule
421 *
422 * @param targetSw Switch to set the rules
423 * @param destSw Final destination switches
424 * @param fwdToSw next hop switches
425 */
426 private void setRoutingRule(Switch targetSw, String destSw, List<String> fwdToSw) {
427
428
429 if (fwdToSw.isEmpty()) {
430 fwdToSw.add(destSw);
431 }
432
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700433 // if both target SW and dest SW are an edge router, then set IP table
Sangho Shin43cee112014-09-25 16:43:34 -0700434 if (IsEdgeRouter(targetSw.getDpid().toString()) &&
435 IsEdgeRouter(destSw)) {
436 // We assume that there is at least one transit router b/w edge routers
437 Switch destSwitch = mutableTopology.getSwitch(new Dpid(destSw));
438 String subnets = destSwitch.getStringAttribute("subnets");
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700439 setIpTableRouterSubnet(targetSw, subnets, getMplsLabel(destSw)
440 ,fwdToSw);
Sangho Shin43cee112014-09-25 16:43:34 -0700441
Sangho Shin43cee112014-09-25 16:43:34 -0700442 String routerIp = destSwitch.getStringAttribute("routerIp");
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700443 setIpTableRouter(targetSw, routerIp, getMplsLabel(destSw), fwdToSw, null);
Sangho Shin43cee112014-09-25 16:43:34 -0700444 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700445 // Only if the target switch is the edge router, then set the IP rules
Sangho Shin43cee112014-09-25 16:43:34 -0700446 else if (IsEdgeRouter(targetSw.getDpid().toString())) {
447 // We assume that there is at least one transit router b/w edge routers
448 Switch destSwitch = mutableTopology.getSwitch(new Dpid(destSw));
449 String routerIp = destSwitch.getStringAttribute("routerIp");
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700450 setIpTableRouter(targetSw, routerIp, getMplsLabel(destSw), fwdToSw, null);
Sangho Shin43cee112014-09-25 16:43:34 -0700451 }
452 // if it is a transit router, then set rules in the MPLS table
453 else {
454 setMplsTable(targetSw, getMplsLabel(destSw), fwdToSw);
455 }
456
457 }
458
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700459 private void setIpTableRouterSubnet(Switch targetSw, String subnets,
460 String mplsLabel, List<String> fwdToSw) {
461
462 Collection <MatchActionOperationEntry> entries =
463 new ArrayList<MatchActionOperationEntry>();
464
465 try {
466 JSONArray arry = new JSONArray(subnets);
467 for (int i = 0; i < arry.length(); i++) {
468 String subnetIp = (String) arry.getJSONObject(i).get("subnetIp");
469 setIpTableRouter(targetSw, subnetIp, mplsLabel, fwdToSw, entries);
470 }
471 } catch (JSONException e) {
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700472 e.printStackTrace();
473 }
474
475 if (!entries.isEmpty()) {
476 IOF13Switch sw13 = (IOF13Switch)floodlightProvider.getMasterSwitch(
477 getSwId(targetSw.getDpid().toString()));
478
479 try {
480 sw13.pushFlows(entries);
481 } catch (IOException e) {
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700482 e.printStackTrace();
483 }
484 }
485
486 }
487
Sangho Shin43cee112014-09-25 16:43:34 -0700488 /**
489 * Check if the switch is the edge router or not
490 * If any subnet information is defined in the config file, the we assume
491 * it is an edge router
492 *
493 * @param dpid Dpid of the switch to check
494 * @return true if it is an edge router, otherwise false
495 */
496 private boolean IsEdgeRouter(String dpid) {
497
498 for (Switch sw: mutableTopology.getSwitches()) {
499 String dpidStr = sw.getDpid().toString();
500 if (dpid.equals(dpidStr)) {
501 String subnetInfo = sw.getStringAttribute("subnets");
502 if (subnetInfo == null || subnetInfo.equals("[]")) {
503 return false;
504 }
505 else
506 return true;
507 }
508 }
509
510 return false;
511 }
512
513 /**
514 * Set IP forwarding rule
515 * - If the destination is the next hop, then do not push MPLS,
516 * just decrease the NW TTL
517 * - Otherwise, push MPLS label and set the MPLS ID
518 *
519 * @param sw target switch to set rules
520 * @param subnetIp Match IP address
521 * @param mplsLabel MPLS label of final destination router
522 * @param fwdToSws next hop routers
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700523 * @param entries
Sangho Shin43cee112014-09-25 16:43:34 -0700524 */
525 private void setIpTableRouter(Switch sw, String subnetIp, String mplsLabel,
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700526 List<String> fwdToSws, Collection<MatchActionOperationEntry> entries) {
Sangho Shin43cee112014-09-25 16:43:34 -0700527
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700528 Ipv4Match ipMatch = new Ipv4Match(subnetIp);
Sangho Shin43cee112014-09-25 16:43:34 -0700529 List<Action> actions = new ArrayList<>();
530
531 // If destination SW is the same as the fwd SW, then do not push MPLS label
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700532
533 if (fwdToSws.size() > 1) {
Sangho Shin43cee112014-09-25 16:43:34 -0700534 PushMplsAction pushMplsAction = new PushMplsAction();
535 SetMplsIdAction setIdAction = new SetMplsIdAction(Integer.parseInt(mplsLabel));
536 CopyTtlOutAction copyTtlOutAction = new CopyTtlOutAction();
Sangho Shin463bee52014-09-29 15:14:43 -0700537 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
Sangho Shin43cee112014-09-25 16:43:34 -0700538
539 actions.add(pushMplsAction);
Sangho Shin43cee112014-09-25 16:43:34 -0700540 actions.add(copyTtlOutAction);
Sangho Shin463bee52014-09-29 15:14:43 -0700541 actions.add(decMplsTtlAction);
542 actions.add(setIdAction);
Sangho Shin43cee112014-09-25 16:43:34 -0700543 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700544 else {
545 String fwdToSw = fwdToSws.get(0);
546 if (getMplsLabel(fwdToSw).equals(mplsLabel)) {
547 DecNwTtlAction decTtlAction = new DecNwTtlAction(1);
548 actions.add(decTtlAction);
549 }
550 else {
551 PushMplsAction pushMplsAction = new PushMplsAction();
552 SetMplsIdAction setIdAction = new SetMplsIdAction(Integer.parseInt(mplsLabel));
553 CopyTtlOutAction copyTtlOutAction = new CopyTtlOutAction();
Sangho Shin463bee52014-09-29 15:14:43 -0700554 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700555
556 actions.add(pushMplsAction);
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700557 actions.add(copyTtlOutAction);
Sangho Shin463bee52014-09-29 15:14:43 -0700558 actions.add(decMplsTtlAction);
559 actions.add(setIdAction);
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700560 }
561 }
Sangho Shin43cee112014-09-25 16:43:34 -0700562
563 GroupAction groupAction = new GroupAction();
564
565 for (String fwdSw : fwdToSws) {
566 groupAction.addSwitch(new Dpid(fwdSw));
567 }
568 actions.add(groupAction);
569
Sangho Shinc8d2f592014-09-30 16:53:57 -0700570 // TODO: Mactch Action Id should be set correctly
Sangho Shin43cee112014-09-25 16:43:34 -0700571 MatchAction matchAction = new MatchAction(new MatchActionId(0),
572 new SwitchPort((long)0,(short)0), ipMatch, actions);
573
574 MatchActionOperationEntry maEntry =
575 new MatchActionOperationEntry(
576 net.onrc.onos.core.matchaction.MatchActionOperations.Operator.ADD,
577 matchAction);
578
Sangho Shin463bee52014-09-29 15:14:43 -0700579 IOF13Switch sw13 = (IOF13Switch)floodlightProvider.getMasterSwitch(
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700580 getSwId(sw.getDpid().toString()));
581
582 try {
583 printMatchActionOperationEntry(sw, maEntry);
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700584 if (entries != null)
585 entries.add(maEntry);
586 else
587 sw13.pushFlow(maEntry);
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700588 } catch (IOException e) {
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700589 e.printStackTrace();
590 }
591
Sangho Shin43cee112014-09-25 16:43:34 -0700592 }
593
594
Sangho Shinac5ee2b2014-09-28 21:27:20 -0700595 /**
596 * Convert a string DPID to its Switch Id (integer)
597 *
598 * @param dpid
599 * @return
600 */
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700601 private long getSwId(String dpid) {
602
603 long swId = 0;
604
605 String swIdStr = dpid.substring(dpid.lastIndexOf(":")+1);
606 if (swIdStr != null)
607 swId = Integer.parseInt(swIdStr);
608
609 return swId;
610 }
611
Sangho Shin43cee112014-09-25 16:43:34 -0700612 /**
613 * Set MPLS forwarding rules to MPLS table
614 * - If the destination is the same as the next hop to forward packets
615 * then, pop the MPLS label according to PHP rule
616 * - Otherwise, just forward packets to next hops using Group action
617 *
618 * @param sw Switch to set the rules
619 * @param mplsLabel destination MPLS label
620 * @param fwdSws next hop switches
621 */
622 private void setMplsTable(Switch sw, String mplsLabel, List<String> fwdSws) {
Sangho Shin463bee52014-09-29 15:14:43 -0700623
Sangho Shin43cee112014-09-25 16:43:34 -0700624 MplsMatch mplsMatch = new MplsMatch(Integer.parseInt(mplsLabel));
625
626 List<Action> actions = new ArrayList<Action>();
Sangho Shin43cee112014-09-25 16:43:34 -0700627
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700628 // If the destination is the same as the next hop, then pop MPLS
Sangho Shinc8d2f592014-09-30 16:53:57 -0700629 // Otherwise, just decrease the MPLS TTL.
Sangho Shin463bee52014-09-29 15:14:43 -0700630 if (fwdSws.size() == 1) {
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700631 String fwdMplsId = getMplsLabel(fwdSws.get(0));
632 if (fwdMplsId.equals(mplsLabel)) {
633 String fwdSw = fwdSws.get(0);
634 if (mplsLabel.equals(getMplsLabel(fwdSw))) {
635 PopMplsAction popAction = new PopMplsAction(EthType.IPv4);
636 CopyTtlInAction copyTtlInAction = new CopyTtlInAction();
Sangho Shin463bee52014-09-29 15:14:43 -0700637 DecNwTtlAction decNwTtlAction = new DecNwTtlAction(1);
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700638
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700639 actions.add(copyTtlInAction);
Sangho Shin463bee52014-09-29 15:14:43 -0700640 actions.add(popAction);
641 actions.add(decNwTtlAction);
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700642 }
643 }
Sangho Shinc8d2f592014-09-30 16:53:57 -0700644 else {
645 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
646 actions.add(decMplsTtlAction);
647 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700648 }
Sangho Shin43cee112014-09-25 16:43:34 -0700649 GroupAction groupAction = new GroupAction();
650 for (String fwdSw: fwdSws)
651 groupAction.addSwitch(new Dpid(fwdSw));
652 actions.add(groupAction);
653
654 MatchAction matchAction = new MatchAction(new MatchActionId(0),
655 new SwitchPort((long)0,(short)0), mplsMatch, actions);
656
657 MatchActionOperationEntry maEntry =
658 new MatchActionOperationEntry(
659 net.onrc.onos.core.matchaction.MatchActionOperations.Operator.ADD,
660 matchAction);
661
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700662 IOF13Switch sw13 = (IOF13Switch)floodlightProvider.getMasterSwitch(
663 getSwId(sw.getDpid().toString()));
664
665 try {
666 printMatchActionOperationEntry(sw, maEntry);
667 sw13.pushFlow(maEntry);
668 } catch (IOException e) {
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700669 e.printStackTrace();
670 }
671
Sangho Shin43cee112014-09-25 16:43:34 -0700672 }
673
674
675 /**
676 * Debugging function to print out the Match Action Entry
677 *
678 * @param maEntry
679 */
Sangho Shinac5ee2b2014-09-28 21:27:20 -0700680 private void printMatchActionOperationEntry(Switch sw,
681 MatchActionOperationEntry maEntry) {
Sangho Shin43cee112014-09-25 16:43:34 -0700682
Sangho Shin0df01982014-09-25 17:11:18 -0700683 StringBuilder logStr = new StringBuilder("In switch " + sw.getDpid() + ", ");
Sangho Shin43cee112014-09-25 16:43:34 -0700684
685 MatchAction ma = maEntry.getTarget();
686 Match m = ma.getMatch();
687 List<Action> actions = ma.getActions();
688
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700689 if (m instanceof Ipv4Match) {
Sangho Shin43cee112014-09-25 16:43:34 -0700690 logStr.append("If the IP matches with ");
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700691 IPv4Net ip = ((Ipv4Match) m).getDestination();
Sangho Shin43cee112014-09-25 16:43:34 -0700692 logStr.append(ip.toString());
693 logStr.append(" then ");
694 }
695 else if (m instanceof MplsMatch) {
696 logStr.append("If the MPLS label matches with ");
697 int mplsLabel = ((MplsMatch) m).getMplsLabel();
698 logStr.append(mplsLabel);
699 logStr.append(" then ");
700 }
701
702 logStr.append(" do { ");
703 for (Action action: actions) {
704 if (action instanceof CopyTtlInAction) {
705 logStr.append("copy ttl In, ");
706 }
707 else if (action instanceof CopyTtlOutAction) {
708 logStr.append("copy ttl Out, ");
709 }
710 else if (action instanceof DecMplsTtlAction) {
711 logStr.append("Dec MPLS TTL , ");
712 }
713 else if (action instanceof GroupAction) {
714 logStr.append("Forward packet to < ");
Sangho Shin0df01982014-09-25 17:11:18 -0700715 NeighborSet dpids = ((GroupAction)action).getDpids();
716 logStr.append(dpids.toString() + ",");
717
Sangho Shin43cee112014-09-25 16:43:34 -0700718 }
719 else if (action instanceof PopMplsAction) {
720 logStr.append("Pop MPLS label, ");
721 }
722 else if (action instanceof PushMplsAction) {
723 logStr.append("Push MPLS label, ");
724 }
725 else if (action instanceof SetMplsIdAction) {
726 int id = ((SetMplsIdAction)action).getMplsId();
727 logStr.append("Set MPLS ID as " + id + ", ");
728
729 }
730 }
731
732 log.debug(logStr.toString());
733
Sangho Shineb083032014-09-22 16:11:34 -0700734 }
735
736 /**
737 * Get MPLS label reading the config file
738 *
739 * @param dipid DPID of the switch
740 * @return MPLS label for the switch
741 */
742
Sangho Shin43cee112014-09-25 16:43:34 -0700743 private String getMplsLabel(String dpid) {
Sangho Shineb083032014-09-22 16:11:34 -0700744
745 String mplsLabel = null;
746 for (Switch sw: mutableTopology.getSwitches()) {
Sangho Shin43cee112014-09-25 16:43:34 -0700747 String dpidStr = sw.getDpid().toString();
748 if (dpid.equals(dpidStr)) {
Sangho Shineb083032014-09-22 16:11:34 -0700749 mplsLabel = sw.getStringAttribute("nodeSid");
750 break;
Sangho Shin1aa93542014-09-22 09:49:44 -0700751 }
752 }
753
Sangho Shineb083032014-09-22 16:11:34 -0700754 return mplsLabel;
Sangho Shin1aa93542014-09-22 09:49:44 -0700755 }
756
Sangho Shineb083032014-09-22 16:11:34 -0700757
758
759 /**
Sangho Shin1aa93542014-09-22 09:49:44 -0700760 * The function checks if given IP matches to the given subnet mask
761 *
762 * @param addr - subnet address to match
763 * @param addr1 - IP address to check
764 * @return true if the IP address matches to the subnet, otherwise false
765 */
Sangho Shin1aa93542014-09-22 09:49:44 -0700766 public boolean netMatch(String addr, String addr1){ //addr is subnet address and addr1 is ip address. Function will return true, if addr1 is within addr(subnet)
767
768 String[] parts = addr.split("/");
769 String ip = parts[0];
770 int prefix;
771
772 if (parts.length < 2) {
773 prefix = 0;
774 } else {
775 prefix = Integer.parseInt(parts[1]);
776 }
777
778 Inet4Address a =null;
779 Inet4Address a1 =null;
780 try {
781 a = (Inet4Address) InetAddress.getByName(ip);
782 a1 = (Inet4Address) InetAddress.getByName(addr1);
783 } catch (UnknownHostException e){}
784
785 byte[] b = a.getAddress();
786 int ipInt = ((b[0] & 0xFF) << 24) |
787 ((b[1] & 0xFF) << 16) |
788 ((b[2] & 0xFF) << 8) |
789 ((b[3] & 0xFF) << 0);
790
791 byte[] b1 = a1.getAddress();
792 int ipInt1 = ((b1[0] & 0xFF) << 24) |
793 ((b1[1] & 0xFF) << 16) |
794 ((b1[2] & 0xFF) << 8) |
795 ((b1[3] & 0xFF) << 0);
796
797 int mask = ~((1 << (32 - prefix)) - 1);
798
799 if ((ipInt & mask) == (ipInt1 & mask)) {
800 return true;
801 }
802 else {
803 return false;
804 }
805 }
Sangho Shineb083032014-09-22 16:11:34 -0700806
Sangho Shinac5ee2b2014-09-28 21:27:20 -0700807 /**
808 * Add a routing rule for the host
809 *
810 * @param sw - Switch to add the rule
811 * @param hostIpAddress Destination host IP address
812 * @param hostMacAddress Destination host MAC address
813 */
Sangho Shineb083032014-09-22 16:11:34 -0700814 public void addRouteToHost(Switch sw, int hostIpAddress, byte[] hostMacAddress) {
815 ipHandler.addRouteToHost(sw, hostIpAddress, hostMacAddress);
816
817 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700818
Sangho Shin463bee52014-09-29 15:14:43 -0700819 /**
820 * Add IP packet to a buffer queue
821 *
822 * @param ipv4
823 */
824 public void addPacket(IPv4 ipv4) {
Sangho Shin61535402014-10-01 11:37:14 -0700825 ipPacketQueue.add(ipv4);
Sangho Shin463bee52014-09-29 15:14:43 -0700826 }
827
828 /**
829 * Retrieve all packets whose destination is the given address.
830 *
831 * @param destIp Destination address of packets to retrieve
832 */
833 public List<IPv4> getIpPacketFromQueue(byte[] destIp) {
834
835 List<IPv4> bufferedPackets = new ArrayList<IPv4>();
836
Sangho Shin61535402014-10-01 11:37:14 -0700837 if (!ipPacketQueue.isEmpty()) {
838 for (IPv4 ip: ipPacketQueue) {
839 int dest = ip.getDestinationAddress();
840 IPv4Address ip1 = IPv4Address.of(dest);
841 IPv4Address ip2 = IPv4Address.of(destIp);
842 if (ip1.equals(ip2)) {
843 bufferedPackets.add((IPv4)(ipPacketQueue.poll()).clone());
Sangho Shin463bee52014-09-29 15:14:43 -0700844 }
845 }
846 }
847
848 return bufferedPackets;
849 }
850
Sangho Shin2f263692014-09-15 14:09:41 -0700851}