blob: 32ec6c1e7bfc76c2e97faf5baf9442e5ee7de7ef [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;
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07008import java.util.Arrays;
Sangho Shin2f263692014-09-15 14:09:41 -07009import java.util.Collection;
Srikanth Vavilapalli363f1dc2014-09-22 14:30:23 -070010import java.util.HashMap;
Sangho Shin5be3e532014-10-03 17:20:58 -070011import java.util.HashSet;
Sangho Shin2f263692014-09-15 14:09:41 -070012import java.util.Iterator;
13import java.util.List;
14import java.util.Map;
Sangho Shin5be3e532014-10-03 17:20:58 -070015import java.util.Set;
Sangho Shin61535402014-10-01 11:37:14 -070016import java.util.concurrent.ConcurrentLinkedQueue;
Sangho Shin11d4e0f2014-09-30 12:00:33 -070017import java.util.concurrent.ExecutionException;
Sangho Shin43cee112014-09-25 16:43:34 -070018import java.util.concurrent.ScheduledExecutorService;
19import java.util.concurrent.TimeUnit;
Sangho Shin11d4e0f2014-09-30 12:00:33 -070020import java.util.concurrent.TimeoutException;
Sangho Shin2f263692014-09-15 14:09:41 -070021
22import net.floodlightcontroller.core.IFloodlightProviderService;
Sangho Shin9c0f4c32014-09-26 16:02:38 -070023import net.floodlightcontroller.core.IOF13Switch;
Sangho Shin0df01982014-09-25 17:11:18 -070024import net.floodlightcontroller.core.IOF13Switch.NeighborSet;
Sangho Shin11d4e0f2014-09-30 12:00:33 -070025import net.floodlightcontroller.core.internal.OFBarrierReplyFuture;
Sangho Shin2f263692014-09-15 14:09:41 -070026import net.floodlightcontroller.core.module.FloodlightModuleContext;
27import net.floodlightcontroller.core.module.FloodlightModuleException;
28import net.floodlightcontroller.core.module.IFloodlightModule;
29import net.floodlightcontroller.core.module.IFloodlightService;
Sangho Shin43cee112014-09-25 16:43:34 -070030import net.floodlightcontroller.core.util.SingletonTask;
Sangho Shin7330c032014-10-20 10:34:51 -070031import net.floodlightcontroller.restserver.IRestApiService;
Sangho Shin43cee112014-09-25 16:43:34 -070032import net.floodlightcontroller.threadpool.IThreadPoolService;
Sangho Shin15273b62014-10-16 22:22:05 -070033import net.floodlightcontroller.util.MACAddress;
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070034import net.onrc.onos.api.packet.IPacketListener;
Sangho Shin2f263692014-09-15 14:09:41 -070035import net.onrc.onos.api.packet.IPacketService;
Fahad Naeem Khan4444b952014-10-18 22:30:50 -070036import net.onrc.onos.apps.segmentrouting.web.SegmentRoutingWebRoutable;
Sangho Shin2f263692014-09-15 14:09:41 -070037import net.onrc.onos.core.flowprogrammer.IFlowPusherService;
Sangho Shinfbc572c2014-10-02 16:37:05 -070038import net.onrc.onos.core.intent.Path;
Sangho Shin2f263692014-09-15 14:09:41 -070039import net.onrc.onos.core.main.config.IConfigInfoService;
Sangho Shin43cee112014-09-25 16:43:34 -070040import net.onrc.onos.core.matchaction.MatchAction;
41import net.onrc.onos.core.matchaction.MatchActionId;
42import net.onrc.onos.core.matchaction.MatchActionOperationEntry;
Sangho Shin5be3e532014-10-03 17:20:58 -070043import net.onrc.onos.core.matchaction.MatchActionOperations.Operator;
Sangho Shin43cee112014-09-25 16:43:34 -070044import net.onrc.onos.core.matchaction.action.Action;
45import net.onrc.onos.core.matchaction.action.CopyTtlInAction;
46import net.onrc.onos.core.matchaction.action.CopyTtlOutAction;
47import net.onrc.onos.core.matchaction.action.DecMplsTtlAction;
48import net.onrc.onos.core.matchaction.action.DecNwTtlAction;
49import net.onrc.onos.core.matchaction.action.GroupAction;
50import net.onrc.onos.core.matchaction.action.PopMplsAction;
51import net.onrc.onos.core.matchaction.action.PushMplsAction;
52import net.onrc.onos.core.matchaction.action.SetMplsIdAction;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -070053import net.onrc.onos.core.matchaction.match.Ipv4Match;
Sangho Shin43cee112014-09-25 16:43:34 -070054import net.onrc.onos.core.matchaction.match.Match;
55import net.onrc.onos.core.matchaction.match.MplsMatch;
Sangho Shin15273b62014-10-16 22:22:05 -070056import net.onrc.onos.core.matchaction.match.PacketMatch;
57import net.onrc.onos.core.matchaction.match.PacketMatchBuilder;
Sangho Shin2f263692014-09-15 14:09:41 -070058import net.onrc.onos.core.packet.ARP;
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070059import net.onrc.onos.core.packet.Ethernet;
60import net.onrc.onos.core.packet.IPv4;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070061import net.onrc.onos.core.topology.ITopologyListener;
Sangho Shin1aa93542014-09-22 09:49:44 -070062import net.onrc.onos.core.topology.ITopologyService;
Sangho Shinbce900e2014-10-07 17:13:23 -070063import net.onrc.onos.core.topology.Link;
Sangho Shinc8d2f592014-09-30 16:53:57 -070064import net.onrc.onos.core.topology.LinkData;
Sangho Shinbce900e2014-10-07 17:13:23 -070065import net.onrc.onos.core.topology.MastershipData;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070066import net.onrc.onos.core.topology.MutableTopology;
Sangho Shineb083032014-09-22 16:11:34 -070067import net.onrc.onos.core.topology.Port;
Sangho Shinc8d2f592014-09-30 16:53:57 -070068import net.onrc.onos.core.topology.PortData;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070069import net.onrc.onos.core.topology.Switch;
Sangho Shin5be3e532014-10-03 17:20:58 -070070import net.onrc.onos.core.topology.SwitchData;
Sangho Shin1aa93542014-09-22 09:49:44 -070071import net.onrc.onos.core.topology.TopologyEvents;
Srikanth Vavilapalli363f1dc2014-09-22 14:30:23 -070072import net.onrc.onos.core.util.Dpid;
Sangho Shin43cee112014-09-25 16:43:34 -070073import net.onrc.onos.core.util.IPv4Net;
74import net.onrc.onos.core.util.SwitchPort;
Sangho Shin2f263692014-09-15 14:09:41 -070075
Sangho Shin43cee112014-09-25 16:43:34 -070076import org.json.JSONArray;
77import org.json.JSONException;
Saurav Dasa962a692014-10-17 14:52:38 -070078import org.projectfloodlight.openflow.protocol.OFBarrierReply;
Saurav Dasbc594a42014-09-25 20:13:50 -070079import org.projectfloodlight.openflow.types.EthType;
Sangho Shin2f263692014-09-15 14:09:41 -070080import org.projectfloodlight.openflow.types.IPv4Address;
81import org.slf4j.Logger;
82import org.slf4j.LoggerFactory;
83
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070084public class SegmentRoutingManager implements IFloodlightModule,
Srikanth Vavilapalli8c49db72014-10-20 13:35:08 -070085 ITopologyListener, IPacketListener, ISegmentRoutingService {
Sangho Shin2f263692014-09-15 14:09:41 -070086
87 private static final Logger log = LoggerFactory
88 .getLogger(SegmentRoutingManager.class);
Sangho Shin23f898d2014-10-13 16:54:00 -070089
Fahad Naeem Khan5b558f22014-10-16 10:35:20 -070090 private ITopologyService topologyService;
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070091 private IPacketService packetService;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070092 private MutableTopology mutableTopology;
Sangho Shin61535402014-10-01 11:37:14 -070093 private ConcurrentLinkedQueue<IPv4> ipPacketQueue;
Fahad Naeem Khan4444b952014-10-18 22:30:50 -070094 private IRestApiService restApi;
Sangho Shin2f263692014-09-15 14:09:41 -070095 private List<ArpEntry> arpEntries;
Sangho Shineb083032014-09-22 16:11:34 -070096 private ArpHandler arpHandler;
97 private GenericIpHandler ipHandler;
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070098 private IcmpHandler icmpHandler;
Sangho Shin43cee112014-09-25 16:43:34 -070099 private IThreadPoolService threadPool;
100 private SingletonTask discoveryTask;
Sangho Shin23f898d2014-10-13 16:54:00 -0700101 private SingletonTask linkAddTask;
Sangho Shin15273b62014-10-16 22:22:05 -0700102 private SingletonTask testTask;
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700103 private IFloodlightProviderService floodlightProvider;
Sangho Shin2f263692014-09-15 14:09:41 -0700104
Sangho Shinfbc572c2014-10-02 16:37:05 -0700105 private HashMap<Switch, ECMPShortestPathGraph> graphs;
Sangho Shin23f898d2014-10-13 16:54:00 -0700106 private HashMap<String, LinkData> linksDown;
107 private HashMap<String, LinkData> linksToAdd;
Sangho Shin5be3e532014-10-03 17:20:58 -0700108 private ConcurrentLinkedQueue<TopologyEvents> topologyEventQueue;
Sangho Shine020cc32014-10-20 13:28:02 -0700109 private HashMap<String, PolicyInfo> policyTable;
Sangho Shin81655442014-10-20 14:22:46 -0700110 private HashMap<String, TunnelInfo> tunnelTable;
Sangho Shin5b8f5452014-10-20 11:46:01 -0700111
112 private int testMode = 0;
113
Sangho Shinbce900e2014-10-07 17:13:23 -0700114
115 private int numOfEvents = 0;
116 private int numOfEventProcess = 0;
117 private int numOfPopulation = 0;
Sangho Shin99918bd2014-10-08 15:52:35 -0700118 private long matchActionId = 0L;
Sangho Shin58182672014-10-21 13:23:38 -0700119
Sangho Shin23f898d2014-10-13 16:54:00 -0700120 private final int DELAY_TO_ADD_LINK = 10;
Sangho Shin15273b62014-10-16 22:22:05 -0700121 private final int MAX_NUM_LABELS = 3;
Sangho Shinfbc572c2014-10-02 16:37:05 -0700122
Sangho Shin5b8f5452014-10-20 11:46:01 -0700123 private final int POLICY_ADD1 = 1;
124 private final int POLICY_ADD2 = 2;
125 private final int POLICY_REMOVE1 = 3;
126 private final int POLICY_REMOVE2 = 4;
Sangho Shin4b46bcd2014-10-20 15:48:47 -0700127 private final int TUNNEL_REMOVE1 = 5;
128 private final int TUNNEL_REMOVE2 = 6;
Sangho Shin5b8f5452014-10-20 11:46:01 -0700129
130
Sangho Shin7330c032014-10-20 10:34:51 -0700131 // ************************************
132 // IFloodlightModule implementation
133 // ************************************
134
Sangho Shin2f263692014-09-15 14:09:41 -0700135 @Override
136 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Srikanth Vavilapalli8c49db72014-10-20 13:35:08 -0700137 Collection<Class<? extends IFloodlightService>> l = new ArrayList<>();
138 l.add(ISegmentRoutingService.class);
139 return l;
Sangho Shin2f263692014-09-15 14:09:41 -0700140 }
141
142 @Override
143 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Srikanth Vavilapalli8c49db72014-10-20 13:35:08 -0700144 Map<Class<? extends IFloodlightService>, IFloodlightService> m = new HashMap<>();
145 m.put(ISegmentRoutingService.class, this);
146 return m;
Sangho Shin2f263692014-09-15 14:09:41 -0700147 }
148
149 @Override
150 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
151 Collection<Class<? extends IFloodlightService>> l = new ArrayList<Class<? extends IFloodlightService>>();
152
153 l.add(IFloodlightProviderService.class);
154 l.add(IConfigInfoService.class);
155 l.add(ITopologyService.class);
156 l.add(IPacketService.class);
157 l.add(IFlowPusherService.class);
158 l.add(ITopologyService.class);
Fahad Naeem Khan4444b952014-10-18 22:30:50 -0700159 l.add(IRestApiService.class);
Sangho Shin2f263692014-09-15 14:09:41 -0700160
161 return l;
162
163 }
164
165 @Override
166 public void init(FloodlightModuleContext context) throws FloodlightModuleException {
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700167 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Sangho Shineb083032014-09-22 16:11:34 -0700168 arpHandler = new ArpHandler(context, this);
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700169 icmpHandler = new IcmpHandler(context, this);
Sangho Shineb083032014-09-22 16:11:34 -0700170 ipHandler = new GenericIpHandler(context, this);
Sangho Shin2f263692014-09-15 14:09:41 -0700171 arpEntries = new ArrayList<ArpEntry>();
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700172 topologyService = context.getServiceImpl(ITopologyService.class);
Sangho Shin43cee112014-09-25 16:43:34 -0700173 threadPool = context.getServiceImpl(IThreadPoolService.class);
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700174 mutableTopology = topologyService.getTopology();
Sangho Shin61535402014-10-01 11:37:14 -0700175 ipPacketQueue = new ConcurrentLinkedQueue<IPv4>();
Sangho Shinfbc572c2014-10-02 16:37:05 -0700176 graphs = new HashMap<Switch, ECMPShortestPathGraph>();
Sangho Shin23f898d2014-10-13 16:54:00 -0700177 linksDown = new HashMap<String, LinkData>();
178 linksToAdd = new HashMap<String, LinkData>();
Sangho Shin5be3e532014-10-03 17:20:58 -0700179 topologyEventQueue = new ConcurrentLinkedQueue<TopologyEvents>();
Sangho Shin15273b62014-10-16 22:22:05 -0700180 packetService = context.getServiceImpl(IPacketService.class);
Fahad Naeem Khan4444b952014-10-18 22:30:50 -0700181 restApi = context.getServiceImpl(IRestApiService.class);
Sangho Shine020cc32014-10-20 13:28:02 -0700182 policyTable = new HashMap<String, PolicyInfo>();
Sangho Shin81655442014-10-20 14:22:46 -0700183 tunnelTable = new HashMap<String, TunnelInfo>();
Sangho Shin2f263692014-09-15 14:09:41 -0700184
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700185 packetService.registerPacketListener(this);
Sangho Shin15273b62014-10-16 22:22:05 -0700186 topologyService.addListener(this, false);
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700187
Sangho Shin99918bd2014-10-08 15:52:35 -0700188
Sangho Shin2f263692014-09-15 14:09:41 -0700189 }
190
191 @Override
192 public void startUp(FloodlightModuleContext context) throws FloodlightModuleException {
Sangho Shinc8d2f592014-09-30 16:53:57 -0700193 ScheduledExecutorService ses = threadPool.getScheduledExecutor();
Fahad Naeem Khan4444b952014-10-18 22:30:50 -0700194 restApi.addRestletRoutable(new SegmentRoutingWebRoutable());
Sangho Shin2f263692014-09-15 14:09:41 -0700195
Sangho Shinc8d2f592014-09-30 16:53:57 -0700196 discoveryTask = new SingletonTask(ses, new Runnable() {
197 @Override
198 public void run() {
Sangho Shin5be3e532014-10-03 17:20:58 -0700199 handleTopologyChangeEvents();
Sangho Shinc8d2f592014-09-30 16:53:57 -0700200 }
201 });
Sangho Shin23f898d2014-10-13 16:54:00 -0700202
203 linkAddTask = new SingletonTask(ses, new Runnable() {
204 @Override
205 public void run() {
206 delayedAddLink();
207 }
208 });
209
Sangho Shin15273b62014-10-16 22:22:05 -0700210 testTask = new SingletonTask(ses, new Runnable() {
211 @Override
212 public void run() {
213 runTest();
214 }
215 });
216
Sangho Shin5b8f5452014-10-20 11:46:01 -0700217 testMode = POLICY_ADD1;
Fahad Naeem Khan95aa4012014-10-21 14:07:00 -0700218 testTask.reschedule(20, TimeUnit.SECONDS);
Sangho Shin2f263692014-09-15 14:09:41 -0700219 }
220
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700221 @Override
222 public void receive(Switch sw, Port inPort, Ethernet payload) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700223 if (payload.getEtherType() == Ethernet.TYPE_ARP)
224 arpHandler.processPacketIn(sw, inPort, payload);
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700225 if (payload.getEtherType() == Ethernet.TYPE_IPV4) {
Sangho Shin7330c032014-10-20 10:34:51 -0700226 addPacketToPacketBuffer((IPv4) payload.getPayload());
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700227 if (((IPv4) payload.getPayload()).getProtocol() == IPv4.PROTOCOL_ICMP)
228 icmpHandler.processPacketIn(sw, inPort, payload);
229 else
230 ipHandler.processPacketIn(sw, inPort, payload);
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700231 }
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700232 else {
233 log.debug("{}", payload.toString());
234 }
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700235 }
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700236
Sangho Shin2f263692014-09-15 14:09:41 -0700237
Sangho Shin7330c032014-10-20 10:34:51 -0700238 // ************************************
239 // Topology event handlers
240 // ************************************
Sangho Shineb083032014-09-22 16:11:34 -0700241
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700242 /**
243 * Topology events that have been generated.
Sangho Shinfbc572c2014-10-02 16:37:05 -0700244 *
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700245 * @param topologyEvents the generated Topology Events
246 * @see TopologyEvents
247 */
248 public void topologyEvents(TopologyEvents topologyEvents)
249 {
Sangho Shin5be3e532014-10-03 17:20:58 -0700250 topologyEventQueue.add(topologyEvents);
Sangho Shinbce900e2014-10-07 17:13:23 -0700251 discoveryTask.reschedule(100, TimeUnit.MILLISECONDS);
Sangho Shin5be3e532014-10-03 17:20:58 -0700252 }
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700253
Sangho Shin23f898d2014-10-13 16:54:00 -0700254 /**
255 * Process the multiple topology events with some delay (100MS at most for now)
256 *
257 */
Sangho Shin5be3e532014-10-03 17:20:58 -0700258 private void handleTopologyChangeEvents() {
Sangho Shinbce900e2014-10-07 17:13:23 -0700259 numOfEventProcess ++;
260
Sangho Shin51625342014-10-17 09:30:48 -0700261 Collection<LinkData> linkEntriesAddedAll = new ArrayList<LinkData>();
262 Collection<PortData> portEntriesAddedAll = new ArrayList<PortData>();
263 Collection<PortData> portEntriesRemovedAll = new ArrayList<PortData>();
264 Collection<LinkData> linkEntriesRemovedAll = new ArrayList<LinkData>();
265 Collection<SwitchData> switchAddedAll = new ArrayList<SwitchData>();
266 Collection<SwitchData> switchRemovedAll = new ArrayList<SwitchData>();
267 Collection<MastershipData> mastershipRemovedAll = new ArrayList<MastershipData>();
Sangho Shinbce900e2014-10-07 17:13:23 -0700268
Sangho Shin5be3e532014-10-03 17:20:58 -0700269 while (!topologyEventQueue.isEmpty()) {
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700270 // We should handle the events in the order of when they happen
271 // TODO: We need to simulate the final results of multiple events
272 // and shoot only the final state.
273 // Ex: link s1-s2 down, link s1-s2 up --> Do nothing
274 // Ex: ink s1-s2 up, s1-p1,p2 down --> link s1-s2 down
Sangho Shin51625342014-10-17 09:30:48 -0700275
Sangho Shin5be3e532014-10-03 17:20:58 -0700276 TopologyEvents topologyEvents = topologyEventQueue.poll();
Sangho Shin51625342014-10-17 09:30:48 -0700277
278 Collection<LinkData> linkEntriesAdded = topologyEvents.getAddedLinkDataEntries();
279 Collection<PortData> portEntriesAdded = topologyEvents.getAddedPortDataEntries();
280 Collection<PortData> portEntriesRemoved = topologyEvents.getRemovedPortDataEntries();
281 Collection<LinkData> linkEntriesRemoved = topologyEvents.getRemovedLinkDataEntries();
282 Collection<SwitchData> switchAdded = topologyEvents.getAddedSwitchDataEntries();
283 Collection<SwitchData> switchRemoved = topologyEvents.getRemovedSwitchDataEntries();
284 Collection<MastershipData> mastershipRemoved = topologyEvents.getRemovedMastershipDataEntries();
285
286 linkEntriesAddedAll.addAll(linkEntriesAdded);
287 portEntriesAddedAll.addAll(portEntriesAdded);
288 portEntriesRemovedAll.addAll(portEntriesRemoved);
289 linkEntriesRemovedAll.addAll(linkEntriesRemoved);
290 switchAddedAll.addAll(switchAdded);
291 switchRemovedAll.addAll(switchRemoved);
292 mastershipRemovedAll.addAll(mastershipRemoved);
Sangho Shinbce900e2014-10-07 17:13:23 -0700293 numOfEvents++;
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700294
295 if (!portEntriesRemoved.isEmpty()) {
296 processPortRemoval(portEntriesRemoved);
297 }
298
299 if (!linkEntriesRemoved.isEmpty()) {
300 processLinkRemoval(linkEntriesRemoved);
301 }
302
303 if (!switchRemoved.isEmpty()) {
304 processSwitchRemoved(switchRemoved);
305 }
306
307 if (!mastershipRemoved.isEmpty()) {
Sangho Shin23f898d2014-10-13 16:54:00 -0700308 log.debug("Mastership is removed. Check if ports are down also.");
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700309 }
310
311 if (!linkEntriesAdded.isEmpty()) {
Sangho Shin23f898d2014-10-13 16:54:00 -0700312 processLinkAdd(linkEntriesAdded, false);
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700313 }
314
315 if (!portEntriesAdded.isEmpty()) {
316 processPortAdd(portEntriesAdded);
317 }
318
319 if (!switchAdded.isEmpty()) {
320 processSwitchAdd(switchAdded);
321 }
Sangho Shin51625342014-10-17 09:30:48 -0700322
Sangho Shinbce900e2014-10-07 17:13:23 -0700323 }
324
Sangho Shin23f898d2014-10-13 16:54:00 -0700325 // TODO: 100ms is enough to check both mastership removed events
326 // and the port removed events? What if the PORT_STATUS packets comes late?
Sangho Shin51625342014-10-17 09:30:48 -0700327 if (!mastershipRemovedAll.isEmpty()) {
328 if (portEntriesRemovedAll.isEmpty()) {
Saurav Das82e62972014-10-16 14:53:57 -0700329 log.debug("Just mastership is removed. Do not do anthing.");
Sangho Shin23f898d2014-10-13 16:54:00 -0700330 }
331 else {
332 HashMap<String, MastershipData> mastershipToRemove =
333 new HashMap<String, MastershipData>();
Sangho Shin51625342014-10-17 09:30:48 -0700334 for (MastershipData ms: mastershipRemovedAll) {
335 for (PortData port: portEntriesRemovedAll) {
Sangho Shin23f898d2014-10-13 16:54:00 -0700336 // TODO: check ALL ports of the switch are dead ..
337 if (port.getDpid().equals(ms.getDpid())) {
338 mastershipToRemove.put(ms.getDpid().toString(), ms);
339 }
340 }
341 log.debug("Swtich {} is really down.", ms.getDpid());
342 }
343 processMastershipRemoved(mastershipToRemove.values());
344 }
345 }
346
Sangho Shinbce900e2014-10-07 17:13:23 -0700347 log.debug("num events {}, num of process {}, "
348 + "num of Population {}", numOfEvents, numOfEventProcess,
349 numOfPopulation);
350 }
351
352 /**
Sangho Shin99918bd2014-10-08 15:52:35 -0700353 * Process the SwitchAdded events from topologyMananger.
354 * It does nothing. When a switch is added, then link will be added too.
355 * LinkAdded event will handle process all re-computation.
356 *
357 * @param switchAdded
358 */
359 private void processSwitchAdd(Collection<SwitchData> switchAdded) {
360
361 }
362
363 /**
Sangho Shinbce900e2014-10-07 17:13:23 -0700364 * Remove all ports connected to the switch removed
365 *
366 * @param mastershipRemoved master switch info removed
367 */
368 private void processMastershipRemoved(Collection<MastershipData>
369 mastershipRemoved) {
370 for (MastershipData mastership: mastershipRemoved) {
371 Switch sw = mutableTopology.getSwitch(mastership.getDpid());
372 for (Link link: sw.getOutgoingLinks()) {
373 Port dstPort = link.getDstPort();
374 IOF13Switch dstSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
375 getSwId(dstPort.getDpid().toString()));
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700376 if (dstSw != null) {
377 dstSw.removePortFromGroups(dstPort.getNumber());
378 log.debug("MasterSwitch {} is gone: remove port {}", sw.getDpid(), dstPort);
379 }
Sangho Shinbce900e2014-10-07 17:13:23 -0700380 }
Sangho Shin61535402014-10-01 11:37:14 -0700381 }
Sangho Shin23f898d2014-10-13 16:54:00 -0700382
383 linksToAdd.clear();
384 linksDown.clear();
Sangho Shin61535402014-10-01 11:37:14 -0700385 }
Sangho Shinc8d2f592014-09-30 16:53:57 -0700386
Sangho Shinbce900e2014-10-07 17:13:23 -0700387 /**
388 * Remove all ports connected to the switch removed
389 *
390 * @param switchRemoved Switch removed
391 */
Sangho Shin5be3e532014-10-03 17:20:58 -0700392 private void processSwitchRemoved(Collection<SwitchData> switchRemoved) {
Sangho Shin23f898d2014-10-13 16:54:00 -0700393 log.debug("SwitchRemoved event occurred !!!");
Sangho Shin5be3e532014-10-03 17:20:58 -0700394 }
395
Sangho Shin61535402014-10-01 11:37:14 -0700396 /**
Sangho Shin99918bd2014-10-08 15:52:35 -0700397 * Report ports added to driver
Sangho Shinfbc572c2014-10-02 16:37:05 -0700398 *
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700399 * @param portEntries
400 */
401 private void processPortAdd(Collection<PortData> portEntries) {
Sangho Shin99918bd2014-10-08 15:52:35 -0700402 // TODO: do we need to add ports with delay?
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700403 for (PortData port : portEntries) {
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700404 Dpid dpid = port.getDpid();
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700405
Sangho Shinfbc572c2014-10-02 16:37:05 -0700406 IOF13Switch sw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700407 getSwId(port.getDpid().toString()));
Sangho Shin815af0c2014-10-10 13:05:45 -0700408 if (sw != null) {
Sangho Shin721ca042014-10-09 13:03:40 -0700409 sw.addPortToGroups(port.getPortNumber());
Sangho Shin15273b62014-10-16 22:22:05 -0700410 //log.debug("Add port {} to switch {}", port, dpid);
Sangho Shin815af0c2014-10-10 13:05:45 -0700411 }
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700412 }
413 }
414
415 /**
416 * Reports ports of new links to driver and recalculate ECMP SPG
Sangho Shin23f898d2014-10-13 16:54:00 -0700417 * If the link to add was removed before, then we just schedule the add link
418 * event and do not recompute the path now.
Sangho Shinfbc572c2014-10-02 16:37:05 -0700419 *
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700420 * @param linkEntries
421 */
Sangho Shin23f898d2014-10-13 16:54:00 -0700422 private void processLinkAdd(Collection<LinkData> linkEntries, boolean delayed) {
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700423
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700424 for (LinkData link : linkEntries) {
Sangho Shin5be3e532014-10-03 17:20:58 -0700425
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700426 SwitchPort srcPort = link.getSrc();
427 SwitchPort dstPort = link.getDst();
428
Sangho Shin23f898d2014-10-13 16:54:00 -0700429 String key = srcPort.getDpid().toString() +
430 dstPort.getDpid().toString();
431 if (!delayed) {
432 if (linksDown.containsKey(key)) {
433 linksToAdd.put(key, link);
434 linksDown.remove(key);
435 linkAddTask.reschedule(DELAY_TO_ADD_LINK, TimeUnit.SECONDS);
436 log.debug("Add link {} with 5 sec delay", link);
437 // TODO: What if we have multiple events of add link:
438 // one is new link add, the other one is link up for
439 // broken link? ECMPSPG function cannot deal with it for now
440 return;
441 }
442 }
443 else {
444 if (linksDown.containsKey(key)) {
445 linksToAdd.remove(key);
446 log.debug("Do not add the link {}: it is down again!", link);
447 return;
448 }
449 }
450
Sangho Shinfbc572c2014-10-02 16:37:05 -0700451 IOF13Switch srcSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700452 getSwId(srcPort.getDpid().toString()));
Sangho Shinfbc572c2014-10-02 16:37:05 -0700453 IOF13Switch dstSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700454 getSwId(dstPort.getDpid().toString()));
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700455
Sangho Shin815af0c2014-10-10 13:05:45 -0700456 if ((srcSw == null) || (dstSw == null))
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700457 continue;
458
459 srcSw.addPortToGroups(srcPort.getPortNumber());
460 dstSw.addPortToGroups(dstPort.getPortNumber());
Sangho Shin5be3e532014-10-03 17:20:58 -0700461
Sangho Shin15273b62014-10-16 22:22:05 -0700462 //log.debug("Add a link port {} to switch {} to add link {}", srcPort, srcSw,
463 // link);
464 //log.debug("Add a link port {} to switch {} to add link {}", dstPort, dstSw,
465 // link);
Sangho Shin815af0c2014-10-10 13:05:45 -0700466
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700467 }
Sangho Shinbce900e2014-10-07 17:13:23 -0700468 populateEcmpRoutingRules(false);
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700469 }
470
471 /**
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700472 * Check if all links are gone b/w the two switches. If all links are gone,
473 * then we need to recalculate the path. Otherwise, just report link failure
474 * to the driver.
Sangho Shinfbc572c2014-10-02 16:37:05 -0700475 *
Sangho Shin61535402014-10-01 11:37:14 -0700476 * @param linkEntries
477 */
478 private void processLinkRemoval(Collection<LinkData> linkEntries) {
Sangho Shinbce900e2014-10-07 17:13:23 -0700479 boolean recomputationRequired = false;
480
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700481 for (LinkData link : linkEntries) {
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700482 SwitchPort srcPort = link.getSrc();
483 SwitchPort dstPort = link.getDst();
Sangho Shinc8d2f592014-09-30 16:53:57 -0700484
Sangho Shinfbc572c2014-10-02 16:37:05 -0700485 IOF13Switch srcSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700486 getSwId(srcPort.getDpid().toString()));
Sangho Shinfbc572c2014-10-02 16:37:05 -0700487 IOF13Switch dstSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700488 getSwId(dstPort.getDpid().toString()));
Sangho Shin815af0c2014-10-10 13:05:45 -0700489 if ((srcSw == null) || (dstSw == null))
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700490 /* If this link is not between two switches, ignore it */
491 continue;
Sangho Shin23f898d2014-10-13 16:54:00 -0700492
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700493 srcSw.removePortFromGroups(srcPort.getPortNumber());
494 dstSw.removePortFromGroups(dstPort.getPortNumber());
Sangho Shin815af0c2014-10-10 13:05:45 -0700495 log.debug("Remove port {} from switch {}", srcPort, srcSw);
496 log.debug("Remove port {} from switch {}", dstPort, dstSw);
497
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700498 Switch srcSwitch = mutableTopology.getSwitch(srcPort.getDpid());
499 if (srcSwitch.getLinkToNeighbor(dstPort.getDpid()) == null) {
Sangho Shinbce900e2014-10-07 17:13:23 -0700500 // TODO: it is only for debugging purpose.
Sangho Shin99918bd2014-10-08 15:52:35 -0700501 // We just need to call populateEcmpRoutingRules() and return;
Sangho Shinbce900e2014-10-07 17:13:23 -0700502 recomputationRequired = true;
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700503 log.debug("All links are gone b/w {} and {}", srcPort.getDpid(),
Sangho Shin5be3e532014-10-03 17:20:58 -0700504 dstPort.getDpid());
Sangho Shinc8d2f592014-09-30 16:53:57 -0700505 }
Sangho Shin23f898d2014-10-13 16:54:00 -0700506
507 String key = link.getSrc().getDpid().toString()+
508 link.getDst().getDpid().toString();
509 if (!linksDown.containsKey(key)) {
510 linksDown.put(key, link);
511 }
Sangho Shinc8d2f592014-09-30 16:53:57 -0700512 }
Sangho Shinbce900e2014-10-07 17:13:23 -0700513
514 if (recomputationRequired)
515 populateEcmpRoutingRules(false);
Sangho Shin61535402014-10-01 11:37:14 -0700516 }
Sangho Shinc8d2f592014-09-30 16:53:57 -0700517
Sangho Shin61535402014-10-01 11:37:14 -0700518 /**
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700519 * report ports removed to the driver immediately
Sangho Shinfbc572c2014-10-02 16:37:05 -0700520 *
Sangho Shin61535402014-10-01 11:37:14 -0700521 * @param portEntries
522 */
523 private void processPortRemoval(Collection<PortData> portEntries) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700524 for (PortData port : portEntries) {
Sangho Shin61535402014-10-01 11:37:14 -0700525 Dpid dpid = port.getDpid();
Sangho Shin61535402014-10-01 11:37:14 -0700526
Sangho Shinfbc572c2014-10-02 16:37:05 -0700527 IOF13Switch sw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin61535402014-10-01 11:37:14 -0700528 getSwId(port.getDpid().toString()));
Sangho Shin815af0c2014-10-10 13:05:45 -0700529 if (sw != null) {
Sangho Shinfbc572c2014-10-02 16:37:05 -0700530 sw.removePortFromGroups(port.getPortNumber());
Sangho Shin815af0c2014-10-10 13:05:45 -0700531 log.debug("Remove port {} from switch {}", port, dpid);
532 }
Sangho Shin61535402014-10-01 11:37:14 -0700533 }
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700534 }
Sangho Shin1aa93542014-09-22 09:49:44 -0700535
536 /**
Sangho Shin7330c032014-10-20 10:34:51 -0700537 * Add the link immediately
538 * The function is scheduled when link add event happens and called
539 * DELAY_TO_ADD_LINK seconds after the event to avoid link flip-flop.
540 */
541 private void delayedAddLink() {
542
543 processLinkAdd(linksToAdd.values(), true);
544
545 }
546
547
548 // ************************************
549 // ECMP shorted path routing functions
550 // ************************************
551
552 /**
Sangho Shin43cee112014-09-25 16:43:34 -0700553 * Populate routing rules walking through the ECMP shortest paths
Sangho Shinfbc572c2014-10-02 16:37:05 -0700554 *
Sangho Shin99918bd2014-10-08 15:52:35 -0700555 * @param modified if true, it "modifies" the rules
Sangho Shin1aa93542014-09-22 09:49:44 -0700556 */
Sangho Shin5be3e532014-10-03 17:20:58 -0700557 private void populateEcmpRoutingRules(boolean modified) {
558 graphs.clear();
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700559 Iterable<Switch> switches = mutableTopology.getSwitches();
Sangho Shin43cee112014-09-25 16:43:34 -0700560 for (Switch sw : switches) {
561 ECMPShortestPathGraph ecmpSPG = new ECMPShortestPathGraph(sw);
Sangho Shinfbc572c2014-10-02 16:37:05 -0700562 graphs.put(sw, ecmpSPG);
563 //log.debug("ECMPShortestPathGraph is computed for switch {}",
564 // HexString.toHexString(sw.getDpid().value()));
Sangho Shin5be3e532014-10-03 17:20:58 -0700565 populateEcmpRoutingRulesForPath(sw, ecmpSPG, modified);
Sangho Shinfbc572c2014-10-02 16:37:05 -0700566 }
Sangho Shinbce900e2014-10-07 17:13:23 -0700567 numOfPopulation++;
Sangho Shinfbc572c2014-10-02 16:37:05 -0700568 }
Sangho Shin1aa93542014-09-22 09:49:44 -0700569
Sangho Shin99918bd2014-10-08 15:52:35 -0700570 /**
571 * populate routing rules to forward packets from the switch given to
572 * all other switches.
573 *
574 * @param sw source switch
575 * @param ecmpSPG shortest path from the the source switch to all others
576 * @param modified modification flag
577 */
Sangho Shinfbc572c2014-10-02 16:37:05 -0700578 private void populateEcmpRoutingRulesForPath(Switch sw,
Sangho Shin5be3e532014-10-03 17:20:58 -0700579 ECMPShortestPathGraph ecmpSPG, boolean modified) {
Sangho Shin43cee112014-09-25 16:43:34 -0700580
Sangho Shinfbc572c2014-10-02 16:37:05 -0700581 HashMap<Integer, HashMap<Switch, ArrayList<ArrayList<Dpid>>>> switchVia =
582 ecmpSPG.getAllLearnedSwitchesAndVia();
583 for (Integer itrIdx : switchVia.keySet()) {
584 //log.debug("ECMPShortestPathGraph:Switches learned in "
585 // + "Iteration{} from switch {}:",
586 // itrIdx,
587 // HexString.toHexString(sw.getDpid().value()));
588 HashMap<Switch, ArrayList<ArrayList<Dpid>>> swViaMap =
589 switchVia.get(itrIdx);
590 for (Switch targetSw : swViaMap.keySet()) {
Sangho Shin5be3e532014-10-03 17:20:58 -0700591 //log.debug("ECMPShortestPathGraph:****switch {} via:",
592 // HexString.toHexString(targetSw.getDpid().value()));
Sangho Shinfbc572c2014-10-02 16:37:05 -0700593 String destSw = sw.getDpid().toString();
594 List<String> fwdToSw = new ArrayList<String>();
595
Sangho Shinfbc572c2014-10-02 16:37:05 -0700596 for (ArrayList<Dpid> via : swViaMap.get(targetSw)) {
Sangho Shin5be3e532014-10-03 17:20:58 -0700597 //log.debug("ECMPShortestPathGraph:******{}) {}", ++i, via);
Sangho Shinfbc572c2014-10-02 16:37:05 -0700598 if (via.isEmpty()) {
599 fwdToSw.add(destSw);
Sangho Shin43cee112014-09-25 16:43:34 -0700600 }
Sangho Shinfbc572c2014-10-02 16:37:05 -0700601 else {
602 fwdToSw.add(via.get(0).toString());
603 }
Sangho Shin43cee112014-09-25 16:43:34 -0700604 }
Sangho Shin5be3e532014-10-03 17:20:58 -0700605 setRoutingRule(targetSw, destSw, fwdToSw, modified);
Sangho Shineb083032014-09-22 16:11:34 -0700606 }
Sangho Shinfbc572c2014-10-02 16:37:05 -0700607
608 // Send Barrier Message and make sure all rules are set
609 // before we set the rules to next routers
Saurav Dasa962a692014-10-17 14:52:38 -0700610 // TODO: barriers to all switches in this update stage
Sangho Shinfbc572c2014-10-02 16:37:05 -0700611 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
612 getSwId(sw.getDpid().toString()));
Sangho Shin5be3e532014-10-03 17:20:58 -0700613 if (sw13 != null) {
Saurav Dasa962a692014-10-17 14:52:38 -0700614 OFBarrierReplyFuture replyFuture = null;
Sangho Shin5be3e532014-10-03 17:20:58 -0700615 try {
Saurav Dasa962a692014-10-17 14:52:38 -0700616 replyFuture = sw13.sendBarrier();
Sangho Shin5be3e532014-10-03 17:20:58 -0700617 } catch (IOException e) {
Saurav Dasa962a692014-10-17 14:52:38 -0700618 log.error("Error sending barrier request to switch {}",
619 sw13.getId(), e.getCause());
Sangho Shin5be3e532014-10-03 17:20:58 -0700620 }
Saurav Dasa962a692014-10-17 14:52:38 -0700621 OFBarrierReply br = null;
622 try {
623 br = replyFuture.get(2, TimeUnit.SECONDS);
624 } catch (TimeoutException | InterruptedException | ExecutionException e) {
625 // XXX for some reason these exceptions are not being thrown
626 }
627 if (br == null) {
628 log.warn("Did not receive barrier-reply from {}", sw13.getId());
629 // XXX take corrective action
630 }
631
Sangho Shinfbc572c2014-10-02 16:37:05 -0700632 }
633 }
634
635 }
636
Sangho Shinfbc572c2014-10-02 16:37:05 -0700637 /**
638 *
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700639 * Set routing rules in targetSw {forward packets to fwdToSw switches in
640 * order to send packets to destSw} - If the target switch is an edge router
641 * and final destnation switch is also an edge router, then set IP
642 * forwarding rules to subnets - If only the target switch is an edge
643 * router, then set IP forwarding rule to the transit router loopback IP
644 * address - If the target is a transit router, then just set the MPLS
645 * forwarding rule
Sangho Shinfbc572c2014-10-02 16:37:05 -0700646 *
Sangho Shin43cee112014-09-25 16:43:34 -0700647 * @param targetSw Switch to set the rules
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700648 * @param destSw Final destination switches
Sangho Shin43cee112014-09-25 16:43:34 -0700649 * @param fwdToSw next hop switches
650 */
Sangho Shin99918bd2014-10-08 15:52:35 -0700651 private void setRoutingRule(Switch targetSw, String destSw,
652 List<String> fwdToSw, boolean modified) {
Sangho Shin43cee112014-09-25 16:43:34 -0700653
Sangho Shin43cee112014-09-25 16:43:34 -0700654 if (fwdToSw.isEmpty()) {
655 fwdToSw.add(destSw);
656 }
657
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700658 // if both target SW and dest SW are an edge router, then set IP table
Sangho Shin43cee112014-09-25 16:43:34 -0700659 if (IsEdgeRouter(targetSw.getDpid().toString()) &&
660 IsEdgeRouter(destSw)) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700661 // We assume that there is at least one transit router b/w edge
662 // routers
Sangho Shin43cee112014-09-25 16:43:34 -0700663 Switch destSwitch = mutableTopology.getSwitch(new Dpid(destSw));
664 String subnets = destSwitch.getStringAttribute("subnets");
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700665 setIpTableRouterSubnet(targetSw, subnets, getMplsLabel(destSw)
Sangho Shin5be3e532014-10-03 17:20:58 -0700666 , fwdToSw, modified);
Sangho Shin43cee112014-09-25 16:43:34 -0700667
Sangho Shin43cee112014-09-25 16:43:34 -0700668 String routerIp = destSwitch.getStringAttribute("routerIp");
Sangho Shin5be3e532014-10-03 17:20:58 -0700669 setIpTableRouter(targetSw, routerIp, getMplsLabel(destSw), fwdToSw,
670 null, modified);
Sangho Shin721ca042014-10-09 13:03:40 -0700671 // Edge router can be a transit router
672 setMplsTable(targetSw, getMplsLabel(destSw), fwdToSw, modified);
Sangho Shin43cee112014-09-25 16:43:34 -0700673 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700674 // Only if the target switch is the edge router, then set the IP rules
Sangho Shin43cee112014-09-25 16:43:34 -0700675 else if (IsEdgeRouter(targetSw.getDpid().toString())) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700676 // We assume that there is at least one transit router b/w edge
677 // routers
Sangho Shin43cee112014-09-25 16:43:34 -0700678 Switch destSwitch = mutableTopology.getSwitch(new Dpid(destSw));
679 String routerIp = destSwitch.getStringAttribute("routerIp");
Sangho Shin5be3e532014-10-03 17:20:58 -0700680 setIpTableRouter(targetSw, routerIp, getMplsLabel(destSw), fwdToSw,
681 null, modified);
Sangho Shin721ca042014-10-09 13:03:40 -0700682 // Edge router can be a transit router
683 setMplsTable(targetSw, getMplsLabel(destSw), fwdToSw, modified);
Sangho Shin43cee112014-09-25 16:43:34 -0700684 }
685 // if it is a transit router, then set rules in the MPLS table
686 else {
Sangho Shin5be3e532014-10-03 17:20:58 -0700687 setMplsTable(targetSw, getMplsLabel(destSw), fwdToSw, modified);
Sangho Shin43cee112014-09-25 16:43:34 -0700688 }
689
690 }
691
Sangho Shinfbc572c2014-10-02 16:37:05 -0700692 /**
693 * Set IP forwarding rule to the gateway of each subnet of switches
694 *
695 * @param targetSw Switch to set rules
696 * @param subnets subnet information
697 * @param mplsLabel destination MPLS label
698 * @param fwdToSw router to forward packets to
699 */
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700700 private void setIpTableRouterSubnet(Switch targetSw, String subnets,
Sangho Shin5be3e532014-10-03 17:20:58 -0700701 String mplsLabel, List<String> fwdToSw, boolean modified) {
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700702
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700703 Collection<MatchActionOperationEntry> entries =
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700704 new ArrayList<MatchActionOperationEntry>();
705
706 try {
707 JSONArray arry = new JSONArray(subnets);
708 for (int i = 0; i < arry.length(); i++) {
709 String subnetIp = (String) arry.getJSONObject(i).get("subnetIp");
Sangho Shin5be3e532014-10-03 17:20:58 -0700710 setIpTableRouter(targetSw, subnetIp, mplsLabel, fwdToSw, entries,
711 modified);
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700712 }
713 } catch (JSONException e) {
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700714 e.printStackTrace();
715 }
716
717 if (!entries.isEmpty()) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700718 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700719 getSwId(targetSw.getDpid().toString()));
720
Sangho Shin721ca042014-10-09 13:03:40 -0700721 if (sw13 != null) {
722 try {
723 sw13.pushFlows(entries);
724 } catch (IOException e) {
725 e.printStackTrace();
726 }
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700727 }
728 }
729
730 }
731
Sangho Shin43cee112014-09-25 16:43:34 -0700732 /**
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700733 * Set IP forwarding rule - If the destination is the next hop, then do not
734 * push MPLS, just decrease the NW TTL - Otherwise, push MPLS label and set
735 * the MPLS ID
Sangho Shinfbc572c2014-10-02 16:37:05 -0700736 *
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700737 * @param sw target switch to set rules
Sangho Shin43cee112014-09-25 16:43:34 -0700738 * @param subnetIp Match IP address
739 * @param mplsLabel MPLS label of final destination router
740 * @param fwdToSws next hop routers
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700741 * @param entries
Sangho Shin43cee112014-09-25 16:43:34 -0700742 */
743 private void setIpTableRouter(Switch sw, String subnetIp, String mplsLabel,
Sangho Shin5be3e532014-10-03 17:20:58 -0700744 List<String> fwdToSws, Collection<MatchActionOperationEntry> entries,
745 boolean modified) {
Sangho Shin43cee112014-09-25 16:43:34 -0700746
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700747 Ipv4Match ipMatch = new Ipv4Match(subnetIp);
Sangho Shin43cee112014-09-25 16:43:34 -0700748 List<Action> actions = new ArrayList<>();
Sangho Shin721ca042014-10-09 13:03:40 -0700749 GroupAction groupAction = new GroupAction();
Sangho Shin43cee112014-09-25 16:43:34 -0700750
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700751 // If destination SW is the same as the fwd SW, then do not push MPLS
752 // label
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700753 if (fwdToSws.size() > 1) {
Sangho Shin43cee112014-09-25 16:43:34 -0700754 PushMplsAction pushMplsAction = new PushMplsAction();
755 SetMplsIdAction setIdAction = new SetMplsIdAction(Integer.parseInt(mplsLabel));
756 CopyTtlOutAction copyTtlOutAction = new CopyTtlOutAction();
Sangho Shin463bee52014-09-29 15:14:43 -0700757 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
Sangho Shin43cee112014-09-25 16:43:34 -0700758
Sangho Shin62ce5c12014-10-08 16:24:40 -0700759 //actions.add(pushMplsAction);
760 //actions.add(copyTtlOutAction);
761 //actions.add(decMplsTtlAction);
Saurav Das82e62972014-10-16 14:53:57 -0700762 // actions.add(setIdAction);
Sangho Shin721ca042014-10-09 13:03:40 -0700763 groupAction.setEdgeLabel(Integer.parseInt(mplsLabel));
Sangho Shin43cee112014-09-25 16:43:34 -0700764 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700765 else {
766 String fwdToSw = fwdToSws.get(0);
767 if (getMplsLabel(fwdToSw).equals(mplsLabel)) {
768 DecNwTtlAction decTtlAction = new DecNwTtlAction(1);
769 actions.add(decTtlAction);
770 }
771 else {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700772 SetMplsIdAction setIdAction = new SetMplsIdAction(
773 Integer.parseInt(mplsLabel));
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700774 CopyTtlOutAction copyTtlOutAction = new CopyTtlOutAction();
Sangho Shin463bee52014-09-29 15:14:43 -0700775 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700776
Sangho Shin62ce5c12014-10-08 16:24:40 -0700777 //actions.add(pushMplsAction);
778 //actions.add(copyTtlOutAction);
779 //actions.add(decMplsTtlAction);
Saurav Das82e62972014-10-16 14:53:57 -0700780 // actions.add(setIdAction);
Sangho Shin721ca042014-10-09 13:03:40 -0700781 groupAction.setEdgeLabel(Integer.parseInt(mplsLabel));
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700782 }
783 }
Sangho Shin43cee112014-09-25 16:43:34 -0700784
Sangho Shin43cee112014-09-25 16:43:34 -0700785 for (String fwdSw : fwdToSws) {
786 groupAction.addSwitch(new Dpid(fwdSw));
787 }
788 actions.add(groupAction);
789
Sangho Shin99918bd2014-10-08 15:52:35 -0700790 MatchAction matchAction = new MatchAction(new MatchActionId(matchActionId++),
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700791 new SwitchPort((long) 0, (short) 0), ipMatch, actions);
Sangho Shin43cee112014-09-25 16:43:34 -0700792
Sangho Shin5be3e532014-10-03 17:20:58 -0700793 Operator operator = null;
794 if (modified)
795 operator = Operator.MODIFY;
796 else
797 operator = Operator.ADD;
798
Sangho Shin43cee112014-09-25 16:43:34 -0700799 MatchActionOperationEntry maEntry =
Sangho Shin5be3e532014-10-03 17:20:58 -0700800 new MatchActionOperationEntry(operator, matchAction);
Sangho Shin43cee112014-09-25 16:43:34 -0700801
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700802 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700803 getSwId(sw.getDpid().toString()));
804
Sangho Shin5be3e532014-10-03 17:20:58 -0700805 if (sw13 != null) {
806 try {
Sangho Shinbce900e2014-10-07 17:13:23 -0700807 //printMatchActionOperationEntry(sw, maEntry);
Sangho Shin5be3e532014-10-03 17:20:58 -0700808 if (entries != null)
809 entries.add(maEntry);
810 else
811 sw13.pushFlow(maEntry);
812 } catch (IOException e) {
813 e.printStackTrace();
814 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700815 }
816
Sangho Shin43cee112014-09-25 16:43:34 -0700817 }
818
Sangho Shinac5ee2b2014-09-28 21:27:20 -0700819 /**
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700820 * Set MPLS forwarding rules to MPLS table
821 * </p>
822 * If the destination is the same as the next hop to forward packets then,
823 * pop the MPLS label according to PHP rule. Here, if BoS is set, then
824 * copy TTL In and decrement NW TTL. Otherwise, it just decrement the MPLS
825 * TTL of the another MPLS header.
826 * If the next hop is not the destination, just forward packets to next
827 * hops using Group action.
Sangho Shinfbc572c2014-10-02 16:37:05 -0700828 *
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700829 * @param sw Switch to set the rules
Sangho Shin43cee112014-09-25 16:43:34 -0700830 * @param mplsLabel destination MPLS label
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700831 * @param fwdSws next hop switches
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700832 * */
Sangho Shin5be3e532014-10-03 17:20:58 -0700833 private void setMplsTable(Switch sw, String mplsLabel, List<String> fwdSws,
834 boolean modified) {
Sangho Shin463bee52014-09-29 15:14:43 -0700835
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700836 if (fwdSws.isEmpty())
837 return;
Sangho Shin43cee112014-09-25 16:43:34 -0700838
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700839 Collection<MatchActionOperationEntry> maEntries =
840 new ArrayList<MatchActionOperationEntry>();
841 String fwdSw1 = fwdSws.get(0);
Sangho Shin43cee112014-09-25 16:43:34 -0700842
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700843 if (fwdSws.size() == 1 && mplsLabel.equals(getMplsLabel(fwdSw1))) {
844 // One rule for Bos = 1
845 MplsMatch mplsMatch = new MplsMatch(Integer.parseInt(mplsLabel), true);
846 List<Action> actions = new ArrayList<Action>();
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700847
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700848 PopMplsAction popAction = new PopMplsAction(EthType.IPv4);
849 CopyTtlInAction copyTtlInAction = new CopyTtlInAction();
850 DecNwTtlAction decNwTtlAction = new DecNwTtlAction(1);
851
852 actions.add(copyTtlInAction);
853 actions.add(popAction);
854 actions.add(decNwTtlAction);
855
856 GroupAction groupAction = new GroupAction();
857 groupAction.addSwitch(new Dpid(fwdSw1));
858 actions.add(groupAction);
859
860 MatchAction matchAction = new MatchAction(new MatchActionId(matchActionId++),
861 new SwitchPort((long) 0, (short) 0), mplsMatch, actions);
862 Operator operator = Operator.ADD;
863 MatchActionOperationEntry maEntry =
864 new MatchActionOperationEntry(operator, matchAction);
865 maEntries.add(maEntry);
866
867 // One rule for Bos = 0
Sangho Shin23f898d2014-10-13 16:54:00 -0700868 MplsMatch mplsMatchBos = new MplsMatch(Integer.parseInt(mplsLabel), false);
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700869 List<Action> actionsBos = new ArrayList<Action>();
Sangho Shin15273b62014-10-16 22:22:05 -0700870 PopMplsAction popActionBos = new PopMplsAction(EthType.MPLS_UNICAST);
871 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
872
873 actionsBos.add(copyTtlInAction);
874 actionsBos.add(popActionBos);
875 actionsBos.add(decMplsTtlAction);
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700876 actionsBos.add(groupAction);
877
878 MatchAction matchActionBos = new MatchAction(new MatchActionId(matchActionId++),
879 new SwitchPort((long) 0, (short) 0), mplsMatchBos, actionsBos);
880 MatchActionOperationEntry maEntryBos =
881 new MatchActionOperationEntry(operator, matchActionBos);
882 maEntries.add(maEntryBos);
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700883 }
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700884 else {
885 MplsMatch mplsMatch = new MplsMatch(Integer.parseInt(mplsLabel), false);
886 List<Action> actions = new ArrayList<Action>();
Sangho Shin43cee112014-09-25 16:43:34 -0700887
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700888 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
889 actions.add(decMplsTtlAction);
Sangho Shin43cee112014-09-25 16:43:34 -0700890
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700891 GroupAction groupAction = new GroupAction();
892 for (String fwdSw : fwdSws)
893 groupAction.addSwitch(new Dpid(fwdSw));
894 actions.add(groupAction);
Sangho Shin5be3e532014-10-03 17:20:58 -0700895
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700896 MatchAction matchAction = new MatchAction(new MatchActionId(
897 matchActionId++),
898 new SwitchPort((long) 0, (short) 0), mplsMatch, actions);
899 Operator operator = Operator.ADD;
900 MatchActionOperationEntry maEntry =
901 new MatchActionOperationEntry(operator, matchAction);
902 maEntries.add(maEntry);
Sangho Shine2e9bcd2014-10-13 15:14:18 -0700903
904 // BoS = 1
905 MplsMatch mplsMatchBoS = new MplsMatch(Integer.parseInt(mplsLabel), true);
906 List<Action> actionsBoS = new ArrayList<Action>();
907
908 DecMplsTtlAction decMplsTtlActionBoS = new DecMplsTtlAction(1);
909 actionsBoS.add(decMplsTtlActionBoS);
910
911 GroupAction groupActionBoS = new GroupAction();
912 for (String fwdSw : fwdSws)
913 groupActionBoS.addSwitch(new Dpid(fwdSw));
914 actionsBoS.add(groupActionBoS);
915
916 MatchAction matchActionBos = new MatchAction(new MatchActionId(
917 matchActionId++),
918 new SwitchPort((long) 0, (short) 0), mplsMatchBoS, actionsBoS);
919 MatchActionOperationEntry maEntryBoS =
920 new MatchActionOperationEntry(operator, matchActionBos);
921 maEntries.add(maEntryBoS);
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700922 }
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700923 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700924 getSwId(sw.getDpid().toString()));
925
Sangho Shin5be3e532014-10-03 17:20:58 -0700926 if (sw13 != null) {
927 try {
Sangho Shinbce900e2014-10-07 17:13:23 -0700928 //printMatchActionOperationEntry(sw, maEntry);
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700929 sw13.pushFlows(maEntries);
Sangho Shin5be3e532014-10-03 17:20:58 -0700930 } catch (IOException e) {
931 e.printStackTrace();
932 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700933 }
Sangho Shin43cee112014-09-25 16:43:34 -0700934 }
935
Sangho Shin7330c032014-10-20 10:34:51 -0700936
937 // ************************************
938 // Policy routing classes and functions
939 // ************************************
940
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -0700941 public class PolicyInfo {
Sangho Shin5b8f5452014-10-20 11:46:01 -0700942
Sangho Shin58182672014-10-21 13:23:38 -0700943 public final int TYPE_EXPLICIT = 1;
944 public final int TYPE_AVOID = 2;
945
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -0700946 private String policyId;
947 private PacketMatch match;
948 private int priority;
949 private String tunnelId;
Sangho Shin58182672014-10-21 13:23:38 -0700950 private int type;
Sangho Shin5b8f5452014-10-20 11:46:01 -0700951
Sangho Shin58182672014-10-21 13:23:38 -0700952 public PolicyInfo(String pid, int type, PacketMatch match, int priority,
953 String tid) {
954 this.policyId = pid;
955 this.match = match;
956 this.priority = priority;
957 this.tunnelId = tid;
958 this.type = type;
959 }
Fahad Naeem Khan95aa4012014-10-21 14:07:00 -0700960
961 public PolicyInfo(String pid, PacketMatch match, int priority,
962 String tid) {
963 this.policyId = pid;
964 this.match = match;
965 this.priority = priority;
966 this.tunnelId = tid;
Fahad Naeem Khan788895c2014-10-21 19:00:24 -0700967 this.type = 0;
Fahad Naeem Khan95aa4012014-10-21 14:07:00 -0700968 }
969 public String getPolicyId(){
970 return this.policyId;
971 }
972 public PacketMatch getMatch(){
973 return this.match;
974 }
975 public int getPriority(){
976 return this.priority;
977 }
978 public String getTunnelId(){
979 return this.tunnelId;
980 }
981 public int getType(){
982 return this.type;
983 }
Sangho Shin5b8f5452014-10-20 11:46:01 -0700984 }
985
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -0700986 public class TunnelInfo {
987 private String tunnelId;
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -0700988 private List<Integer> labelIds;
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -0700989 private List<TunnelRouteInfo> routes;
Sangho Shin81655442014-10-20 14:22:46 -0700990
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -0700991 public TunnelInfo(String tid, List<Integer> labelIds, List<TunnelRouteInfo> routes) {
Sangho Shin81655442014-10-20 14:22:46 -0700992 this.tunnelId = tid;
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -0700993 this.labelIds = labelIds;
Sangho Shin81655442014-10-20 14:22:46 -0700994 this.routes = routes;
995 }
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -0700996 public String getTunnelId(){
997 return this.tunnelId;
998 }
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -0700999
1000 public List<Integer> getLabelids() {
1001 return this.labelIds;
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001002 }
1003 public List<TunnelRouteInfo> getRoutes(){
1004 return this.routes;
1005 }
Sangho Shin81655442014-10-20 14:22:46 -07001006 }
1007
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001008 public class TunnelRouteInfo {
Sangho Shin7330c032014-10-20 10:34:51 -07001009
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001010 private String srcSwDpid;
1011 private List<Dpid> fwdSwDpids;
1012 private List<String> route;
Sangho Shin7330c032014-10-20 10:34:51 -07001013
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001014 public TunnelRouteInfo() {
Sangho Shin7330c032014-10-20 10:34:51 -07001015 fwdSwDpids = new ArrayList<Dpid>();
1016 route = new ArrayList<String>();
1017 }
1018
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001019 private void setSrcDpid(String dpid) {
Sangho Shin7330c032014-10-20 10:34:51 -07001020 this.srcSwDpid = dpid;
1021 }
1022
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001023 private void setFwdSwDpid(List<Dpid> dpid) {
Sangho Shin7330c032014-10-20 10:34:51 -07001024 this.fwdSwDpids = dpid;
1025 }
1026
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001027 private void addRoute(String id) {
Sangho Shin7330c032014-10-20 10:34:51 -07001028 route.add(id);
1029 }
1030
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001031 private void setRoute(List<String> r) {
Sangho Shin7330c032014-10-20 10:34:51 -07001032 this.route = r;
1033 }
1034
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001035 public String getSrcSwDpid() {
Sangho Shin7330c032014-10-20 10:34:51 -07001036 return this.srcSwDpid;
1037 }
1038
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001039 public List<Dpid> getFwdSwDpid() {
Sangho Shin7330c032014-10-20 10:34:51 -07001040 return this.fwdSwDpids;
1041 }
1042
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001043 public List<String> getRoute() {
Sangho Shin7330c032014-10-20 10:34:51 -07001044 return this.route;
1045 }
1046 }
1047
Sangho Shin15273b62014-10-16 22:22:05 -07001048 /**
Sangho Shin81655442014-10-20 14:22:46 -07001049 * Return the Tunnel table
1050 *
1051 * @return collection of TunnelInfo
1052 */
1053 public Collection<TunnelInfo> getTunnelTable() {
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001054 return this.tunnelTable.values();
Sangho Shin81655442014-10-20 14:22:46 -07001055 }
Fahad Naeem Khan12fa63a2014-10-21 17:01:27 -07001056
1057 public Collection<PolicyInfo> getPoclicyTable() {
1058 return this.policyTable.values();
1059 }
Sangho Shin81655442014-10-20 14:22:46 -07001060
1061 /**
Sangho Shin5671cbb2014-10-20 22:35:41 -07001062 * Return router DPIDs for the tunnel
1063 *
1064 * @param tid tunnel ID
1065 * @return List of DPID
1066 */
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001067 public List<Integer> getTunnelInfo(String tid) {
Sangho Shin5671cbb2014-10-20 22:35:41 -07001068 TunnelInfo tunnelInfo = tunnelTable.get(tid);
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001069 return tunnelInfo.labelIds;
Sangho Shin5671cbb2014-10-20 22:35:41 -07001070
1071 }
1072
1073 /**
1074 * Get the first group ID for the tunnel for specific source router
1075 * If Segment Stitching was required to create the tunnel, there are
1076 * mutiple source routers.
1077 *
1078 * @param tunnelId ID for the tunnel
1079 * @param dpid source router DPID
1080 * @return the first group ID of the tunnel
1081 */
1082 public int getTunnelGroupId(String tunnelId, String dpid) {
1083 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
1084 getSwId(dpid));
1085
1086 if (sw13 == null) {
1087 return -1;
1088 }
1089 else {
1090 return sw13.getTunnelGroupId(tunnelId);
1091 }
1092 }
1093
1094 /**
Sangho Shin15273b62014-10-16 22:22:05 -07001095 * Create a tunnel for policy routing
1096 * It delivers the node IDs of tunnels to driver.
1097 * Split the node IDs if number of IDs exceeds the limit for stitching.
1098 *
1099 * @param tunnelId Node IDs for the tunnel
1100 * @param Ids tunnel ID
1101 */
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001102 public boolean createTunnel(String tunnelId, List<Integer> labelIds) {
Sangho Shin15273b62014-10-16 22:22:05 -07001103
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001104 if (labelIds.isEmpty() || labelIds.size() < 2) {
Sangho Shin15273b62014-10-16 22:22:05 -07001105 log.debug("Wrong tunnel information");
1106 return false;
1107 }
1108
Sangho Shin55d00e12014-10-20 12:13:07 -07001109 List<String> Ids = new ArrayList<String>();
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001110 for (Integer label : labelIds) {
1111 Ids.add(label.toString());
Sangho Shin55d00e12014-10-20 12:13:07 -07001112 }
1113
Sangho Shin81655442014-10-20 14:22:46 -07001114 List<TunnelRouteInfo> stitchingRule = getStitchingRule(Ids);
Sangho Shin15273b62014-10-16 22:22:05 -07001115 if (stitchingRule == null) {
1116 log.debug("Failed to get the policy rule.");
1117 return false;
1118 }
Sangho Shin81655442014-10-20 14:22:46 -07001119 for (TunnelRouteInfo route: stitchingRule) {
Sangho Shin15273b62014-10-16 22:22:05 -07001120
1121 IOF13Switch targetSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin81655442014-10-20 14:22:46 -07001122 getSwId(route.srcSwDpid));
Sangho Shin15273b62014-10-16 22:22:05 -07001123
1124 if (targetSw == null) {
Sangho Shin81655442014-10-20 14:22:46 -07001125 log.debug("Switch {} is gone.", route.srcSwDpid);
Sangho Shin15273b62014-10-16 22:22:05 -07001126 return false;
1127 }
1128
1129 NeighborSet ns = new NeighborSet();
1130 for (Dpid dpid: route.getFwdSwDpid())
1131 ns.addDpid(dpid);
1132
1133 printTunnelInfo(targetSw, tunnelId, route.getRoute(), ns);
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001134 targetSw.createTunnel(tunnelId, route.getRoute(), ns);
Sangho Shin15273b62014-10-16 22:22:05 -07001135 }
1136
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001137 TunnelInfo tunnelInfo = new TunnelInfo(tunnelId, labelIds, stitchingRule);
Sangho Shin81655442014-10-20 14:22:46 -07001138 tunnelTable.put(tunnelId, tunnelInfo);
Sangho Shin15273b62014-10-16 22:22:05 -07001139
1140 return true;
1141 }
1142
1143 /**
1144 * Set policy table for policy routing
1145 *
1146 * @param sw
1147 * @param mplsLabel
Sangho Shin306633a2014-10-20 14:26:55 -07001148 * @return
Sangho Shin15273b62014-10-16 22:22:05 -07001149 */
Sangho Shin306633a2014-10-20 14:26:55 -07001150 public boolean createPolicy(String pid, MACAddress srcMac, MACAddress dstMac,
Sangho Shin15273b62014-10-16 22:22:05 -07001151 Short etherType, IPv4Net srcIp, IPv4Net dstIp, Byte ipProto,
Sangho Shine020cc32014-10-20 13:28:02 -07001152 Short srcTcpPort, Short dstTcpPort, int priority, String tid) {
Sangho Shin15273b62014-10-16 22:22:05 -07001153
Sangho Shin5b8f5452014-10-20 11:46:01 -07001154 PacketMatchBuilder packetBuilder = new PacketMatchBuilder();
1155
1156 if (srcMac != null)
1157 packetBuilder.setSrcMac(srcMac);
1158 if (dstMac != null)
1159 packetBuilder.setDstMac(dstMac);
Sangho Shin58182672014-10-21 13:23:38 -07001160 if (etherType == null) // Cqpd requires the type of IPV4
1161 packetBuilder.setEtherType(Ethernet.TYPE_IPV4);
1162 else
Sangho Shin5b8f5452014-10-20 11:46:01 -07001163 packetBuilder.setEtherType(etherType);
1164 if (srcIp != null)
1165 packetBuilder.setSrcIp(srcIp.address(), srcIp.prefixLen());
1166 if (dstIp != null)
1167 packetBuilder.setDstIp(dstIp.address(), dstIp.prefixLen());
1168 if (ipProto != null)
1169 packetBuilder.setIpProto(ipProto);
1170 if (srcTcpPort > 0)
1171 packetBuilder.setSrcTcpPort(srcTcpPort);
1172 if (dstTcpPort > 0)
1173 packetBuilder.setDstTcpPort(dstTcpPort);
1174 PacketMatch policyMatch = packetBuilder.build();
Sangho Shin81655442014-10-20 14:22:46 -07001175 TunnelInfo tunnelInfo = tunnelTable.get(tid);
1176 List<TunnelRouteInfo> routes = tunnelInfo.routes;
Sangho Shin5b8f5452014-10-20 11:46:01 -07001177
Sangho Shin81655442014-10-20 14:22:46 -07001178 for (TunnelRouteInfo route : routes) {
Sangho Shin15273b62014-10-16 22:22:05 -07001179 List<Action> actions = new ArrayList<>();
1180 GroupAction groupAction = new GroupAction();
Sangho Shin81655442014-10-20 14:22:46 -07001181 groupAction.setTunnelId(tid);
Sangho Shin15273b62014-10-16 22:22:05 -07001182 actions.add(groupAction);
1183
1184 MatchAction matchAction = new MatchAction(new MatchActionId(
1185 matchActionId++),
Sangho Shin5b8f5452014-10-20 11:46:01 -07001186 new SwitchPort((long) 0, (short) 0), policyMatch, priority,
1187 actions);
Sangho Shin15273b62014-10-16 22:22:05 -07001188 MatchActionOperationEntry maEntry =
1189 new MatchActionOperationEntry(Operator.ADD, matchAction);
1190
1191 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin81655442014-10-20 14:22:46 -07001192 getSwId(route.srcSwDpid));
Sangho Shin15273b62014-10-16 22:22:05 -07001193
1194 if (sw13 != null) {
1195 printMatchActionOperationEntry(sw13, maEntry);
1196 try {
1197 sw13.pushFlow(maEntry);
1198 } catch (IOException e) {
1199 e.printStackTrace();
Sangho Shin306633a2014-10-20 14:26:55 -07001200 return false;
Sangho Shin15273b62014-10-16 22:22:05 -07001201 }
1202 }
1203 }
Sangho Shin5b8f5452014-10-20 11:46:01 -07001204
1205 PolicyInfo policyInfo = new PolicyInfo(pid, policyMatch, priority, tid);
Sangho Shine020cc32014-10-20 13:28:02 -07001206 policyTable.put(pid, policyInfo);
Sangho Shin306633a2014-10-20 14:26:55 -07001207
1208 return true;
Sangho Shin15273b62014-10-16 22:22:05 -07001209 }
1210
1211 /**
Sangho Shin1ad7be02014-10-20 16:56:49 -07001212 * Split the nodes IDs into multiple tunnel if Segment Stitching is required.
1213 * We assume that the first node ID is the one of source router, and the last
1214 * node ID is that of the destination router.
Sangho Shin15273b62014-10-16 22:22:05 -07001215 *
Sangho Shin1ad7be02014-10-20 16:56:49 -07001216 * @param route list of node IDs
1217 * @return List of the TunnelRoutInfo
Sangho Shin15273b62014-10-16 22:22:05 -07001218 */
Sangho Shin81655442014-10-20 14:22:46 -07001219 private List<TunnelRouteInfo> getStitchingRule(List<String> route) {
Sangho Shin15273b62014-10-16 22:22:05 -07001220
1221 if (route.isEmpty() || route.size() < 2)
1222 return null;
1223
Sangho Shin81655442014-10-20 14:22:46 -07001224 List<TunnelRouteInfo> rules = new ArrayList<TunnelRouteInfo>();
Sangho Shin15273b62014-10-16 22:22:05 -07001225
1226 Switch srcSw = this.getSwitchFromNodeId(route.get(0));
1227 String srcDpid = srcSw.getDpid().toString();
1228
1229 if (route.size() <= MAX_NUM_LABELS+1) {
Sangho Shin58182672014-10-21 13:23:38 -07001230 boolean match =false;
1231 TunnelRouteInfo routeInfo = new TunnelRouteInfo();
1232 routeInfo.setSrcDpid(srcSw.getDpid().toString());
1233 String nodeId = route.get(1);
Sangho Shina000c612014-10-21 14:17:59 -07001234 List<Dpid> fwdSwDpids = getForwardingSwitchForNodeId(srcSw, nodeId);
Fahad Naeem Khan95aa4012014-10-21 14:07:00 -07001235 if (fwdSwDpids == null){
1236 return null;
1237 }
Sangho Shin58182672014-10-21 13:23:38 -07001238 for (Dpid dpid: fwdSwDpids) {
1239 if (getMplsLabel(dpid.toString()).toString().equals(nodeId)) {
1240 List<Dpid> fwdSws = new ArrayList<Dpid>();
1241 fwdSws.add(dpid);
1242 routeInfo.setFwdSwDpid(fwdSws);
1243 match = true;
1244 break;
1245 }
1246 }
1247 route.remove(0); // remove source router from the list
1248 if (match) {
1249 route.remove(0);
1250 }
1251 else {
1252 routeInfo.setFwdSwDpid(fwdSwDpids);
1253 }
1254 routeInfo.setRoute(route);
1255 rules.add(routeInfo);
Sangho Shin15273b62014-10-16 22:22:05 -07001256 return rules;
1257 }
1258
1259 int i = 0;
Sangho Shine020cc32014-10-20 13:28:02 -07001260 TunnelRouteInfo routeInfo = new TunnelRouteInfo();
Sangho Shin15273b62014-10-16 22:22:05 -07001261 boolean checkNeighbor = true;
1262
1263 for (String nodeId: route) {
Sangho Shin1ad7be02014-10-20 16:56:49 -07001264 // First node ID is always the source router
Sangho Shin15273b62014-10-16 22:22:05 -07001265 if (i == 0) {
1266 routeInfo.setSrcDpid(srcDpid);
1267 srcSw = getSwitchFromNodeId(nodeId);
1268 i++;
1269 }
Sangho Shin58182672014-10-21 13:23:38 -07001270 else if (i == 1 && checkNeighbor) {
1271 // Check if next node is the neighbor SW of the source SW
1272 List<Dpid> fwdSwDpids = getForwardingSwitchForNodeId(srcSw,
1273 nodeId);
1274 if (fwdSwDpids == null || fwdSwDpids.isEmpty()) {
1275 log.debug("There is no route from node {} to node {}",
1276 srcSw.getDpid(), nodeId);
1277 return null;
Sangho Shin15273b62014-10-16 22:22:05 -07001278 }
Sangho Shin58182672014-10-21 13:23:38 -07001279 // If first Id is one of the neighbors, do not include it to route, but set it as a fwd SW.
1280 boolean match = false;
1281 for (Dpid dpid: fwdSwDpids) {
1282 if (getMplsLabel(dpid.toString()).toString().equals(nodeId)) {
1283 List<Dpid> fwdSws = new ArrayList<Dpid>();
1284 fwdSws.add(dpid);
1285 routeInfo.setFwdSwDpid(fwdSws);
1286 match = true;
1287 break;
1288 }
1289 }
1290 if (!match) {
Sangho Shin15273b62014-10-16 22:22:05 -07001291 routeInfo.addRoute(nodeId);
Sangho Shin58182672014-10-21 13:23:38 -07001292 routeInfo.setFwdSwDpid(fwdSwDpids);
Sangho Shin15273b62014-10-16 22:22:05 -07001293 i++;
1294 }
Sangho Shin58182672014-10-21 13:23:38 -07001295 // we check only the next node ID of the source router
1296 checkNeighbor = false;
Sangho Shin15273b62014-10-16 22:22:05 -07001297 }
1298 else {
1299 routeInfo.addRoute(nodeId);
1300 i++;
1301 }
1302
Sangho Shin1ad7be02014-10-20 16:56:49 -07001303 // If the number of labels reaches the limit, start over the procedure
Sangho Shin15273b62014-10-16 22:22:05 -07001304 if (i == MAX_NUM_LABELS+1) {
Sangho Shin81655442014-10-20 14:22:46 -07001305 rules.add(routeInfo);
Sangho Shine020cc32014-10-20 13:28:02 -07001306 routeInfo = new TunnelRouteInfo();
Sangho Shin15273b62014-10-16 22:22:05 -07001307 srcSw = getSwitchFromNodeId(nodeId);
1308 srcDpid = getSwitchFromNodeId(nodeId).getDpid().toString();
1309 routeInfo.setSrcDpid(srcDpid);
1310 i = 1;
1311 checkNeighbor = true;
1312 }
1313 }
1314
1315 if (i < MAX_NUM_LABELS+1) {
Sangho Shin81655442014-10-20 14:22:46 -07001316 rules.add(routeInfo);
Sangho Shin15273b62014-10-16 22:22:05 -07001317 }
1318
1319 return rules;
1320 }
1321
Sangho Shin5b8f5452014-10-20 11:46:01 -07001322 /**
1323 * Remove all policies applied to specific tunnel.
1324 *
1325 * @param srcMac
1326 * @param dstMac
1327 * @param etherType
1328 * @param srcIp
1329 * @param dstIp
1330 * @param ipProto
1331 * @param srcTcpPort
1332 * @param dstTcpPort
1333 * @param tid
Sangho Shin306633a2014-10-20 14:26:55 -07001334 * @return
Sangho Shin5b8f5452014-10-20 11:46:01 -07001335 */
Sangho Shin306633a2014-10-20 14:26:55 -07001336 public boolean removePolicy(String pid) {
Sangho Shine020cc32014-10-20 13:28:02 -07001337 PolicyInfo policyInfo = policyTable.get(pid);
Sangho Shin5671cbb2014-10-20 22:35:41 -07001338 if (policyInfo == null)
1339 return false;
Sangho Shin5b8f5452014-10-20 11:46:01 -07001340 PacketMatch policyMatch = policyInfo.match;
Sangho Shine020cc32014-10-20 13:28:02 -07001341 String tid = policyInfo.tunnelId;
Sangho Shin5b8f5452014-10-20 11:46:01 -07001342 int priority = policyInfo.priority;
1343
1344 List<Action> actions = new ArrayList<>();
1345 int gropuId = 0; // dummy group ID
1346 GroupAction groupAction = new GroupAction();
1347 groupAction.setGroupId(gropuId);
1348 actions.add(groupAction);
1349
1350 MatchAction matchAction = new MatchAction(new MatchActionId(
1351 matchActionId++),
1352 new SwitchPort((long) 0, (short) 0), policyMatch, priority,
1353 actions);
1354 MatchActionOperationEntry maEntry =
1355 new MatchActionOperationEntry(Operator.REMOVE, matchAction);
1356
Sangho Shin81655442014-10-20 14:22:46 -07001357 TunnelInfo tunnelInfo = tunnelTable.get(tid);
Sangho Shin5671cbb2014-10-20 22:35:41 -07001358 if (tunnelInfo == null)
1359 return false;
Sangho Shin81655442014-10-20 14:22:46 -07001360 List<TunnelRouteInfo> routes = tunnelInfo.routes;
1361
1362 for (TunnelRouteInfo route : routes) {
Sangho Shin5b8f5452014-10-20 11:46:01 -07001363 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin81655442014-10-20 14:22:46 -07001364 getSwId(route.srcSwDpid));
Sangho Shin5b8f5452014-10-20 11:46:01 -07001365
Sangho Shin5671cbb2014-10-20 22:35:41 -07001366 if (sw13 == null) {
1367 return false;
1368 }
1369 else {
Sangho Shin5b8f5452014-10-20 11:46:01 -07001370 printMatchActionOperationEntry(sw13, maEntry);
1371 try {
1372 sw13.pushFlow(maEntry);
1373 } catch (IOException e) {
1374 e.printStackTrace();
1375 log.debug("policy remove failed due to pushFlow() exception");
Sangho Shin306633a2014-10-20 14:26:55 -07001376 return false;
Sangho Shin5b8f5452014-10-20 11:46:01 -07001377 }
1378 }
1379 }
1380
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001381 policyTable.remove(pid);
Sangho Shin5b8f5452014-10-20 11:46:01 -07001382 log.debug("Policy {} is removed.", pid);
Sangho Shin306633a2014-10-20 14:26:55 -07001383 return true;
Sangho Shine020cc32014-10-20 13:28:02 -07001384 }
Sangho Shin5b8f5452014-10-20 11:46:01 -07001385
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001386 /**
1387 * Remove a tunnel
1388 * It removes all groups for the tunnel if the tunnel is not used for any
1389 * policy.
1390 *
1391 * @param tunnelId tunnel ID to remove
1392 */
Sangho Shin306633a2014-10-20 14:26:55 -07001393 public boolean removeTunnel(String tunnelId) {
Sangho Shin55d00e12014-10-20 12:13:07 -07001394
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001395 // Check if the tunnel is used for any policy
1396 for (PolicyInfo policyInfo: policyTable.values()) {
Sangho Shina000c612014-10-21 14:17:59 -07001397 if (policyInfo.tunnelId.equals(tunnelId)) {
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001398 log.debug("Tunnel {} is still used for the policy {}.",
1399 policyInfo.policyId, tunnelId);
1400 return false;
1401 }
1402 }
1403
1404 TunnelInfo tunnelInfo = tunnelTable.get(tunnelId);
Sangho Shin5671cbb2014-10-20 22:35:41 -07001405 if (tunnelInfo == null)
1406 return false;
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001407
1408 List<TunnelRouteInfo> routes = tunnelInfo.routes;
1409 for (TunnelRouteInfo route: routes) {
1410 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
1411 getSwId(route.srcSwDpid));
1412
Sangho Shin5671cbb2014-10-20 22:35:41 -07001413 if (sw13 == null) {
1414 return false;
1415 }
1416 else {
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001417 sw13.removeTunnel(tunnelId);
1418 }
1419 }
1420
1421 tunnelTable.remove(tunnelId);
1422 log.debug("Tunnel {} was removed ", tunnelId);
1423
Sangho Shin306633a2014-10-20 14:26:55 -07001424 return true;
Sangho Shin55d00e12014-10-20 12:13:07 -07001425 }
1426
Sangho Shin7330c032014-10-20 10:34:51 -07001427 // ************************************
1428 // Utility functions
1429 // ************************************
1430
Sangho Shin15273b62014-10-16 22:22:05 -07001431 /**
Sangho Shin7330c032014-10-20 10:34:51 -07001432 * Get the forwarding Switch DPIDs to send packets to a node
Sangho Shin15273b62014-10-16 22:22:05 -07001433 *
Sangho Shin7330c032014-10-20 10:34:51 -07001434 * @param srcSw source switch
1435 * @param nodeId destination node Id
1436 * @return list of switch DPID to forward packets to
Sangho Shin15273b62014-10-16 22:22:05 -07001437 */
Sangho Shin7330c032014-10-20 10:34:51 -07001438 private List<Dpid> getForwardingSwitchForNodeId(Switch srcSw, String nodeId) {
Sangho Shin15273b62014-10-16 22:22:05 -07001439
Sangho Shin7330c032014-10-20 10:34:51 -07001440 List<Dpid> fwdSws = new ArrayList<Dpid>();
1441 Switch destSw = null;
Sangho Shin15273b62014-10-16 22:22:05 -07001442
Sangho Shin7330c032014-10-20 10:34:51 -07001443 destSw = getSwitchFromNodeId(nodeId);
1444
1445 if (destSw == null) {
1446 log.debug("Cannot find the switch with ID {}", nodeId);
1447 return null;
1448 }
1449
1450 ECMPShortestPathGraph ecmpSPG = new ECMPShortestPathGraph(srcSw);
1451
1452 HashMap<Integer, HashMap<Switch, ArrayList<ArrayList<Dpid>>>> switchVia =
1453 ecmpSPG.getAllLearnedSwitchesAndVia();
1454 for (Integer itrIdx : switchVia.keySet()) {
1455 HashMap<Switch, ArrayList<ArrayList<Dpid>>> swViaMap =
1456 switchVia.get(itrIdx);
1457 for (Switch targetSw : swViaMap.keySet()) {
1458 String destSwDpid = destSw.getDpid().toString();
1459 if (targetSw.getDpid().toString().equals(destSwDpid)) {
1460 for (ArrayList<Dpid> via : swViaMap.get(targetSw)) {
1461 if (via.isEmpty()) {
1462 fwdSws.add(destSw.getDpid());
1463 }
1464 else {
Sangho Shina000c612014-10-21 14:17:59 -07001465 Dpid firstVia = via.get(via.size()-1);
1466 fwdSws.add(firstVia);
Sangho Shin7330c032014-10-20 10:34:51 -07001467 }
1468 }
1469 }
1470 }
1471 }
1472
1473 return fwdSws;
Sangho Shin15273b62014-10-16 22:22:05 -07001474 }
1475
Sangho Shin7330c032014-10-20 10:34:51 -07001476 /**
1477 * Get switch for the node Id specified
1478 *
1479 * @param nodeId node ID for switch
1480 * @return Switch
1481 */
1482 private Switch getSwitchFromNodeId(String nodeId) {
Fahad Naeem Khan4444b952014-10-18 22:30:50 -07001483
Sangho Shin7330c032014-10-20 10:34:51 -07001484 for (Switch sw : mutableTopology.getSwitches()) {
1485 String id = sw.getStringAttribute("nodeSid");
1486 if (id.equals(nodeId)) {
1487 return sw;
1488 }
1489 }
1490
1491 return null;
1492 }
Fahad Naeem Khan4444b952014-10-18 22:30:50 -07001493
Sangho Shin43cee112014-09-25 16:43:34 -07001494 /**
Sangho Shin7330c032014-10-20 10:34:51 -07001495 * Convert a string DPID to its Switch Id (integer)
Sangho Shinfbc572c2014-10-02 16:37:05 -07001496 *
Sangho Shin7330c032014-10-20 10:34:51 -07001497 * @param dpid
1498 * @return
Sangho Shin43cee112014-09-25 16:43:34 -07001499 */
Sangho Shin7330c032014-10-20 10:34:51 -07001500 private long getSwId(String dpid) {
Sangho Shin43cee112014-09-25 16:43:34 -07001501
Sangho Shin7330c032014-10-20 10:34:51 -07001502 long swId = 0;
Sangho Shin43cee112014-09-25 16:43:34 -07001503
Sangho Shin7330c032014-10-20 10:34:51 -07001504 String swIdHexStr = "0x"+dpid.substring(dpid.lastIndexOf(":") + 1);
1505 if (swIdHexStr != null)
1506 swId = Integer.decode(swIdHexStr);
Sangho Shin43cee112014-09-25 16:43:34 -07001507
Sangho Shin7330c032014-10-20 10:34:51 -07001508 return swId;
1509 }
Sangho Shin43cee112014-09-25 16:43:34 -07001510
Sangho Shin7330c032014-10-20 10:34:51 -07001511 /**
1512 * Check if the switch is the edge router or not.
1513 *
1514 * @param dpid Dpid of the switch to check
1515 * @return true if it is an edge router, otherwise false
1516 */
1517 private boolean IsEdgeRouter(String dpid) {
Sangho Shin0df01982014-09-25 17:11:18 -07001518
Sangho Shin7330c032014-10-20 10:34:51 -07001519 for (Switch sw : mutableTopology.getSwitches()) {
1520 String dpidStr = sw.getDpid().toString();
1521 if (dpid.equals(dpidStr)) {
1522 /*
1523 String subnetInfo = sw.getStringAttribute("subnets");
1524 if (subnetInfo == null || subnetInfo.equals("[]")) {
1525 return false;
1526 }
1527 else
1528 return true;
1529 */
1530 String isEdge = sw.getStringAttribute("isEdgeRouter");
1531 if (isEdge != null) {
1532 if (isEdge.equals("true"))
1533 return true;
1534 else
1535 return false;
1536 }
Sangho Shin43cee112014-09-25 16:43:34 -07001537 }
1538 }
1539
Sangho Shin7330c032014-10-20 10:34:51 -07001540 return false;
Sangho Shineb083032014-09-22 16:11:34 -07001541 }
1542
1543 /**
1544 * Get MPLS label reading the config file
Sangho Shinfbc572c2014-10-02 16:37:05 -07001545 *
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001546 * @param dipid DPID of the switch
Sangho Shineb083032014-09-22 16:11:34 -07001547 * @return MPLS label for the switch
1548 */
Sangho Shin43cee112014-09-25 16:43:34 -07001549 private String getMplsLabel(String dpid) {
Sangho Shineb083032014-09-22 16:11:34 -07001550
1551 String mplsLabel = null;
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001552 for (Switch sw : mutableTopology.getSwitches()) {
Sangho Shin43cee112014-09-25 16:43:34 -07001553 String dpidStr = sw.getDpid().toString();
1554 if (dpid.equals(dpidStr)) {
Sangho Shineb083032014-09-22 16:11:34 -07001555 mplsLabel = sw.getStringAttribute("nodeSid");
1556 break;
Sangho Shin1aa93542014-09-22 09:49:44 -07001557 }
1558 }
1559
Sangho Shineb083032014-09-22 16:11:34 -07001560 return mplsLabel;
Sangho Shin1aa93542014-09-22 09:49:44 -07001561 }
1562
Sangho Shineb083032014-09-22 16:11:34 -07001563 /**
Sangho Shin1aa93542014-09-22 09:49:44 -07001564 * The function checks if given IP matches to the given subnet mask
Sangho Shinfbc572c2014-10-02 16:37:05 -07001565 *
Sangho Shin1aa93542014-09-22 09:49:44 -07001566 * @param addr - subnet address to match
1567 * @param addr1 - IP address to check
1568 * @return true if the IP address matches to the subnet, otherwise false
1569 */
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001570 public boolean netMatch(String addr, String addr1) { // addr is subnet
1571 // address and addr1 is
1572 // ip address. Function
1573 // will return true, if
1574 // addr1 is within
1575 // addr(subnet)
Sangho Shin1aa93542014-09-22 09:49:44 -07001576
1577 String[] parts = addr.split("/");
1578 String ip = parts[0];
1579 int prefix;
1580
1581 if (parts.length < 2) {
1582 prefix = 0;
1583 } else {
1584 prefix = Integer.parseInt(parts[1]);
1585 }
1586
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001587 Inet4Address a = null;
1588 Inet4Address a1 = null;
Sangho Shin1aa93542014-09-22 09:49:44 -07001589 try {
1590 a = (Inet4Address) InetAddress.getByName(ip);
1591 a1 = (Inet4Address) InetAddress.getByName(addr1);
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001592 } catch (UnknownHostException e) {
1593 }
Sangho Shin1aa93542014-09-22 09:49:44 -07001594
1595 byte[] b = a.getAddress();
1596 int ipInt = ((b[0] & 0xFF) << 24) |
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001597 ((b[1] & 0xFF) << 16) |
1598 ((b[2] & 0xFF) << 8) |
1599 ((b[3] & 0xFF) << 0);
Sangho Shin1aa93542014-09-22 09:49:44 -07001600
1601 byte[] b1 = a1.getAddress();
1602 int ipInt1 = ((b1[0] & 0xFF) << 24) |
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001603 ((b1[1] & 0xFF) << 16) |
1604 ((b1[2] & 0xFF) << 8) |
1605 ((b1[3] & 0xFF) << 0);
Sangho Shin1aa93542014-09-22 09:49:44 -07001606
1607 int mask = ~((1 << (32 - prefix)) - 1);
1608
1609 if ((ipInt & mask) == (ipInt1 & mask)) {
1610 return true;
1611 }
1612 else {
1613 return false;
1614 }
1615 }
Sangho Shineb083032014-09-22 16:11:34 -07001616
Sangho Shinac5ee2b2014-09-28 21:27:20 -07001617 /**
1618 * Add a routing rule for the host
Sangho Shinfbc572c2014-10-02 16:37:05 -07001619 *
Sangho Shinac5ee2b2014-09-28 21:27:20 -07001620 * @param sw - Switch to add the rule
1621 * @param hostIpAddress Destination host IP address
1622 * @param hostMacAddress Destination host MAC address
1623 */
Sangho Shineb083032014-09-22 16:11:34 -07001624 public void addRouteToHost(Switch sw, int hostIpAddress, byte[] hostMacAddress) {
1625 ipHandler.addRouteToHost(sw, hostIpAddress, hostMacAddress);
Sangho Shineb083032014-09-22 16:11:34 -07001626 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -07001627
Sangho Shin463bee52014-09-29 15:14:43 -07001628 /**
1629 * Add IP packet to a buffer queue
Sangho Shinfbc572c2014-10-02 16:37:05 -07001630 *
Sangho Shin463bee52014-09-29 15:14:43 -07001631 * @param ipv4
1632 */
Sangho Shin7330c032014-10-20 10:34:51 -07001633 public void addPacketToPacketBuffer(IPv4 ipv4) {
Sangho Shin61535402014-10-01 11:37:14 -07001634 ipPacketQueue.add(ipv4);
Sangho Shin463bee52014-09-29 15:14:43 -07001635 }
1636
1637 /**
1638 * Retrieve all packets whose destination is the given address.
Sangho Shinfbc572c2014-10-02 16:37:05 -07001639 *
Sangho Shin463bee52014-09-29 15:14:43 -07001640 * @param destIp Destination address of packets to retrieve
1641 */
1642 public List<IPv4> getIpPacketFromQueue(byte[] destIp) {
1643
1644 List<IPv4> bufferedPackets = new ArrayList<IPv4>();
1645
Sangho Shin61535402014-10-01 11:37:14 -07001646 if (!ipPacketQueue.isEmpty()) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001647 for (IPv4 ip : ipPacketQueue) {
Sangho Shin61535402014-10-01 11:37:14 -07001648 int dest = ip.getDestinationAddress();
1649 IPv4Address ip1 = IPv4Address.of(dest);
1650 IPv4Address ip2 = IPv4Address.of(destIp);
1651 if (ip1.equals(ip2)) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001652 bufferedPackets.add((IPv4) (ipPacketQueue.poll()).clone());
Sangho Shin463bee52014-09-29 15:14:43 -07001653 }
1654 }
1655 }
1656
1657 return bufferedPackets;
1658 }
1659
Sangho Shin7330c032014-10-20 10:34:51 -07001660 /**
1661 * Get MAC address to known hosts
1662 *
1663 * @param destinationAddress IP address to get MAC address
1664 * @return MAC Address to given IP address
1665 */
1666 public byte[] getMacAddressFromIpAddress(int destinationAddress) {
1667
1668 // Can't we get the host IP address from the TopologyService ??
1669
1670 Iterator<ArpEntry> iterator = arpEntries.iterator();
1671
1672 IPv4Address ipAddress = IPv4Address.of(destinationAddress);
1673 byte[] ipAddressInByte = ipAddress.getBytes();
1674
1675 while (iterator.hasNext()) {
1676 ArpEntry arpEntry = iterator.next();
1677 byte[] address = arpEntry.targetIpAddress;
1678
1679 IPv4Address a = IPv4Address.of(address);
1680 IPv4Address b = IPv4Address.of(ipAddressInByte);
1681
1682 if (a.equals(b)) {
1683 log.debug("Found an arp entry");
1684 return arpEntry.targetMacAddress;
1685 }
1686 }
1687
1688 return null;
1689 }
1690
1691 /**
1692 * Send an ARP request via ArpHandler
1693 *
1694 * @param destinationAddress
1695 * @param sw
1696 * @param inPort
1697 *
1698 */
1699 public void sendArpRequest(Switch sw, int destinationAddress, Port inPort) {
1700 arpHandler.sendArpRequest(sw, destinationAddress, inPort);
1701 }
1702
1703
1704 // ************************************
1705 // Test functions
1706 // ************************************
1707
Sangho Shin55d00e12014-10-20 12:13:07 -07001708 private void runTest() {
1709
1710 if (testMode == POLICY_ADD1) {
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001711 Integer[] routeArray = {101, 105, 110};
1712 /*List<Dpid> routeList = new ArrayList<Dpid>();
Sangho Shin55d00e12014-10-20 12:13:07 -07001713 for (int i = 0; i < routeArray.length; i++) {
1714 Dpid dpid = getSwitchFromNodeId(routeArray[i]).getDpid();
1715 routeList.add(dpid);
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001716 }*/
Sangho Shin55d00e12014-10-20 12:13:07 -07001717
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001718 if (createTunnel("1", Arrays.asList(routeArray))) {
Sangho Shin55d00e12014-10-20 12:13:07 -07001719 IPv4Net srcIp = new IPv4Net("10.0.1.1/24");
1720 IPv4Net dstIp = new IPv4Net("10.1.2.1/24");
1721
1722 log.debug("Set the policy 1");
Sangho Shine020cc32014-10-20 13:28:02 -07001723 this.createPolicy("1", null, null, Ethernet.TYPE_IPV4, srcIp,
Sangho Shin55d00e12014-10-20 12:13:07 -07001724 dstIp, IPv4.PROTOCOL_ICMP, (short)-1, (short)-1, 10000,
Sangho Shine020cc32014-10-20 13:28:02 -07001725 "1");
Sangho Shin55d00e12014-10-20 12:13:07 -07001726 testMode = POLICY_ADD2;
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001727 testTask.reschedule(5, TimeUnit.SECONDS);
Sangho Shin55d00e12014-10-20 12:13:07 -07001728 }
1729 else {
1730 // retry it
1731 testTask.reschedule(5, TimeUnit.SECONDS);
1732 }
1733 }
1734 else if (testMode == POLICY_ADD2) {
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001735 Integer[] routeArray = {101, 102, 103, 104, 105, 108, 110};
Sangho Shin55d00e12014-10-20 12:13:07 -07001736
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001737 if (createTunnel("2", Arrays.asList(routeArray))) {
Sangho Shin55d00e12014-10-20 12:13:07 -07001738 IPv4Net srcIp = new IPv4Net("10.0.1.1/24");
1739 IPv4Net dstIp = new IPv4Net("10.1.2.1/24");
1740
1741 log.debug("Set the policy 2");
Sangho Shine020cc32014-10-20 13:28:02 -07001742 this.createPolicy("2", null, null, Ethernet.TYPE_IPV4, srcIp,
Sangho Shin55d00e12014-10-20 12:13:07 -07001743 dstIp, IPv4.PROTOCOL_ICMP, (short)-1, (short)-1, 20000,
Sangho Shine020cc32014-10-20 13:28:02 -07001744 "2");
Fahad Naeem Khan95aa4012014-10-21 14:07:00 -07001745 //testMode = POLICY_REMOVE2;
1746 //testTask.reschedule(5, TimeUnit.SECONDS);
Sangho Shin55d00e12014-10-20 12:13:07 -07001747 }
1748 else {
1749 log.debug("Retry it");
1750 testTask.reschedule(5, TimeUnit.SECONDS);
1751 }
1752 }
1753 else if (testMode == POLICY_REMOVE2){
1754 log.debug("Remove the policy 2");
Sangho Shine020cc32014-10-20 13:28:02 -07001755 this.removePolicy("2");
Sangho Shin55d00e12014-10-20 12:13:07 -07001756 testMode = POLICY_REMOVE1;
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001757 testTask.reschedule(5, TimeUnit.SECONDS);
Sangho Shin55d00e12014-10-20 12:13:07 -07001758 }
1759 else if (testMode == POLICY_REMOVE1){
1760 log.debug("Remove the policy 1");
Sangho Shine020cc32014-10-20 13:28:02 -07001761 this.removePolicy("1");
Sangho Shin55d00e12014-10-20 12:13:07 -07001762
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001763 testMode = TUNNEL_REMOVE1;
1764 testTask.reschedule(5, TimeUnit.SECONDS);
1765 }
1766 else if (testMode == TUNNEL_REMOVE1) {
1767 log.debug("Remove the tunnel 1");
1768 this.removeTunnel("1");
1769
1770 testMode = TUNNEL_REMOVE2;
1771 testTask.reschedule(5, TimeUnit.SECONDS);
1772 }
1773 else if (testMode == TUNNEL_REMOVE2) {
1774 log.debug("Remove the tunnel 2");
1775 this.removeTunnel("2");
1776 log.debug("The end of test");
1777 }
Sangho Shin55d00e12014-10-20 12:13:07 -07001778 }
Sangho Shin7330c032014-10-20 10:34:51 -07001779
1780 private void runTest1() {
1781
1782 String dpid1 = "00:00:00:00:00:00:00:01";
1783 String dpid2 = "00:00:00:00:00:00:00:0a";
1784 Switch srcSw = mutableTopology.getSwitch(new Dpid(dpid1));
1785 Switch dstSw = mutableTopology.getSwitch(new Dpid(dpid2));
1786
1787 if (srcSw == null || dstSw == null) {
1788 testTask.reschedule(1, TimeUnit.SECONDS);
1789 log.debug("Switch is gone. Reschedule the test");
1790 return;
1791 }
1792
1793 String[] routeArray = {"101", "102", "105", "108", "110"};
1794 List<String> routeList = new ArrayList<String>();
1795 for (int i = 0; i < routeArray.length; i++)
1796 routeList.add(routeArray[i]);
1797
1798 List<String> optimizedRoute = this.getOptimizedPath(srcSw, dstSw, routeList);
1799
1800 log.debug("Test set is {}", routeList.toString());
1801 log.debug("Result set is {}", optimizedRoute.toString());
1802
1803
1804 }
1805
1806 /**
1807 * print tunnel info - used only for debugging.
1808 * @param targetSw
1809 *
1810 * @param fwdSwDpids
1811 * @param ids
1812 * @param tunnelId
1813 */
Sangho Shine020cc32014-10-20 13:28:02 -07001814 private void printTunnelInfo(IOF13Switch targetSw, String tunnelId,
Sangho Shin7330c032014-10-20 10:34:51 -07001815 List<String> ids, NeighborSet ns) {
1816 StringBuilder logStr = new StringBuilder("In switch " +
1817 targetSw.getId() + ", create a tunnel " + tunnelId + " " + " of push ");
1818 for (String id: ids)
1819 logStr.append(id + "-");
1820 logStr.append(" output to ");
1821 for (Dpid dpid: ns.getDpids())
1822 logStr.append(dpid + " - ");
1823
1824 log.debug(logStr.toString());
1825
1826 }
1827
1828 /**
1829 * Debugging function to print out the Match Action Entry
1830 * @param sw13
1831 *
1832 * @param maEntry
1833 */
1834 private void printMatchActionOperationEntry(
1835 IOF13Switch sw13, MatchActionOperationEntry maEntry) {
1836
1837 StringBuilder logStr = new StringBuilder("In switch " + sw13.getId() + ", ");
1838
1839 MatchAction ma = maEntry.getTarget();
1840 Match m = ma.getMatch();
1841 List<Action> actions = ma.getActions();
1842
1843 if (m instanceof Ipv4Match) {
1844 logStr.append("If the IP matches with ");
1845 IPv4Net ip = ((Ipv4Match) m).getDestination();
1846 logStr.append(ip.toString());
1847 logStr.append(" then ");
1848 }
1849 else if (m instanceof MplsMatch) {
1850 logStr.append("If the MPLS label matches with ");
1851 int mplsLabel = ((MplsMatch) m).getMplsLabel();
1852 logStr.append(mplsLabel);
1853 logStr.append(" then ");
1854 }
1855 else if (m instanceof PacketMatch) {
1856 GroupAction ga = (GroupAction)actions.get(0);
1857 logStr.append("if the policy match is XXX then go to group " +
1858 ga.getGroupId());
1859 log.debug(logStr.toString());
1860 return;
1861 }
1862
1863 logStr.append(" do { ");
1864 for (Action action : actions) {
1865 if (action instanceof CopyTtlInAction) {
1866 logStr.append("copy ttl In, ");
1867 }
1868 else if (action instanceof CopyTtlOutAction) {
1869 logStr.append("copy ttl Out, ");
1870 }
1871 else if (action instanceof DecMplsTtlAction) {
1872 logStr.append("Dec MPLS TTL , ");
1873 }
1874 else if (action instanceof GroupAction) {
1875 logStr.append("Forward packet to < ");
1876 NeighborSet dpids = ((GroupAction) action).getDpids();
1877 logStr.append(dpids.toString() + ",");
1878
1879 }
1880 else if (action instanceof PopMplsAction) {
1881 logStr.append("Pop MPLS label, ");
1882 }
1883 else if (action instanceof PushMplsAction) {
1884 logStr.append("Push MPLS label, ");
1885 }
1886 else if (action instanceof SetMplsIdAction) {
1887 int id = ((SetMplsIdAction) action).getMplsId();
1888 logStr.append("Set MPLS ID as " + id + ", ");
1889 }
1890 }
1891
1892 log.debug(logStr.toString());
1893
1894 }
1895
1896
1897 // ************************************
1898 // Unused classes and functions
1899 // ************************************
1900
1901 /**
1902 * Temporary class to to keep ARP entry
1903 *
1904 */
1905 private class ArpEntry {
1906
1907 byte[] targetMacAddress;
1908 byte[] targetIpAddress;
1909
1910 private ArpEntry(byte[] macAddress, byte[] ipAddress) {
1911 this.targetMacAddress = macAddress;
1912 this.targetIpAddress = ipAddress;
1913 }
1914 }
1915
1916 /**
1917 * This class is used only for link recovery optimization in
1918 * modifyEcmpRoutingRules() function.
1919 * TODO: please remove if the optimization is not used at all
1920 */
1921 private class SwitchPair {
1922 private Switch src;
1923 private Switch dst;
1924
1925 public SwitchPair(Switch src, Switch dst) {
1926 this.src = src;
1927 this.dst = dst;
1928 }
1929
1930 public Switch getSource() {
1931 return src;
1932 }
1933
1934 public Switch getDestination() {
1935 return dst;
1936 }
1937 }
1938
1939 /**
1940 * Update ARP Cache using ARP packets It is used to set destination MAC
1941 * address to forward packets to known hosts. But, it will be replace with
1942 * Host information of Topology service later.
1943 *
1944 * @param arp APR packets to use for updating ARP entries
1945 */
1946 public void updateArpCache(ARP arp) {
1947
1948 ArpEntry arpEntry = new ArpEntry(arp.getSenderHardwareAddress(),
1949 arp.getSenderProtocolAddress());
1950 // TODO: Need to check the duplication
1951 arpEntries.add(arpEntry);
1952 }
1953
1954 /**
1955 * Modify the routing rules for the lost links
1956 * - Recompute the path if the link failed is included in the path
1957 * (including src and dest).
1958 *
1959 * @param newLink
1960 */
1961 private void modifyEcmpRoutingRules(LinkData linkRemoved) {
1962
1963 //HashMap<Switch, SwitchPair> linksToRecompute = new HashMap<Switch, SwitchPair>();
1964 Set<SwitchPair> linksToRecompute = new HashSet<SwitchPair>();
1965
1966 for (ECMPShortestPathGraph ecmpSPG : graphs.values()) {
1967 Switch rootSw = ecmpSPG.getRootSwitch();
1968 HashMap<Integer, HashMap<Switch, ArrayList<Path>>> paths =
1969 ecmpSPG.getCompleteLearnedSwitchesAndPaths();
1970 for (HashMap<Switch, ArrayList<Path>> p: paths.values()) {
1971 for (Switch destSw: p.keySet()) {
1972 ArrayList<Path> path = p.get(destSw);
1973 if (checkPath(path, linkRemoved)) {
1974 boolean found = false;
1975 for (SwitchPair pair: linksToRecompute) {
1976 if (pair.getSource().getDpid() == rootSw.getDpid() &&
1977 pair.getSource().getDpid() == destSw.getDpid()) {
1978 found = true;
1979 }
1980 }
1981 if (!found) {
1982 linksToRecompute.add(new SwitchPair(rootSw, destSw));
1983 }
1984 }
1985 }
1986 }
1987 }
1988
1989 // Recompute the path for the specific route
1990 for (SwitchPair pair: linksToRecompute) {
1991
1992 log.debug("Recompute path from {} to {}", pair.getSource(), pair.getDestination());
1993 // We need the following function for optimization
1994 //ECMPShortestPathGraph ecmpSPG =
1995 // new ECMPShortestPathGraph(pair.getSource(), pair.getDestination());
1996 ECMPShortestPathGraph ecmpSPG =
1997 new ECMPShortestPathGraph(pair.getSource());
1998 populateEcmpRoutingRulesForPath(pair.getSource(), ecmpSPG, true);
1999 }
2000 }
2001
2002 /**
2003 * Optimize the mpls label
2004 * The feature will be used only for policy of "avoid a specific switch".
2005 * Check route to each router in route backward.
2006 * If there is only one route to the router and the routers are included in
2007 * the route, remove the id from the path.
2008 * A-B-C-D-E => A-B-C-D-E -> A-E
2009 * | | => A-B-H-I -> A-I
Sangho Shin5b8f5452014-10-20 11:46:01 -07002010 * F-G-H-I => A-D-I > A-D-I
Sangho Shin7330c032014-10-20 10:34:51 -07002011 */
2012 private List<String> getOptimizedPath(Switch srcSw, Switch dstSw, List<String> route) {
2013
2014 List<String> optimizedPath = new ArrayList<String>();
2015 optimizedPath.addAll(route);
2016 ECMPShortestPathGraph ecmpSPG = new ECMPShortestPathGraph(srcSw);
2017
2018 HashMap<Integer, HashMap<Switch, ArrayList<Path>>> paths =
2019 ecmpSPG.getCompleteLearnedSwitchesAndPaths();
2020 for (HashMap<Switch, ArrayList<Path>> p: paths.values()) {
2021 for (Switch s: p.keySet()) {
2022 if (s.getDpid().toString().equals(dstSw.getDpid().toString())) {
2023 ArrayList<Path> ecmpPaths = p.get(s);
2024 if (ecmpPaths!= null && ecmpPaths.size() == 1) {
2025 for (Path path: ecmpPaths) {
2026 for (LinkData link: path) {
2027 String srcId = getMplsLabel(link.getSrc().getDpid().toString());
2028 String dstId = getMplsLabel(link.getSrc().getDpid().toString());
2029 if (optimizedPath.contains(srcId)) {
2030 optimizedPath.remove(srcId);
2031 }
2032 if (optimizedPath.contains(dstId)) {
2033 optimizedPath.remove(dstId);
2034 }
2035 }
2036 }
2037 }
2038 }
2039 }
2040 }
2041
2042 return optimizedPath;
2043
2044 }
2045
2046 /**
2047 * Check if the path is affected from the link removed
2048 *
2049 * @param path Path to check
2050 * @param linkRemoved link removed
2051 * @return true if the path contains the link removed
2052 */
2053 private boolean checkPath(ArrayList<Path> path, LinkData linkRemoved) {
2054
2055 for (Path ppp: path) {
2056 // TODO: need to check if this is a bidirectional or
2057 // unidirectional
2058 for (LinkData link: ppp) {
2059 if (link.getDst().getDpid().equals(linkRemoved.getDst().getDpid()) &&
2060 link.getSrc().getDpid().equals(linkRemoved.getSrc().getDpid()))
2061 return true;
2062 }
2063 }
2064
2065 return false;
2066 }
Sangho Shin15273b62014-10-16 22:22:05 -07002067
2068
Sangho Shin2f263692014-09-15 14:09:41 -07002069}