blob: 91f1262f993a218201aa32c82a5218059a71a183 [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 Shin5be3e532014-10-03 17:20:58 -070010import java.util.HashSet;
Sangho Shin2f263692014-09-15 14:09:41 -070011import java.util.Iterator;
12import java.util.List;
13import java.util.Map;
Sangho Shin5be3e532014-10-03 17:20:58 -070014import java.util.Set;
Sangho Shin61535402014-10-01 11:37:14 -070015import java.util.concurrent.ConcurrentLinkedQueue;
Sangho Shin11d4e0f2014-09-30 12:00:33 -070016import java.util.concurrent.ExecutionException;
Sangho Shin43cee112014-09-25 16:43:34 -070017import java.util.concurrent.ScheduledExecutorService;
18import java.util.concurrent.TimeUnit;
Sangho Shin11d4e0f2014-09-30 12:00:33 -070019import java.util.concurrent.TimeoutException;
Sangho Shin2f263692014-09-15 14:09:41 -070020
21import net.floodlightcontroller.core.IFloodlightProviderService;
Sangho Shin9c0f4c32014-09-26 16:02:38 -070022import net.floodlightcontroller.core.IOF13Switch;
Sangho Shin0df01982014-09-25 17:11:18 -070023import net.floodlightcontroller.core.IOF13Switch.NeighborSet;
Sangho Shin11d4e0f2014-09-30 12:00:33 -070024import net.floodlightcontroller.core.internal.OFBarrierReplyFuture;
Sangho Shin2f263692014-09-15 14:09:41 -070025import net.floodlightcontroller.core.module.FloodlightModuleContext;
26import net.floodlightcontroller.core.module.FloodlightModuleException;
27import net.floodlightcontroller.core.module.IFloodlightModule;
28import net.floodlightcontroller.core.module.IFloodlightService;
Sangho Shin43cee112014-09-25 16:43:34 -070029import net.floodlightcontroller.core.util.SingletonTask;
30import net.floodlightcontroller.threadpool.IThreadPoolService;
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070031import net.onrc.onos.api.packet.IPacketListener;
Sangho Shin2f263692014-09-15 14:09:41 -070032import net.onrc.onos.api.packet.IPacketService;
33import net.onrc.onos.core.flowprogrammer.IFlowPusherService;
Sangho Shinfbc572c2014-10-02 16:37:05 -070034import net.onrc.onos.core.intent.Path;
Sangho Shin2f263692014-09-15 14:09:41 -070035import net.onrc.onos.core.main.config.IConfigInfoService;
Sangho Shin43cee112014-09-25 16:43:34 -070036import net.onrc.onos.core.matchaction.MatchAction;
37import net.onrc.onos.core.matchaction.MatchActionId;
38import net.onrc.onos.core.matchaction.MatchActionOperationEntry;
Sangho Shin5be3e532014-10-03 17:20:58 -070039import net.onrc.onos.core.matchaction.MatchActionOperations.Operator;
Sangho Shin43cee112014-09-25 16:43:34 -070040import net.onrc.onos.core.matchaction.action.Action;
41import net.onrc.onos.core.matchaction.action.CopyTtlInAction;
42import net.onrc.onos.core.matchaction.action.CopyTtlOutAction;
43import net.onrc.onos.core.matchaction.action.DecMplsTtlAction;
44import net.onrc.onos.core.matchaction.action.DecNwTtlAction;
45import net.onrc.onos.core.matchaction.action.GroupAction;
46import net.onrc.onos.core.matchaction.action.PopMplsAction;
47import net.onrc.onos.core.matchaction.action.PushMplsAction;
48import net.onrc.onos.core.matchaction.action.SetMplsIdAction;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -070049import net.onrc.onos.core.matchaction.match.Ipv4Match;
Sangho Shin43cee112014-09-25 16:43:34 -070050import net.onrc.onos.core.matchaction.match.Match;
51import net.onrc.onos.core.matchaction.match.MplsMatch;
Sangho Shin2f263692014-09-15 14:09:41 -070052import net.onrc.onos.core.packet.ARP;
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070053import net.onrc.onos.core.packet.Ethernet;
54import net.onrc.onos.core.packet.IPv4;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070055import net.onrc.onos.core.topology.ITopologyListener;
Sangho Shin1aa93542014-09-22 09:49:44 -070056import net.onrc.onos.core.topology.ITopologyService;
Sangho Shinc8d2f592014-09-30 16:53:57 -070057import net.onrc.onos.core.topology.LinkData;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070058import net.onrc.onos.core.topology.MutableTopology;
Sangho Shineb083032014-09-22 16:11:34 -070059import net.onrc.onos.core.topology.Port;
Sangho Shinc8d2f592014-09-30 16:53:57 -070060import net.onrc.onos.core.topology.PortData;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070061import net.onrc.onos.core.topology.Switch;
Sangho Shin5be3e532014-10-03 17:20:58 -070062import net.onrc.onos.core.topology.SwitchData;
Sangho Shin1aa93542014-09-22 09:49:44 -070063import net.onrc.onos.core.topology.TopologyEvents;
Srikanth Vavilapalli363f1dc2014-09-22 14:30:23 -070064import net.onrc.onos.core.util.Dpid;
Sangho Shin43cee112014-09-25 16:43:34 -070065import net.onrc.onos.core.util.IPv4Net;
66import net.onrc.onos.core.util.SwitchPort;
Sangho Shin2f263692014-09-15 14:09:41 -070067
Sangho Shin43cee112014-09-25 16:43:34 -070068import org.json.JSONArray;
69import org.json.JSONException;
Saurav Dasbc594a42014-09-25 20:13:50 -070070import org.projectfloodlight.openflow.types.EthType;
Sangho Shin2f263692014-09-15 14:09:41 -070071import org.projectfloodlight.openflow.types.IPv4Address;
72import org.slf4j.Logger;
73import org.slf4j.LoggerFactory;
74
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070075public class SegmentRoutingManager implements IFloodlightModule,
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -070076 ITopologyListener, IPacketListener {
Sangho Shin2f263692014-09-15 14:09:41 -070077
78 private static final Logger log = LoggerFactory
79 .getLogger(SegmentRoutingManager.class);
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070080 private ITopologyService topologyService;
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070081 private IPacketService packetService;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070082 private MutableTopology mutableTopology;
Sangho Shin61535402014-10-01 11:37:14 -070083 private ConcurrentLinkedQueue<IPv4> ipPacketQueue;
Sangho Shin2f263692014-09-15 14:09:41 -070084
85 private List<ArpEntry> arpEntries;
Sangho Shineb083032014-09-22 16:11:34 -070086 private ArpHandler arpHandler;
87 private GenericIpHandler ipHandler;
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070088 private IcmpHandler icmpHandler;
Sangho Shin43cee112014-09-25 16:43:34 -070089 private IThreadPoolService threadPool;
90 private SingletonTask discoveryTask;
Sangho Shin9c0f4c32014-09-26 16:02:38 -070091 private IFloodlightProviderService floodlightProvider;
Sangho Shin2f263692014-09-15 14:09:41 -070092
Sangho Shinfbc572c2014-10-02 16:37:05 -070093 private HashMap<Switch, ECMPShortestPathGraph> graphs;
Sangho Shin5be3e532014-10-03 17:20:58 -070094 private HashSet<LinkData> topologyLinks;
95 private ConcurrentLinkedQueue<TopologyEvents> topologyEventQueue;
Sangho Shinfbc572c2014-10-02 16:37:05 -070096
Sangho Shin2f263692014-09-15 14:09:41 -070097 @Override
98 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
99 // TODO Auto-generated method stub
100 return null;
101 }
102
103 @Override
104 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
105 // TODO Auto-generated method stub
106 return null;
107 }
108
109 @Override
110 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
111 Collection<Class<? extends IFloodlightService>> l = new ArrayList<Class<? extends IFloodlightService>>();
112
113 l.add(IFloodlightProviderService.class);
114 l.add(IConfigInfoService.class);
115 l.add(ITopologyService.class);
116 l.add(IPacketService.class);
117 l.add(IFlowPusherService.class);
118 l.add(ITopologyService.class);
119
120 return l;
121
122 }
123
124 @Override
125 public void init(FloodlightModuleContext context) throws FloodlightModuleException {
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700126 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Sangho Shineb083032014-09-22 16:11:34 -0700127 arpHandler = new ArpHandler(context, this);
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700128 icmpHandler = new IcmpHandler(context, this);
Sangho Shineb083032014-09-22 16:11:34 -0700129 ipHandler = new GenericIpHandler(context, this);
Sangho Shin2f263692014-09-15 14:09:41 -0700130 arpEntries = new ArrayList<ArpEntry>();
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700131 topologyService = context.getServiceImpl(ITopologyService.class);
Sangho Shin43cee112014-09-25 16:43:34 -0700132 threadPool = context.getServiceImpl(IThreadPoolService.class);
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700133 mutableTopology = topologyService.getTopology();
134 topologyService.addListener(this, false);
Sangho Shin61535402014-10-01 11:37:14 -0700135 ipPacketQueue = new ConcurrentLinkedQueue<IPv4>();
Sangho Shinfbc572c2014-10-02 16:37:05 -0700136 graphs = new HashMap<Switch, ECMPShortestPathGraph>();
Sangho Shin5be3e532014-10-03 17:20:58 -0700137 topologyLinks = new HashSet<LinkData>();
138 topologyEventQueue = new ConcurrentLinkedQueue<TopologyEvents>();
Sangho Shin2f263692014-09-15 14:09:41 -0700139
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700140 this.packetService = context.getServiceImpl(IPacketService.class);
141 packetService.registerPacketListener(this);
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700142
Sangho Shin2f263692014-09-15 14:09:41 -0700143 }
144
145 @Override
146 public void startUp(FloodlightModuleContext context) throws FloodlightModuleException {
Sangho Shinc8d2f592014-09-30 16:53:57 -0700147 ScheduledExecutorService ses = threadPool.getScheduledExecutor();
Sangho Shin2f263692014-09-15 14:09:41 -0700148
Sangho Shinc8d2f592014-09-30 16:53:57 -0700149 discoveryTask = new SingletonTask(ses, new Runnable() {
150 @Override
151 public void run() {
Sangho Shin5be3e532014-10-03 17:20:58 -0700152 handleTopologyChangeEvents();
Sangho Shinc8d2f592014-09-30 16:53:57 -0700153 }
154 });
Sangho Shin2f263692014-09-15 14:09:41 -0700155 }
156
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700157 @Override
158 public void receive(Switch sw, Port inPort, Ethernet payload) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700159 if (payload.getEtherType() == Ethernet.TYPE_ARP)
160 arpHandler.processPacketIn(sw, inPort, payload);
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700161 if (payload.getEtherType() == Ethernet.TYPE_IPV4) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700162 addPacket((IPv4) payload.getPayload());
163 if (((IPv4) payload.getPayload()).getProtocol() == IPv4.PROTOCOL_ICMP)
164 icmpHandler.processPacketIn(sw, inPort, payload);
165 else
166 ipHandler.processPacketIn(sw, inPort, payload);
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700167 }
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700168 else {
169 log.debug("{}", payload.toString());
170 }
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700171 }
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700172
Sangho Shin2f263692014-09-15 14:09:41 -0700173 /**
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700174 * Update ARP Cache using ARP packets It is used to set destination MAC
175 * address to forward packets to known hosts. But, it will be replace with
176 * Host information of Topology service later.
Sangho Shinfbc572c2014-10-02 16:37:05 -0700177 *
Sangho Shin2f263692014-09-15 14:09:41 -0700178 * @param arp APR packets to use for updating ARP entries
179 */
180 public void updateArpCache(ARP arp) {
181
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700182 ArpEntry arpEntry = new ArpEntry(arp.getSenderHardwareAddress(),
183 arp.getSenderProtocolAddress());
Sangho Shin2f263692014-09-15 14:09:41 -0700184 // TODO: Need to check the duplication
185 arpEntries.add(arpEntry);
186 }
187
188 /**
189 * Get MAC address to known hosts
Sangho Shinfbc572c2014-10-02 16:37:05 -0700190 *
Sangho Shin2f263692014-09-15 14:09:41 -0700191 * @param destinationAddress IP address to get MAC address
192 * @return MAC Address to given IP address
193 */
194 public byte[] getMacAddressFromIpAddress(int destinationAddress) {
195
196 // Can't we get the host IP address from the TopologyService ??
197
198 Iterator<ArpEntry> iterator = arpEntries.iterator();
199
200 IPv4Address ipAddress = IPv4Address.of(destinationAddress);
201 byte[] ipAddressInByte = ipAddress.getBytes();
202
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700203 while (iterator.hasNext()) {
Sangho Shin2f263692014-09-15 14:09:41 -0700204 ArpEntry arpEntry = iterator.next();
205 byte[] address = arpEntry.targetIpAddress;
206
207 IPv4Address a = IPv4Address.of(address);
208 IPv4Address b = IPv4Address.of(ipAddressInByte);
209
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700210 if (a.equals(b)) {
Sangho Shin2f263692014-09-15 14:09:41 -0700211 log.debug("Found an arp entry");
212 return arpEntry.targetMacAddress;
213 }
214 }
215
216 return null;
217 }
218
Sangho Shineb083032014-09-22 16:11:34 -0700219 /**
220 * Send an ARP request via ArpHandler
Sangho Shinfbc572c2014-10-02 16:37:05 -0700221 *
Sangho Shineb083032014-09-22 16:11:34 -0700222 * @param destinationAddress
223 * @param sw
224 * @param inPort
Sangho Shinfbc572c2014-10-02 16:37:05 -0700225 *
Sangho Shineb083032014-09-22 16:11:34 -0700226 */
227 public void sendArpRequest(Switch sw, int destinationAddress, Port inPort) {
228 arpHandler.sendArpRequest(sw, destinationAddress, inPort);
229 }
Sangho Shin2f263692014-09-15 14:09:41 -0700230
231 /**
232 * Temporary class to to keep ARP entry
Sangho Shinfbc572c2014-10-02 16:37:05 -0700233 *
Sangho Shin2f263692014-09-15 14:09:41 -0700234 */
235 private class ArpEntry {
236
237 byte[] targetMacAddress;
238 byte[] targetIpAddress;
239
240 private ArpEntry(byte[] macAddress, byte[] ipAddress) {
241 this.targetMacAddress = macAddress;
242 this.targetIpAddress = ipAddress;
243 }
Sangho Shin2f263692014-09-15 14:09:41 -0700244 }
Sangho Shineb083032014-09-22 16:11:34 -0700245
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700246 /**
247 * Topology events that have been generated.
Sangho Shinfbc572c2014-10-02 16:37:05 -0700248 *
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700249 * @param topologyEvents the generated Topology Events
250 * @see TopologyEvents
251 */
252 public void topologyEvents(TopologyEvents topologyEvents)
253 {
Sangho Shin5be3e532014-10-03 17:20:58 -0700254 topologyEventQueue.add(topologyEvents);
255 discoveryTask.reschedule(500, TimeUnit.MILLISECONDS);
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700256
Sangho Shin5be3e532014-10-03 17:20:58 -0700257 }
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700258
Sangho Shinc8d2f592014-09-30 16:53:57 -0700259
Sangho Shin5be3e532014-10-03 17:20:58 -0700260 private void handleTopologyChangeEvents() {
Sangho Shinc8d2f592014-09-30 16:53:57 -0700261
Sangho Shin5be3e532014-10-03 17:20:58 -0700262 while (!topologyEventQueue.isEmpty()) {
263 TopologyEvents topologyEvents = topologyEventQueue.poll();
264
265 Collection<LinkData> linkEntriesAdded =
266 topologyEvents.getAddedLinkDataEntries();
267 if (!linkEntriesAdded.isEmpty()) {
268 processLinkAdd(linkEntriesAdded);
269 }
270
271 Collection<PortData> PortEntriesAdded =
272 topologyEvents.getAddedPortDataEntries();
273 if (linkEntriesAdded != null) {
274 processPortAdd(PortEntriesAdded);
275 }
276
277 Collection<PortData> portEntries =
278 topologyEvents.getRemovedPortDataEntries();
279 if (!portEntries.isEmpty()) {
280 processPortRemoval(portEntries);
281 }
282
283 Collection<LinkData> linkEntriesRemoved =
284 topologyEvents.getRemovedLinkDataEntries();
285 if (!linkEntriesRemoved.isEmpty()) {
286 processLinkRemoval(linkEntriesRemoved);
287 }
288
289 Collection<SwitchData> switchRemoved =
290 topologyEvents.getRemovedSwitchDataEntries();
291 if (!switchRemoved.isEmpty()) {
292 processSwitchRemoved(switchRemoved);
293 }
294
Sangho Shin61535402014-10-01 11:37:14 -0700295 }
296 }
Sangho Shinc8d2f592014-09-30 16:53:57 -0700297
Sangho Shin5be3e532014-10-03 17:20:58 -0700298 private void processSwitchRemoved(Collection<SwitchData> switchRemoved) {
299 /* TODO: We should remove only the links of the switch removed */
300 topologyLinks.clear();
301 }
302
Sangho Shin61535402014-10-01 11:37:14 -0700303 /**
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700304 * Report ports newly added to driver
Sangho Shinfbc572c2014-10-02 16:37:05 -0700305 *
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700306 * @param portEntries
307 */
308 private void processPortAdd(Collection<PortData> portEntries) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700309 // TODO: do we need to add ports slowly?
310 for (PortData port : portEntries) {
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700311 Dpid dpid = port.getDpid();
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700312
Sangho Shinfbc572c2014-10-02 16:37:05 -0700313 IOF13Switch sw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700314 getSwId(port.getDpid().toString()));
Fahad Naeem Khand89448d2014-10-06 18:40:45 -0700315 if (sw == null){
316 return;
317 }
Sangho Shinfbc572c2014-10-02 16:37:05 -0700318 sw.addPortToGroups(port.getPortNumber());
319
320 log.debug("Add port {} to switch {}", port, dpid);
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700321 }
322 }
323
324 /**
325 * Reports ports of new links to driver and recalculate ECMP SPG
Sangho Shinfbc572c2014-10-02 16:37:05 -0700326 *
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700327 * @param linkEntries
328 */
329 private void processLinkAdd(Collection<LinkData> linkEntries) {
330
Sangho Shin5be3e532014-10-03 17:20:58 -0700331 boolean linkRecovered = false;
332
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700333 // TODO: How to determine this link was broken before and back now
334 // If so, we need to ad the link slowly...
335 // Or, just add any new or restored link slowly ???
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700336 for (LinkData link : linkEntries) {
Sangho Shin5be3e532014-10-03 17:20:58 -0700337
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700338 SwitchPort srcPort = link.getSrc();
339 SwitchPort dstPort = link.getDst();
340
Sangho Shinfbc572c2014-10-02 16:37:05 -0700341 IOF13Switch srcSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700342 getSwId(srcPort.getDpid().toString()));
Sangho Shinfbc572c2014-10-02 16:37:05 -0700343 IOF13Switch dstSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700344 getSwId(srcPort.getDpid().toString()));
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700345
Sangho Shinfbc572c2014-10-02 16:37:05 -0700346 srcSw.addPortToGroups(srcPort.getPortNumber());
347 dstSw.addPortToGroups(dstPort.getPortNumber());
Sangho Shin5be3e532014-10-03 17:20:58 -0700348
349
350 if (!topologyLinks.contains(link)) {
351 topologyLinks.add(link);
352 }
353 else {
354 linkRecovered = true;
355 }
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700356 }
Sangho Shin5be3e532014-10-03 17:20:58 -0700357 if (linkRecovered) {
358 populateEcmpRoutingRules(true);
359 }
360 else {
361 populateEcmpRoutingRules(false);
362 }
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700363 }
364
365 /**
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700366 * Check if all links are gone b/w the two switches. If all links are gone,
367 * then we need to recalculate the path. Otherwise, just report link failure
368 * to the driver.
Sangho Shinfbc572c2014-10-02 16:37:05 -0700369 *
Sangho Shin61535402014-10-01 11:37:14 -0700370 * @param linkEntries
371 */
372 private void processLinkRemoval(Collection<LinkData> linkEntries) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700373 for (LinkData link : linkEntries) {
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700374 SwitchPort srcPort = link.getSrc();
375 SwitchPort dstPort = link.getDst();
Sangho Shinc8d2f592014-09-30 16:53:57 -0700376
Sangho Shinfbc572c2014-10-02 16:37:05 -0700377 IOF13Switch srcSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700378 getSwId(srcPort.getDpid().toString()));
Sangho Shinfbc572c2014-10-02 16:37:05 -0700379 IOF13Switch dstSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700380 getSwId(srcPort.getDpid().toString()));
Sangho Shinfbc572c2014-10-02 16:37:05 -0700381
382 // TODO: Why do we get null for the master switch??
383 if (srcSw != null)
384 srcSw.removePortFromGroups(srcPort.getPortNumber());
385 if (dstSw != null)
386 dstSw.removePortFromGroups(dstPort.getPortNumber());
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700387
388 Switch srcSwitch = mutableTopology.getSwitch(srcPort.getDpid());
389 if (srcSwitch.getLinkToNeighbor(dstPort.getDpid()) == null) {
Sangho Shin5be3e532014-10-03 17:20:58 -0700390 //modifyEcmpRoutingRules(link);
391 populateEcmpRoutingRules(true);
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700392 log.debug("All links are gone b/w {} and {}", srcPort.getDpid(),
Sangho Shin5be3e532014-10-03 17:20:58 -0700393 dstPort.getDpid());
Sangho Shinc8d2f592014-09-30 16:53:57 -0700394 }
395 }
Sangho Shin61535402014-10-01 11:37:14 -0700396 }
Sangho Shinc8d2f592014-09-30 16:53:57 -0700397
Sangho Shin61535402014-10-01 11:37:14 -0700398 /**
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700399 * report ports removed to the driver immediately
Sangho Shinfbc572c2014-10-02 16:37:05 -0700400 *
Sangho Shin61535402014-10-01 11:37:14 -0700401 * @param portEntries
402 */
403 private void processPortRemoval(Collection<PortData> portEntries) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700404 for (PortData port : portEntries) {
Sangho Shin61535402014-10-01 11:37:14 -0700405 Dpid dpid = port.getDpid();
Sangho Shin61535402014-10-01 11:37:14 -0700406
Sangho Shinfbc572c2014-10-02 16:37:05 -0700407 IOF13Switch sw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin61535402014-10-01 11:37:14 -0700408 getSwId(port.getDpid().toString()));
Sangho Shinfbc572c2014-10-02 16:37:05 -0700409 if (sw != null)
410 sw.removePortFromGroups(port.getPortNumber());
411 log.debug("Remove port {} from switch {}", port, dpid);
Sangho Shin61535402014-10-01 11:37:14 -0700412 }
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700413 }
Sangho Shin1aa93542014-09-22 09:49:44 -0700414
415 /**
Sangho Shin43cee112014-09-25 16:43:34 -0700416 * Populate routing rules walking through the ECMP shortest paths
Sangho Shinfbc572c2014-10-02 16:37:05 -0700417 *
Sangho Shin1aa93542014-09-22 09:49:44 -0700418 */
Sangho Shin5be3e532014-10-03 17:20:58 -0700419 private void populateEcmpRoutingRules(boolean modified) {
420 graphs.clear();
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700421 Iterable<Switch> switches = mutableTopology.getSwitches();
Sangho Shin43cee112014-09-25 16:43:34 -0700422 for (Switch sw : switches) {
423 ECMPShortestPathGraph ecmpSPG = new ECMPShortestPathGraph(sw);
Sangho Shinfbc572c2014-10-02 16:37:05 -0700424 graphs.put(sw, ecmpSPG);
425 //log.debug("ECMPShortestPathGraph is computed for switch {}",
426 // HexString.toHexString(sw.getDpid().value()));
Sangho Shin5be3e532014-10-03 17:20:58 -0700427 populateEcmpRoutingRulesForPath(sw, ecmpSPG, modified);
428 if (modified) {
429 log.debug("Modify the rules for {}" , sw.getDpid());
430 }
Sangho Shinfbc572c2014-10-02 16:37:05 -0700431 }
432 }
Sangho Shin1aa93542014-09-22 09:49:44 -0700433
Sangho Shinfbc572c2014-10-02 16:37:05 -0700434 private void populateEcmpRoutingRulesForPath(Switch sw,
Sangho Shin5be3e532014-10-03 17:20:58 -0700435 ECMPShortestPathGraph ecmpSPG, boolean modified) {
Sangho Shin43cee112014-09-25 16:43:34 -0700436
Sangho Shinfbc572c2014-10-02 16:37:05 -0700437 HashMap<Integer, HashMap<Switch, ArrayList<ArrayList<Dpid>>>> switchVia =
438 ecmpSPG.getAllLearnedSwitchesAndVia();
439 for (Integer itrIdx : switchVia.keySet()) {
440 //log.debug("ECMPShortestPathGraph:Switches learned in "
441 // + "Iteration{} from switch {}:",
442 // itrIdx,
443 // HexString.toHexString(sw.getDpid().value()));
444 HashMap<Switch, ArrayList<ArrayList<Dpid>>> swViaMap =
445 switchVia.get(itrIdx);
446 for (Switch targetSw : swViaMap.keySet()) {
Sangho Shin5be3e532014-10-03 17:20:58 -0700447 //log.debug("ECMPShortestPathGraph:****switch {} via:",
448 // HexString.toHexString(targetSw.getDpid().value()));
Sangho Shinfbc572c2014-10-02 16:37:05 -0700449 String destSw = sw.getDpid().toString();
450 List<String> fwdToSw = new ArrayList<String>();
451
Sangho Shinfbc572c2014-10-02 16:37:05 -0700452 for (ArrayList<Dpid> via : swViaMap.get(targetSw)) {
Sangho Shin5be3e532014-10-03 17:20:58 -0700453 //log.debug("ECMPShortestPathGraph:******{}) {}", ++i, via);
Sangho Shinfbc572c2014-10-02 16:37:05 -0700454 if (via.isEmpty()) {
455 fwdToSw.add(destSw);
Sangho Shin43cee112014-09-25 16:43:34 -0700456 }
Sangho Shinfbc572c2014-10-02 16:37:05 -0700457 else {
458 fwdToSw.add(via.get(0).toString());
459 }
Sangho Shin43cee112014-09-25 16:43:34 -0700460 }
Sangho Shin5be3e532014-10-03 17:20:58 -0700461 setRoutingRule(targetSw, destSw, fwdToSw, modified);
Sangho Shineb083032014-09-22 16:11:34 -0700462 }
Sangho Shinfbc572c2014-10-02 16:37:05 -0700463
464 // Send Barrier Message and make sure all rules are set
465 // before we set the rules to next routers
466 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
467 getSwId(sw.getDpid().toString()));
Sangho Shin5be3e532014-10-03 17:20:58 -0700468 if (sw13 != null) {
469 try {
470 OFBarrierReplyFuture replyFuture = sw13.sendBarrier();
471 replyFuture.get(10, TimeUnit.SECONDS);
472 } catch (IOException e) {
473 e.printStackTrace();
474 } catch (InterruptedException | ExecutionException | TimeoutException e) {
475 log.error("Barrier message not received for sw: {}", sw.getDpid());
476 e.printStackTrace();
477 }
Sangho Shinfbc572c2014-10-02 16:37:05 -0700478 }
479 }
480
481 }
482
483
484 private class SwitchPair {
485 private Switch src;
486 private Switch dst;
487
488 public SwitchPair(Switch src, Switch dst) {
489 this.src = src;
490 this.dst = dst;
491 }
492
493 public Switch getSource() {
494 return src;
495 }
496
497 public Switch getDestination() {
498 return dst;
Sangho Shineb083032014-09-22 16:11:34 -0700499 }
Sangho Shin43cee112014-09-25 16:43:34 -0700500 }
501
502 /**
Sangho Shinfbc572c2014-10-02 16:37:05 -0700503 * Modify the routing rules for the lost links
504 * - Recompute the path if the link failed is included in the path
505 * (including src and dest).
506 *
507 * @param newLink
508 */
509 private void modifyEcmpRoutingRules(LinkData linkRemoved) {
510
511 //HashMap<Switch, SwitchPair> linksToRecompute = new HashMap<Switch, SwitchPair>();
Sangho Shin5be3e532014-10-03 17:20:58 -0700512 Set<SwitchPair> linksToRecompute = new HashSet<SwitchPair>();
Sangho Shinfbc572c2014-10-02 16:37:05 -0700513
514 for (ECMPShortestPathGraph ecmpSPG : graphs.values()) {
515 Switch rootSw = ecmpSPG.getRootSwitch();
516 HashMap<Integer, HashMap<Switch, ArrayList<Path>>> paths =
517 ecmpSPG.getCompleteLearnedSwitchesAndPaths();
518 for (HashMap<Switch, ArrayList<Path>> p: paths.values()) {
519 for (Switch destSw: p.keySet()) {
520 ArrayList<Path> path = p.get(destSw);
521 if (checkPath(path, linkRemoved)) {
Sangho Shin5be3e532014-10-03 17:20:58 -0700522 boolean found = false;
523 for (SwitchPair pair: linksToRecompute) {
524 if (pair.getSource().getDpid() == rootSw.getDpid() &&
525 pair.getSource().getDpid() == destSw.getDpid()) {
526 found = true;
527 }
528 }
529 if (!found) {
530 linksToRecompute.add(new SwitchPair(rootSw, destSw));
531 }
Sangho Shinfbc572c2014-10-02 16:37:05 -0700532 }
533 }
534 }
535 }
536
537 // Recompute the path for the specific route
538 for (SwitchPair pair: linksToRecompute) {
539
540 log.debug("Recompute path from {} to {}", pair.getSource(), pair.getDestination());
541 // TODO : we need the following function
542 //ECMPShortestPathGraph ecmpSPG =
543 // new ECMPShortestPathGraph(pair.getSource(), pair.getDestination());
544 ECMPShortestPathGraph ecmpSPG =
545 new ECMPShortestPathGraph(pair.getSource());
546 // TODO: we need to use different function to MODIFY the rules
Sangho Shin5be3e532014-10-03 17:20:58 -0700547 populateEcmpRoutingRulesForPath(pair.getSource(), ecmpSPG, true);
Sangho Shinfbc572c2014-10-02 16:37:05 -0700548 }
549 }
550
551 /**
552 * Check if the path is affected from the link removed
553 *
554 * @param path Path to check
555 * @param linkRemoved link removed
556 * @return true if the path contains the link removed
557 */
558 private boolean checkPath(ArrayList<Path> path, LinkData linkRemoved) {
559
560 for (Path ppp: path) {
561 // TODO: need to check if this is a bidirectional or
562 // unidirectional
Sangho Shin5be3e532014-10-03 17:20:58 -0700563 for (LinkData link: ppp) {
564 //if (link.equals(linkRemoved))
565 if (link.getDst().getDpid().equals(linkRemoved.getDst().getDpid()) &&
566 link.getSrc().getDpid().equals(linkRemoved.getSrc().getDpid()))
567 return true;
Sangho Shinfbc572c2014-10-02 16:37:05 -0700568 }
569 }
570
571 return false;
572 }
573
574 /**
575 *
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700576 * Set routing rules in targetSw {forward packets to fwdToSw switches in
577 * order to send packets to destSw} - If the target switch is an edge router
578 * and final destnation switch is also an edge router, then set IP
579 * forwarding rules to subnets - If only the target switch is an edge
580 * router, then set IP forwarding rule to the transit router loopback IP
581 * address - If the target is a transit router, then just set the MPLS
582 * forwarding rule
Sangho Shinfbc572c2014-10-02 16:37:05 -0700583 *
Sangho Shin43cee112014-09-25 16:43:34 -0700584 * @param targetSw Switch to set the rules
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700585 * @param destSw Final destination switches
Sangho Shin43cee112014-09-25 16:43:34 -0700586 * @param fwdToSw next hop switches
587 */
Sangho Shin5be3e532014-10-03 17:20:58 -0700588 private void setRoutingRule(Switch targetSw, String destSw, List<String> fwdToSw,
589 boolean modified) {
Sangho Shin43cee112014-09-25 16:43:34 -0700590
Sangho Shin43cee112014-09-25 16:43:34 -0700591 if (fwdToSw.isEmpty()) {
592 fwdToSw.add(destSw);
593 }
594
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700595 // if both target SW and dest SW are an edge router, then set IP table
Sangho Shin43cee112014-09-25 16:43:34 -0700596 if (IsEdgeRouter(targetSw.getDpid().toString()) &&
597 IsEdgeRouter(destSw)) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700598 // We assume that there is at least one transit router b/w edge
599 // routers
Sangho Shin43cee112014-09-25 16:43:34 -0700600 Switch destSwitch = mutableTopology.getSwitch(new Dpid(destSw));
601 String subnets = destSwitch.getStringAttribute("subnets");
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700602 setIpTableRouterSubnet(targetSw, subnets, getMplsLabel(destSw)
Sangho Shin5be3e532014-10-03 17:20:58 -0700603 , fwdToSw, modified);
Sangho Shin43cee112014-09-25 16:43:34 -0700604
Sangho Shin43cee112014-09-25 16:43:34 -0700605 String routerIp = destSwitch.getStringAttribute("routerIp");
Sangho Shin5be3e532014-10-03 17:20:58 -0700606 setIpTableRouter(targetSw, routerIp, getMplsLabel(destSw), fwdToSw,
607 null, modified);
Sangho Shin43cee112014-09-25 16:43:34 -0700608 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700609 // Only if the target switch is the edge router, then set the IP rules
Sangho Shin43cee112014-09-25 16:43:34 -0700610 else if (IsEdgeRouter(targetSw.getDpid().toString())) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700611 // We assume that there is at least one transit router b/w edge
612 // routers
Sangho Shin43cee112014-09-25 16:43:34 -0700613 Switch destSwitch = mutableTopology.getSwitch(new Dpid(destSw));
614 String routerIp = destSwitch.getStringAttribute("routerIp");
Sangho Shin5be3e532014-10-03 17:20:58 -0700615 setIpTableRouter(targetSw, routerIp, getMplsLabel(destSw), fwdToSw,
616 null, modified);
Sangho Shin43cee112014-09-25 16:43:34 -0700617 }
618 // if it is a transit router, then set rules in the MPLS table
619 else {
Sangho Shin5be3e532014-10-03 17:20:58 -0700620 setMplsTable(targetSw, getMplsLabel(destSw), fwdToSw, modified);
Sangho Shin43cee112014-09-25 16:43:34 -0700621 }
622
623 }
624
Sangho Shinfbc572c2014-10-02 16:37:05 -0700625 /**
626 * Set IP forwarding rule to the gateway of each subnet of switches
627 *
628 * @param targetSw Switch to set rules
629 * @param subnets subnet information
630 * @param mplsLabel destination MPLS label
631 * @param fwdToSw router to forward packets to
632 */
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700633 private void setIpTableRouterSubnet(Switch targetSw, String subnets,
Sangho Shin5be3e532014-10-03 17:20:58 -0700634 String mplsLabel, List<String> fwdToSw, boolean modified) {
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700635
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700636 Collection<MatchActionOperationEntry> entries =
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700637 new ArrayList<MatchActionOperationEntry>();
638
639 try {
640 JSONArray arry = new JSONArray(subnets);
641 for (int i = 0; i < arry.length(); i++) {
642 String subnetIp = (String) arry.getJSONObject(i).get("subnetIp");
Sangho Shin5be3e532014-10-03 17:20:58 -0700643 setIpTableRouter(targetSw, subnetIp, mplsLabel, fwdToSw, entries,
644 modified);
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700645 }
646 } catch (JSONException e) {
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700647 e.printStackTrace();
648 }
649
650 if (!entries.isEmpty()) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700651 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700652 getSwId(targetSw.getDpid().toString()));
653
654 try {
655 sw13.pushFlows(entries);
656 } catch (IOException e) {
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700657 e.printStackTrace();
658 }
659 }
660
661 }
662
Sangho Shin43cee112014-09-25 16:43:34 -0700663 /**
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700664 * Check if the switch is the edge router or not If any subnet information
665 * is defined in the config file, the we assume it is an edge router
Sangho Shinfbc572c2014-10-02 16:37:05 -0700666 *
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700667 * @param dpid Dpid of the switch to check
Sangho Shin43cee112014-09-25 16:43:34 -0700668 * @return true if it is an edge router, otherwise false
669 */
670 private boolean IsEdgeRouter(String dpid) {
671
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700672 for (Switch sw : mutableTopology.getSwitches()) {
Sangho Shin43cee112014-09-25 16:43:34 -0700673 String dpidStr = sw.getDpid().toString();
674 if (dpid.equals(dpidStr)) {
675 String subnetInfo = sw.getStringAttribute("subnets");
676 if (subnetInfo == null || subnetInfo.equals("[]")) {
677 return false;
678 }
679 else
680 return true;
681 }
682 }
683
684 return false;
685 }
686
687 /**
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700688 * Set IP forwarding rule - If the destination is the next hop, then do not
689 * push MPLS, just decrease the NW TTL - Otherwise, push MPLS label and set
690 * the MPLS ID
Sangho Shinfbc572c2014-10-02 16:37:05 -0700691 *
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700692 * @param sw target switch to set rules
Sangho Shin43cee112014-09-25 16:43:34 -0700693 * @param subnetIp Match IP address
694 * @param mplsLabel MPLS label of final destination router
695 * @param fwdToSws next hop routers
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700696 * @param entries
Sangho Shin43cee112014-09-25 16:43:34 -0700697 */
698 private void setIpTableRouter(Switch sw, String subnetIp, String mplsLabel,
Sangho Shin5be3e532014-10-03 17:20:58 -0700699 List<String> fwdToSws, Collection<MatchActionOperationEntry> entries,
700 boolean modified) {
Sangho Shin43cee112014-09-25 16:43:34 -0700701
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700702 Ipv4Match ipMatch = new Ipv4Match(subnetIp);
Sangho Shin43cee112014-09-25 16:43:34 -0700703 List<Action> actions = new ArrayList<>();
704
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700705 // If destination SW is the same as the fwd SW, then do not push MPLS
706 // label
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700707
708 if (fwdToSws.size() > 1) {
Sangho Shin43cee112014-09-25 16:43:34 -0700709 PushMplsAction pushMplsAction = new PushMplsAction();
710 SetMplsIdAction setIdAction = new SetMplsIdAction(Integer.parseInt(mplsLabel));
711 CopyTtlOutAction copyTtlOutAction = new CopyTtlOutAction();
Sangho Shin463bee52014-09-29 15:14:43 -0700712 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
Sangho Shin43cee112014-09-25 16:43:34 -0700713
714 actions.add(pushMplsAction);
Sangho Shin43cee112014-09-25 16:43:34 -0700715 actions.add(copyTtlOutAction);
Sangho Shin463bee52014-09-29 15:14:43 -0700716 actions.add(decMplsTtlAction);
717 actions.add(setIdAction);
Sangho Shin43cee112014-09-25 16:43:34 -0700718 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700719 else {
720 String fwdToSw = fwdToSws.get(0);
721 if (getMplsLabel(fwdToSw).equals(mplsLabel)) {
722 DecNwTtlAction decTtlAction = new DecNwTtlAction(1);
723 actions.add(decTtlAction);
724 }
725 else {
726 PushMplsAction pushMplsAction = new PushMplsAction();
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700727 SetMplsIdAction setIdAction = new SetMplsIdAction(
728 Integer.parseInt(mplsLabel));
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700729 CopyTtlOutAction copyTtlOutAction = new CopyTtlOutAction();
Sangho Shin463bee52014-09-29 15:14:43 -0700730 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700731
732 actions.add(pushMplsAction);
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700733 actions.add(copyTtlOutAction);
Sangho Shin463bee52014-09-29 15:14:43 -0700734 actions.add(decMplsTtlAction);
735 actions.add(setIdAction);
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700736 }
737 }
Sangho Shin43cee112014-09-25 16:43:34 -0700738
739 GroupAction groupAction = new GroupAction();
740
741 for (String fwdSw : fwdToSws) {
742 groupAction.addSwitch(new Dpid(fwdSw));
743 }
744 actions.add(groupAction);
745
Sangho Shinc8d2f592014-09-30 16:53:57 -0700746 // TODO: Mactch Action Id should be set correctly
Sangho Shin43cee112014-09-25 16:43:34 -0700747 MatchAction matchAction = new MatchAction(new MatchActionId(0),
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700748 new SwitchPort((long) 0, (short) 0), ipMatch, actions);
Sangho Shin43cee112014-09-25 16:43:34 -0700749
Sangho Shin5be3e532014-10-03 17:20:58 -0700750 Operator operator = null;
751 if (modified)
752 operator = Operator.MODIFY;
753 else
754 operator = Operator.ADD;
755
Sangho Shin43cee112014-09-25 16:43:34 -0700756 MatchActionOperationEntry maEntry =
Sangho Shin5be3e532014-10-03 17:20:58 -0700757 new MatchActionOperationEntry(operator, matchAction);
Sangho Shin43cee112014-09-25 16:43:34 -0700758
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700759 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700760 getSwId(sw.getDpid().toString()));
761
Sangho Shin5be3e532014-10-03 17:20:58 -0700762 /* TODO: we should check the SWICH REMOVED events */
763 if (sw13 != null) {
764 try {
765 printMatchActionOperationEntry(sw, maEntry);
766 if (entries != null)
767 entries.add(maEntry);
768 else
769 sw13.pushFlow(maEntry);
770 } catch (IOException e) {
771 e.printStackTrace();
772 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700773 }
774
Sangho Shin43cee112014-09-25 16:43:34 -0700775 }
776
Sangho Shinac5ee2b2014-09-28 21:27:20 -0700777 /**
778 * Convert a string DPID to its Switch Id (integer)
Sangho Shinfbc572c2014-10-02 16:37:05 -0700779 *
Sangho Shinac5ee2b2014-09-28 21:27:20 -0700780 * @param dpid
781 * @return
782 */
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700783 private long getSwId(String dpid) {
784
785 long swId = 0;
786
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700787 String swIdStr = dpid.substring(dpid.lastIndexOf(":") + 1);
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700788 if (swIdStr != null)
789 swId = Integer.parseInt(swIdStr);
790
791 return swId;
792 }
793
Sangho Shin43cee112014-09-25 16:43:34 -0700794 /**
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700795 * Set MPLS forwarding rules to MPLS table - If the destination is the same
796 * as the next hop to forward packets then, pop the MPLS label according to
797 * PHP rule - Otherwise, just forward packets to next hops using Group
798 * action
Sangho Shinfbc572c2014-10-02 16:37:05 -0700799 *
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700800 * @param sw Switch to set the rules
Sangho Shin43cee112014-09-25 16:43:34 -0700801 * @param mplsLabel destination MPLS label
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700802 * @param fwdSws next hop switches
Sangho Shin43cee112014-09-25 16:43:34 -0700803 */
Sangho Shin5be3e532014-10-03 17:20:58 -0700804 private void setMplsTable(Switch sw, String mplsLabel, List<String> fwdSws,
805 boolean modified) {
Sangho Shin463bee52014-09-29 15:14:43 -0700806
Sangho Shin43cee112014-09-25 16:43:34 -0700807 MplsMatch mplsMatch = new MplsMatch(Integer.parseInt(mplsLabel));
808
809 List<Action> actions = new ArrayList<Action>();
Sangho Shin43cee112014-09-25 16:43:34 -0700810
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700811 // If the destination is the same as the next hop, then pop MPLS
Sangho Shinc8d2f592014-09-30 16:53:57 -0700812 // Otherwise, just decrease the MPLS TTL.
Sangho Shin463bee52014-09-29 15:14:43 -0700813 if (fwdSws.size() == 1) {
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700814 String fwdMplsId = getMplsLabel(fwdSws.get(0));
815 if (fwdMplsId.equals(mplsLabel)) {
816 String fwdSw = fwdSws.get(0);
817 if (mplsLabel.equals(getMplsLabel(fwdSw))) {
818 PopMplsAction popAction = new PopMplsAction(EthType.IPv4);
819 CopyTtlInAction copyTtlInAction = new CopyTtlInAction();
Sangho Shin463bee52014-09-29 15:14:43 -0700820 DecNwTtlAction decNwTtlAction = new DecNwTtlAction(1);
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700821
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700822 actions.add(copyTtlInAction);
Sangho Shin463bee52014-09-29 15:14:43 -0700823 actions.add(popAction);
824 actions.add(decNwTtlAction);
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700825 }
826 }
Sangho Shinc8d2f592014-09-30 16:53:57 -0700827 else {
828 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
829 actions.add(decMplsTtlAction);
830 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700831 }
Sangho Shin43cee112014-09-25 16:43:34 -0700832 GroupAction groupAction = new GroupAction();
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700833 for (String fwdSw : fwdSws)
Sangho Shin43cee112014-09-25 16:43:34 -0700834 groupAction.addSwitch(new Dpid(fwdSw));
835 actions.add(groupAction);
836
837 MatchAction matchAction = new MatchAction(new MatchActionId(0),
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700838 new SwitchPort((long) 0, (short) 0), mplsMatch, actions);
Sangho Shin43cee112014-09-25 16:43:34 -0700839
Sangho Shin5be3e532014-10-03 17:20:58 -0700840 Operator operator = null;
841 if (modified)
842 operator = Operator.MODIFY;
843 else
844 operator = Operator.ADD;
845
Sangho Shin43cee112014-09-25 16:43:34 -0700846 MatchActionOperationEntry maEntry =
Sangho Shin5be3e532014-10-03 17:20:58 -0700847 new MatchActionOperationEntry(operator, matchAction);
Sangho Shin43cee112014-09-25 16:43:34 -0700848
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700849 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700850 getSwId(sw.getDpid().toString()));
851
Sangho Shin5be3e532014-10-03 17:20:58 -0700852 if (sw13 != null) {
853 try {
854 printMatchActionOperationEntry(sw, maEntry);
855 sw13.pushFlow(maEntry);
856 } catch (IOException e) {
857 e.printStackTrace();
858 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700859 }
860
Sangho Shin43cee112014-09-25 16:43:34 -0700861 }
862
Sangho Shin43cee112014-09-25 16:43:34 -0700863 /**
864 * Debugging function to print out the Match Action Entry
Sangho Shinfbc572c2014-10-02 16:37:05 -0700865 *
Sangho Shin43cee112014-09-25 16:43:34 -0700866 * @param maEntry
867 */
Sangho Shinac5ee2b2014-09-28 21:27:20 -0700868 private void printMatchActionOperationEntry(Switch sw,
869 MatchActionOperationEntry maEntry) {
Sangho Shin43cee112014-09-25 16:43:34 -0700870
Sangho Shin0df01982014-09-25 17:11:18 -0700871 StringBuilder logStr = new StringBuilder("In switch " + sw.getDpid() + ", ");
Sangho Shin43cee112014-09-25 16:43:34 -0700872
873 MatchAction ma = maEntry.getTarget();
874 Match m = ma.getMatch();
875 List<Action> actions = ma.getActions();
876
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700877 if (m instanceof Ipv4Match) {
Sangho Shin43cee112014-09-25 16:43:34 -0700878 logStr.append("If the IP matches with ");
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700879 IPv4Net ip = ((Ipv4Match) m).getDestination();
Sangho Shin43cee112014-09-25 16:43:34 -0700880 logStr.append(ip.toString());
881 logStr.append(" then ");
882 }
883 else if (m instanceof MplsMatch) {
884 logStr.append("If the MPLS label matches with ");
885 int mplsLabel = ((MplsMatch) m).getMplsLabel();
886 logStr.append(mplsLabel);
887 logStr.append(" then ");
888 }
889
890 logStr.append(" do { ");
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700891 for (Action action : actions) {
Sangho Shin43cee112014-09-25 16:43:34 -0700892 if (action instanceof CopyTtlInAction) {
893 logStr.append("copy ttl In, ");
894 }
895 else if (action instanceof CopyTtlOutAction) {
896 logStr.append("copy ttl Out, ");
897 }
898 else if (action instanceof DecMplsTtlAction) {
899 logStr.append("Dec MPLS TTL , ");
900 }
901 else if (action instanceof GroupAction) {
902 logStr.append("Forward packet to < ");
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700903 NeighborSet dpids = ((GroupAction) action).getDpids();
Sangho Shin0df01982014-09-25 17:11:18 -0700904 logStr.append(dpids.toString() + ",");
905
Sangho Shin43cee112014-09-25 16:43:34 -0700906 }
907 else if (action instanceof PopMplsAction) {
908 logStr.append("Pop MPLS label, ");
909 }
910 else if (action instanceof PushMplsAction) {
911 logStr.append("Push MPLS label, ");
912 }
913 else if (action instanceof SetMplsIdAction) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700914 int id = ((SetMplsIdAction) action).getMplsId();
Sangho Shin43cee112014-09-25 16:43:34 -0700915 logStr.append("Set MPLS ID as " + id + ", ");
916
917 }
918 }
919
920 log.debug(logStr.toString());
921
Sangho Shineb083032014-09-22 16:11:34 -0700922 }
923
924 /**
925 * Get MPLS label reading the config file
Sangho Shinfbc572c2014-10-02 16:37:05 -0700926 *
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700927 * @param dipid DPID of the switch
Sangho Shineb083032014-09-22 16:11:34 -0700928 * @return MPLS label for the switch
929 */
930
Sangho Shin43cee112014-09-25 16:43:34 -0700931 private String getMplsLabel(String dpid) {
Sangho Shineb083032014-09-22 16:11:34 -0700932
933 String mplsLabel = null;
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700934 for (Switch sw : mutableTopology.getSwitches()) {
Sangho Shin43cee112014-09-25 16:43:34 -0700935 String dpidStr = sw.getDpid().toString();
936 if (dpid.equals(dpidStr)) {
Sangho Shineb083032014-09-22 16:11:34 -0700937 mplsLabel = sw.getStringAttribute("nodeSid");
938 break;
Sangho Shin1aa93542014-09-22 09:49:44 -0700939 }
940 }
941
Sangho Shineb083032014-09-22 16:11:34 -0700942 return mplsLabel;
Sangho Shin1aa93542014-09-22 09:49:44 -0700943 }
944
Sangho Shineb083032014-09-22 16:11:34 -0700945 /**
Sangho Shin1aa93542014-09-22 09:49:44 -0700946 * The function checks if given IP matches to the given subnet mask
Sangho Shinfbc572c2014-10-02 16:37:05 -0700947 *
Sangho Shin1aa93542014-09-22 09:49:44 -0700948 * @param addr - subnet address to match
949 * @param addr1 - IP address to check
950 * @return true if the IP address matches to the subnet, otherwise false
951 */
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700952 public boolean netMatch(String addr, String addr1) { // addr is subnet
953 // address and addr1 is
954 // ip address. Function
955 // will return true, if
956 // addr1 is within
957 // addr(subnet)
Sangho Shin1aa93542014-09-22 09:49:44 -0700958
959 String[] parts = addr.split("/");
960 String ip = parts[0];
961 int prefix;
962
963 if (parts.length < 2) {
964 prefix = 0;
965 } else {
966 prefix = Integer.parseInt(parts[1]);
967 }
968
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700969 Inet4Address a = null;
970 Inet4Address a1 = null;
Sangho Shin1aa93542014-09-22 09:49:44 -0700971 try {
972 a = (Inet4Address) InetAddress.getByName(ip);
973 a1 = (Inet4Address) InetAddress.getByName(addr1);
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700974 } catch (UnknownHostException e) {
975 }
Sangho Shin1aa93542014-09-22 09:49:44 -0700976
977 byte[] b = a.getAddress();
978 int ipInt = ((b[0] & 0xFF) << 24) |
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700979 ((b[1] & 0xFF) << 16) |
980 ((b[2] & 0xFF) << 8) |
981 ((b[3] & 0xFF) << 0);
Sangho Shin1aa93542014-09-22 09:49:44 -0700982
983 byte[] b1 = a1.getAddress();
984 int ipInt1 = ((b1[0] & 0xFF) << 24) |
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700985 ((b1[1] & 0xFF) << 16) |
986 ((b1[2] & 0xFF) << 8) |
987 ((b1[3] & 0xFF) << 0);
Sangho Shin1aa93542014-09-22 09:49:44 -0700988
989 int mask = ~((1 << (32 - prefix)) - 1);
990
991 if ((ipInt & mask) == (ipInt1 & mask)) {
992 return true;
993 }
994 else {
995 return false;
996 }
997 }
Sangho Shineb083032014-09-22 16:11:34 -0700998
Sangho Shinac5ee2b2014-09-28 21:27:20 -0700999 /**
1000 * Add a routing rule for the host
Sangho Shinfbc572c2014-10-02 16:37:05 -07001001 *
Sangho Shinac5ee2b2014-09-28 21:27:20 -07001002 * @param sw - Switch to add the rule
1003 * @param hostIpAddress Destination host IP address
1004 * @param hostMacAddress Destination host MAC address
1005 */
Sangho Shineb083032014-09-22 16:11:34 -07001006 public void addRouteToHost(Switch sw, int hostIpAddress, byte[] hostMacAddress) {
1007 ipHandler.addRouteToHost(sw, hostIpAddress, hostMacAddress);
1008
1009 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -07001010
Sangho Shin463bee52014-09-29 15:14:43 -07001011 /**
1012 * Add IP packet to a buffer queue
Sangho Shinfbc572c2014-10-02 16:37:05 -07001013 *
Sangho Shin463bee52014-09-29 15:14:43 -07001014 * @param ipv4
1015 */
1016 public void addPacket(IPv4 ipv4) {
Sangho Shin61535402014-10-01 11:37:14 -07001017 ipPacketQueue.add(ipv4);
Sangho Shin463bee52014-09-29 15:14:43 -07001018 }
1019
1020 /**
1021 * Retrieve all packets whose destination is the given address.
Sangho Shinfbc572c2014-10-02 16:37:05 -07001022 *
Sangho Shin463bee52014-09-29 15:14:43 -07001023 * @param destIp Destination address of packets to retrieve
1024 */
1025 public List<IPv4> getIpPacketFromQueue(byte[] destIp) {
1026
1027 List<IPv4> bufferedPackets = new ArrayList<IPv4>();
1028
Sangho Shin61535402014-10-01 11:37:14 -07001029 if (!ipPacketQueue.isEmpty()) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001030 for (IPv4 ip : ipPacketQueue) {
Sangho Shin61535402014-10-01 11:37:14 -07001031 int dest = ip.getDestinationAddress();
1032 IPv4Address ip1 = IPv4Address.of(dest);
1033 IPv4Address ip2 = IPv4Address.of(destIp);
1034 if (ip1.equals(ip2)) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001035 bufferedPackets.add((IPv4) (ipPacketQueue.poll()).clone());
Sangho Shin463bee52014-09-29 15:14:43 -07001036 }
1037 }
1038 }
1039
1040 return bufferedPackets;
1041 }
1042
Sangho Shin2f263692014-09-15 14:09:41 -07001043}