blob: 2e89510125227e9654db8c3cba18514d0594070b [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;
Sangho Shin6d3c2f02014-10-22 10:10:55 -070050import net.onrc.onos.core.matchaction.action.ModifyDstMacAction;
51import net.onrc.onos.core.matchaction.action.ModifySrcMacAction;
52import net.onrc.onos.core.matchaction.action.OutputAction;
Sangho Shin43cee112014-09-25 16:43:34 -070053import net.onrc.onos.core.matchaction.action.PopMplsAction;
54import net.onrc.onos.core.matchaction.action.PushMplsAction;
Sangho Shine842cad2014-10-24 16:07:35 -070055import net.onrc.onos.core.matchaction.action.SetDAAction;
Sangho Shin43cee112014-09-25 16:43:34 -070056import net.onrc.onos.core.matchaction.action.SetMplsIdAction;
Sangho Shine842cad2014-10-24 16:07:35 -070057import net.onrc.onos.core.matchaction.action.SetSAAction;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -070058import net.onrc.onos.core.matchaction.match.Ipv4Match;
Sangho Shin43cee112014-09-25 16:43:34 -070059import net.onrc.onos.core.matchaction.match.Match;
60import net.onrc.onos.core.matchaction.match.MplsMatch;
Sangho Shin15273b62014-10-16 22:22:05 -070061import net.onrc.onos.core.matchaction.match.PacketMatch;
62import net.onrc.onos.core.matchaction.match.PacketMatchBuilder;
Sangho Shin2f263692014-09-15 14:09:41 -070063import net.onrc.onos.core.packet.ARP;
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070064import net.onrc.onos.core.packet.Ethernet;
65import net.onrc.onos.core.packet.IPv4;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070066import net.onrc.onos.core.topology.ITopologyListener;
Sangho Shin1aa93542014-09-22 09:49:44 -070067import net.onrc.onos.core.topology.ITopologyService;
Sangho Shinbce900e2014-10-07 17:13:23 -070068import net.onrc.onos.core.topology.Link;
Sangho Shinc8d2f592014-09-30 16:53:57 -070069import net.onrc.onos.core.topology.LinkData;
Sangho Shinbce900e2014-10-07 17:13:23 -070070import net.onrc.onos.core.topology.MastershipData;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070071import net.onrc.onos.core.topology.MutableTopology;
Sangho Shineb083032014-09-22 16:11:34 -070072import net.onrc.onos.core.topology.Port;
Sangho Shinc8d2f592014-09-30 16:53:57 -070073import net.onrc.onos.core.topology.PortData;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070074import net.onrc.onos.core.topology.Switch;
Sangho Shin5be3e532014-10-03 17:20:58 -070075import net.onrc.onos.core.topology.SwitchData;
Sangho Shin1aa93542014-09-22 09:49:44 -070076import net.onrc.onos.core.topology.TopologyEvents;
Srikanth Vavilapalli363f1dc2014-09-22 14:30:23 -070077import net.onrc.onos.core.util.Dpid;
Sangho Shin43cee112014-09-25 16:43:34 -070078import net.onrc.onos.core.util.IPv4Net;
Sangho Shin6d3c2f02014-10-22 10:10:55 -070079import net.onrc.onos.core.util.PortNumber;
Sangho Shin43cee112014-09-25 16:43:34 -070080import net.onrc.onos.core.util.SwitchPort;
Sangho Shin2f263692014-09-15 14:09:41 -070081
Sangho Shin43cee112014-09-25 16:43:34 -070082import org.json.JSONArray;
83import org.json.JSONException;
Saurav Dasa962a692014-10-17 14:52:38 -070084import org.projectfloodlight.openflow.protocol.OFBarrierReply;
Saurav Dasbc594a42014-09-25 20:13:50 -070085import org.projectfloodlight.openflow.types.EthType;
Sangho Shin2f263692014-09-15 14:09:41 -070086import org.projectfloodlight.openflow.types.IPv4Address;
Sangho Shine842cad2014-10-24 16:07:35 -070087import org.projectfloodlight.openflow.types.MacAddress;
Sangho Shin2f263692014-09-15 14:09:41 -070088import org.slf4j.Logger;
89import org.slf4j.LoggerFactory;
90
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070091public class SegmentRoutingManager implements IFloodlightModule,
Srikanth Vavilapalli8c49db72014-10-20 13:35:08 -070092 ITopologyListener, IPacketListener, ISegmentRoutingService {
Sangho Shin2f263692014-09-15 14:09:41 -070093
94 private static final Logger log = LoggerFactory
95 .getLogger(SegmentRoutingManager.class);
Sangho Shin23f898d2014-10-13 16:54:00 -070096
Fahad Naeem Khan5b558f22014-10-16 10:35:20 -070097 private ITopologyService topologyService;
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070098 private IPacketService packetService;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070099 private MutableTopology mutableTopology;
Sangho Shin61535402014-10-01 11:37:14 -0700100 private ConcurrentLinkedQueue<IPv4> ipPacketQueue;
Fahad Naeem Khan4444b952014-10-18 22:30:50 -0700101 private IRestApiService restApi;
Sangho Shin2f263692014-09-15 14:09:41 -0700102 private List<ArpEntry> arpEntries;
Sangho Shineb083032014-09-22 16:11:34 -0700103 private ArpHandler arpHandler;
104 private GenericIpHandler ipHandler;
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700105 private IcmpHandler icmpHandler;
Sangho Shin43cee112014-09-25 16:43:34 -0700106 private IThreadPoolService threadPool;
107 private SingletonTask discoveryTask;
Sangho Shin23f898d2014-10-13 16:54:00 -0700108 private SingletonTask linkAddTask;
Sangho Shin15273b62014-10-16 22:22:05 -0700109 private SingletonTask testTask;
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700110 private IFloodlightProviderService floodlightProvider;
Sangho Shin2f263692014-09-15 14:09:41 -0700111
Sangho Shinfbc572c2014-10-02 16:37:05 -0700112 private HashMap<Switch, ECMPShortestPathGraph> graphs;
Sangho Shin23f898d2014-10-13 16:54:00 -0700113 private HashMap<String, LinkData> linksDown;
114 private HashMap<String, LinkData> linksToAdd;
Sangho Shin5be3e532014-10-03 17:20:58 -0700115 private ConcurrentLinkedQueue<TopologyEvents> topologyEventQueue;
Sangho Shine020cc32014-10-20 13:28:02 -0700116 private HashMap<String, PolicyInfo> policyTable;
Sangho Shin81655442014-10-20 14:22:46 -0700117 private HashMap<String, TunnelInfo> tunnelTable;
Sangho Shin6471d202014-10-23 10:59:36 -0700118 private HashMap<Integer, HashMap<Integer, List<Integer>>> adjacencySidTable;
Sangho Shin5b8f5452014-10-20 11:46:01 -0700119
Sangho Shine842cad2014-10-24 16:07:35 -0700120 // Flag whether transit router supports ECMP or not
121 private boolean supportTransitECMP = true;
Sangho Shin5b8f5452014-10-20 11:46:01 -0700122
Sangho Shine842cad2014-10-24 16:07:35 -0700123 private int testMode = 0;
Sangho Shinbce900e2014-10-07 17:13:23 -0700124
125 private int numOfEvents = 0;
126 private int numOfEventProcess = 0;
127 private int numOfPopulation = 0;
Sangho Shin99918bd2014-10-08 15:52:35 -0700128 private long matchActionId = 0L;
Sangho Shin58182672014-10-21 13:23:38 -0700129
Sangho Shin23f898d2014-10-13 16:54:00 -0700130 private final int DELAY_TO_ADD_LINK = 10;
Sangho Shin15273b62014-10-16 22:22:05 -0700131 private final int MAX_NUM_LABELS = 3;
Sangho Shinfbc572c2014-10-02 16:37:05 -0700132
Sangho Shin5b8f5452014-10-20 11:46:01 -0700133 private final int POLICY_ADD1 = 1;
134 private final int POLICY_ADD2 = 2;
135 private final int POLICY_REMOVE1 = 3;
136 private final int POLICY_REMOVE2 = 4;
Sangho Shin4b46bcd2014-10-20 15:48:47 -0700137 private final int TUNNEL_REMOVE1 = 5;
138 private final int TUNNEL_REMOVE2 = 6;
Sangho Shin5b8f5452014-10-20 11:46:01 -0700139
140
Sangho Shin7330c032014-10-20 10:34:51 -0700141 // ************************************
142 // IFloodlightModule implementation
143 // ************************************
144
Sangho Shin2f263692014-09-15 14:09:41 -0700145 @Override
146 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Srikanth Vavilapalli8c49db72014-10-20 13:35:08 -0700147 Collection<Class<? extends IFloodlightService>> l = new ArrayList<>();
148 l.add(ISegmentRoutingService.class);
149 return l;
Sangho Shin2f263692014-09-15 14:09:41 -0700150 }
151
152 @Override
153 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Srikanth Vavilapalli8c49db72014-10-20 13:35:08 -0700154 Map<Class<? extends IFloodlightService>, IFloodlightService> m = new HashMap<>();
155 m.put(ISegmentRoutingService.class, this);
156 return m;
Sangho Shin2f263692014-09-15 14:09:41 -0700157 }
158
159 @Override
160 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
161 Collection<Class<? extends IFloodlightService>> l = new ArrayList<Class<? extends IFloodlightService>>();
162
163 l.add(IFloodlightProviderService.class);
164 l.add(IConfigInfoService.class);
165 l.add(ITopologyService.class);
166 l.add(IPacketService.class);
167 l.add(IFlowPusherService.class);
168 l.add(ITopologyService.class);
Fahad Naeem Khan4444b952014-10-18 22:30:50 -0700169 l.add(IRestApiService.class);
Sangho Shin2f263692014-09-15 14:09:41 -0700170
171 return l;
172
173 }
174
175 @Override
176 public void init(FloodlightModuleContext context) throws FloodlightModuleException {
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700177 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Sangho Shineb083032014-09-22 16:11:34 -0700178 arpHandler = new ArpHandler(context, this);
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700179 icmpHandler = new IcmpHandler(context, this);
Sangho Shineb083032014-09-22 16:11:34 -0700180 ipHandler = new GenericIpHandler(context, this);
Sangho Shin2f263692014-09-15 14:09:41 -0700181 arpEntries = new ArrayList<ArpEntry>();
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700182 topologyService = context.getServiceImpl(ITopologyService.class);
Sangho Shin43cee112014-09-25 16:43:34 -0700183 threadPool = context.getServiceImpl(IThreadPoolService.class);
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700184 mutableTopology = topologyService.getTopology();
Sangho Shin61535402014-10-01 11:37:14 -0700185 ipPacketQueue = new ConcurrentLinkedQueue<IPv4>();
Sangho Shinfbc572c2014-10-02 16:37:05 -0700186 graphs = new HashMap<Switch, ECMPShortestPathGraph>();
Sangho Shin23f898d2014-10-13 16:54:00 -0700187 linksDown = new HashMap<String, LinkData>();
188 linksToAdd = new HashMap<String, LinkData>();
Sangho Shin5be3e532014-10-03 17:20:58 -0700189 topologyEventQueue = new ConcurrentLinkedQueue<TopologyEvents>();
Sangho Shin15273b62014-10-16 22:22:05 -0700190 packetService = context.getServiceImpl(IPacketService.class);
Fahad Naeem Khan4444b952014-10-18 22:30:50 -0700191 restApi = context.getServiceImpl(IRestApiService.class);
Sangho Shine020cc32014-10-20 13:28:02 -0700192 policyTable = new HashMap<String, PolicyInfo>();
Sangho Shin81655442014-10-20 14:22:46 -0700193 tunnelTable = new HashMap<String, TunnelInfo>();
Sangho Shin6471d202014-10-23 10:59:36 -0700194 adjacencySidTable = new HashMap<Integer,HashMap<Integer, List<Integer>>>();
Sangho Shin2f263692014-09-15 14:09:41 -0700195
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700196 packetService.registerPacketListener(this);
Sangho Shin15273b62014-10-16 22:22:05 -0700197 topologyService.addListener(this, false);
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700198
Sangho Shin99918bd2014-10-08 15:52:35 -0700199
Sangho Shin2f263692014-09-15 14:09:41 -0700200 }
201
202 @Override
203 public void startUp(FloodlightModuleContext context) throws FloodlightModuleException {
Sangho Shinc8d2f592014-09-30 16:53:57 -0700204 ScheduledExecutorService ses = threadPool.getScheduledExecutor();
Fahad Naeem Khan4444b952014-10-18 22:30:50 -0700205 restApi.addRestletRoutable(new SegmentRoutingWebRoutable());
Sangho Shin2f263692014-09-15 14:09:41 -0700206
Sangho Shinc8d2f592014-09-30 16:53:57 -0700207 discoveryTask = new SingletonTask(ses, new Runnable() {
208 @Override
209 public void run() {
Sangho Shin5be3e532014-10-03 17:20:58 -0700210 handleTopologyChangeEvents();
Sangho Shinc8d2f592014-09-30 16:53:57 -0700211 }
212 });
Sangho Shin23f898d2014-10-13 16:54:00 -0700213
214 linkAddTask = new SingletonTask(ses, new Runnable() {
215 @Override
216 public void run() {
217 delayedAddLink();
218 }
219 });
220
Sangho Shin15273b62014-10-16 22:22:05 -0700221 testTask = new SingletonTask(ses, new Runnable() {
222 @Override
223 public void run() {
224 runTest();
225 }
226 });
227
Sangho Shin5b8f5452014-10-20 11:46:01 -0700228 testMode = POLICY_ADD1;
Sangho Shin204b9972014-10-22 11:08:10 -0700229 //testTask.reschedule(20, TimeUnit.SECONDS);
Sangho Shin2f263692014-09-15 14:09:41 -0700230 }
231
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700232 @Override
233 public void receive(Switch sw, Port inPort, Ethernet payload) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700234 if (payload.getEtherType() == Ethernet.TYPE_ARP)
235 arpHandler.processPacketIn(sw, inPort, payload);
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700236 if (payload.getEtherType() == Ethernet.TYPE_IPV4) {
Sangho Shin7330c032014-10-20 10:34:51 -0700237 addPacketToPacketBuffer((IPv4) payload.getPayload());
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700238 if (((IPv4) payload.getPayload()).getProtocol() == IPv4.PROTOCOL_ICMP)
239 icmpHandler.processPacketIn(sw, inPort, payload);
240 else
241 ipHandler.processPacketIn(sw, inPort, payload);
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700242 }
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700243 else {
244 log.debug("{}", payload.toString());
245 }
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700246 }
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700247
Sangho Shin2f263692014-09-15 14:09:41 -0700248
Sangho Shin7330c032014-10-20 10:34:51 -0700249 // ************************************
250 // Topology event handlers
251 // ************************************
Sangho Shineb083032014-09-22 16:11:34 -0700252
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700253 /**
254 * Topology events that have been generated.
Sangho Shinfbc572c2014-10-02 16:37:05 -0700255 *
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700256 * @param topologyEvents the generated Topology Events
257 * @see TopologyEvents
258 */
259 public void topologyEvents(TopologyEvents topologyEvents)
260 {
Sangho Shin5be3e532014-10-03 17:20:58 -0700261 topologyEventQueue.add(topologyEvents);
Sangho Shinbce900e2014-10-07 17:13:23 -0700262 discoveryTask.reschedule(100, TimeUnit.MILLISECONDS);
Sangho Shin5be3e532014-10-03 17:20:58 -0700263 }
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700264
Sangho Shin23f898d2014-10-13 16:54:00 -0700265 /**
266 * Process the multiple topology events with some delay (100MS at most for now)
267 *
268 */
Sangho Shin5be3e532014-10-03 17:20:58 -0700269 private void handleTopologyChangeEvents() {
Sangho Shinbce900e2014-10-07 17:13:23 -0700270 numOfEventProcess ++;
271
Sangho Shin51625342014-10-17 09:30:48 -0700272 Collection<LinkData> linkEntriesAddedAll = new ArrayList<LinkData>();
273 Collection<PortData> portEntriesAddedAll = new ArrayList<PortData>();
274 Collection<PortData> portEntriesRemovedAll = new ArrayList<PortData>();
275 Collection<LinkData> linkEntriesRemovedAll = new ArrayList<LinkData>();
276 Collection<SwitchData> switchAddedAll = new ArrayList<SwitchData>();
277 Collection<SwitchData> switchRemovedAll = new ArrayList<SwitchData>();
278 Collection<MastershipData> mastershipRemovedAll = new ArrayList<MastershipData>();
Sangho Shinbce900e2014-10-07 17:13:23 -0700279
Sangho Shin5be3e532014-10-03 17:20:58 -0700280 while (!topologyEventQueue.isEmpty()) {
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700281 // We should handle the events in the order of when they happen
282 // TODO: We need to simulate the final results of multiple events
283 // and shoot only the final state.
284 // Ex: link s1-s2 down, link s1-s2 up --> Do nothing
285 // Ex: ink s1-s2 up, s1-p1,p2 down --> link s1-s2 down
Sangho Shin51625342014-10-17 09:30:48 -0700286
Sangho Shin5be3e532014-10-03 17:20:58 -0700287 TopologyEvents topologyEvents = topologyEventQueue.poll();
Sangho Shin51625342014-10-17 09:30:48 -0700288
289 Collection<LinkData> linkEntriesAdded = topologyEvents.getAddedLinkDataEntries();
290 Collection<PortData> portEntriesAdded = topologyEvents.getAddedPortDataEntries();
291 Collection<PortData> portEntriesRemoved = topologyEvents.getRemovedPortDataEntries();
292 Collection<LinkData> linkEntriesRemoved = topologyEvents.getRemovedLinkDataEntries();
293 Collection<SwitchData> switchAdded = topologyEvents.getAddedSwitchDataEntries();
294 Collection<SwitchData> switchRemoved = topologyEvents.getRemovedSwitchDataEntries();
295 Collection<MastershipData> mastershipRemoved = topologyEvents.getRemovedMastershipDataEntries();
296
297 linkEntriesAddedAll.addAll(linkEntriesAdded);
298 portEntriesAddedAll.addAll(portEntriesAdded);
299 portEntriesRemovedAll.addAll(portEntriesRemoved);
300 linkEntriesRemovedAll.addAll(linkEntriesRemoved);
301 switchAddedAll.addAll(switchAdded);
302 switchRemovedAll.addAll(switchRemoved);
303 mastershipRemovedAll.addAll(mastershipRemoved);
Sangho Shinbce900e2014-10-07 17:13:23 -0700304 numOfEvents++;
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700305
306 if (!portEntriesRemoved.isEmpty()) {
307 processPortRemoval(portEntriesRemoved);
308 }
309
310 if (!linkEntriesRemoved.isEmpty()) {
311 processLinkRemoval(linkEntriesRemoved);
312 }
313
314 if (!switchRemoved.isEmpty()) {
315 processSwitchRemoved(switchRemoved);
316 }
317
318 if (!mastershipRemoved.isEmpty()) {
Sangho Shin23f898d2014-10-13 16:54:00 -0700319 log.debug("Mastership is removed. Check if ports are down also.");
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700320 }
321
322 if (!linkEntriesAdded.isEmpty()) {
Sangho Shin23f898d2014-10-13 16:54:00 -0700323 processLinkAdd(linkEntriesAdded, false);
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700324 }
325
326 if (!portEntriesAdded.isEmpty()) {
327 processPortAdd(portEntriesAdded);
328 }
329
330 if (!switchAdded.isEmpty()) {
331 processSwitchAdd(switchAdded);
332 }
Sangho Shin51625342014-10-17 09:30:48 -0700333
Sangho Shinbce900e2014-10-07 17:13:23 -0700334 }
335
Sangho Shin23f898d2014-10-13 16:54:00 -0700336 // TODO: 100ms is enough to check both mastership removed events
337 // and the port removed events? What if the PORT_STATUS packets comes late?
Sangho Shin51625342014-10-17 09:30:48 -0700338 if (!mastershipRemovedAll.isEmpty()) {
339 if (portEntriesRemovedAll.isEmpty()) {
Saurav Das82e62972014-10-16 14:53:57 -0700340 log.debug("Just mastership is removed. Do not do anthing.");
Sangho Shin23f898d2014-10-13 16:54:00 -0700341 }
342 else {
343 HashMap<String, MastershipData> mastershipToRemove =
344 new HashMap<String, MastershipData>();
Sangho Shin51625342014-10-17 09:30:48 -0700345 for (MastershipData ms: mastershipRemovedAll) {
346 for (PortData port: portEntriesRemovedAll) {
Sangho Shin23f898d2014-10-13 16:54:00 -0700347 // TODO: check ALL ports of the switch are dead ..
348 if (port.getDpid().equals(ms.getDpid())) {
349 mastershipToRemove.put(ms.getDpid().toString(), ms);
350 }
351 }
352 log.debug("Swtich {} is really down.", ms.getDpid());
353 }
354 processMastershipRemoved(mastershipToRemove.values());
355 }
356 }
357
Sangho Shinbce900e2014-10-07 17:13:23 -0700358 log.debug("num events {}, num of process {}, "
359 + "num of Population {}", numOfEvents, numOfEventProcess,
360 numOfPopulation);
361 }
362
363 /**
Sangho Shin99918bd2014-10-08 15:52:35 -0700364 * Process the SwitchAdded events from topologyMananger.
365 * It does nothing. When a switch is added, then link will be added too.
366 * LinkAdded event will handle process all re-computation.
367 *
368 * @param switchAdded
369 */
370 private void processSwitchAdd(Collection<SwitchData> switchAdded) {
371
372 }
373
374 /**
Sangho Shinbce900e2014-10-07 17:13:23 -0700375 * Remove all ports connected to the switch removed
376 *
377 * @param mastershipRemoved master switch info removed
378 */
379 private void processMastershipRemoved(Collection<MastershipData>
380 mastershipRemoved) {
381 for (MastershipData mastership: mastershipRemoved) {
382 Switch sw = mutableTopology.getSwitch(mastership.getDpid());
383 for (Link link: sw.getOutgoingLinks()) {
384 Port dstPort = link.getDstPort();
385 IOF13Switch dstSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
386 getSwId(dstPort.getDpid().toString()));
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700387 if (dstSw != null) {
388 dstSw.removePortFromGroups(dstPort.getNumber());
389 log.debug("MasterSwitch {} is gone: remove port {}", sw.getDpid(), dstPort);
390 }
Sangho Shinbce900e2014-10-07 17:13:23 -0700391 }
Sangho Shin61535402014-10-01 11:37:14 -0700392 }
Sangho Shin23f898d2014-10-13 16:54:00 -0700393
394 linksToAdd.clear();
395 linksDown.clear();
Sangho Shin61535402014-10-01 11:37:14 -0700396 }
Sangho Shinc8d2f592014-09-30 16:53:57 -0700397
Sangho Shinbce900e2014-10-07 17:13:23 -0700398 /**
399 * Remove all ports connected to the switch removed
400 *
401 * @param switchRemoved Switch removed
402 */
Sangho Shin5be3e532014-10-03 17:20:58 -0700403 private void processSwitchRemoved(Collection<SwitchData> switchRemoved) {
Sangho Shin23f898d2014-10-13 16:54:00 -0700404 log.debug("SwitchRemoved event occurred !!!");
Sangho Shin5be3e532014-10-03 17:20:58 -0700405 }
406
Sangho Shin61535402014-10-01 11:37:14 -0700407 /**
Sangho Shin99918bd2014-10-08 15:52:35 -0700408 * Report ports added to driver
Sangho Shinfbc572c2014-10-02 16:37:05 -0700409 *
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700410 * @param portEntries
411 */
412 private void processPortAdd(Collection<PortData> portEntries) {
Sangho Shin99918bd2014-10-08 15:52:35 -0700413 // TODO: do we need to add ports with delay?
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700414 for (PortData port : portEntries) {
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700415 Dpid dpid = port.getDpid();
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700416
Sangho Shinfbc572c2014-10-02 16:37:05 -0700417 IOF13Switch sw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700418 getSwId(port.getDpid().toString()));
Sangho Shin815af0c2014-10-10 13:05:45 -0700419 if (sw != null) {
Sangho Shin721ca042014-10-09 13:03:40 -0700420 sw.addPortToGroups(port.getPortNumber());
Sangho Shin15273b62014-10-16 22:22:05 -0700421 //log.debug("Add port {} to switch {}", port, dpid);
Sangho Shin815af0c2014-10-10 13:05:45 -0700422 }
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700423 }
424 }
425
426 /**
427 * Reports ports of new links to driver and recalculate ECMP SPG
Sangho Shin23f898d2014-10-13 16:54:00 -0700428 * If the link to add was removed before, then we just schedule the add link
429 * event and do not recompute the path now.
Sangho Shinfbc572c2014-10-02 16:37:05 -0700430 *
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700431 * @param linkEntries
432 */
Sangho Shin23f898d2014-10-13 16:54:00 -0700433 private void processLinkAdd(Collection<LinkData> linkEntries, boolean delayed) {
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700434
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700435 for (LinkData link : linkEntries) {
Sangho Shin5be3e532014-10-03 17:20:58 -0700436
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700437 SwitchPort srcPort = link.getSrc();
438 SwitchPort dstPort = link.getDst();
439
Sangho Shin23f898d2014-10-13 16:54:00 -0700440 String key = srcPort.getDpid().toString() +
441 dstPort.getDpid().toString();
442 if (!delayed) {
443 if (linksDown.containsKey(key)) {
444 linksToAdd.put(key, link);
445 linksDown.remove(key);
446 linkAddTask.reschedule(DELAY_TO_ADD_LINK, TimeUnit.SECONDS);
447 log.debug("Add link {} with 5 sec delay", link);
448 // TODO: What if we have multiple events of add link:
449 // one is new link add, the other one is link up for
450 // broken link? ECMPSPG function cannot deal with it for now
451 return;
452 }
453 }
454 else {
455 if (linksDown.containsKey(key)) {
456 linksToAdd.remove(key);
457 log.debug("Do not add the link {}: it is down again!", link);
458 return;
459 }
460 }
461
Sangho Shinfbc572c2014-10-02 16:37:05 -0700462 IOF13Switch srcSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700463 getSwId(srcPort.getDpid().toString()));
Sangho Shinfbc572c2014-10-02 16:37:05 -0700464 IOF13Switch dstSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700465 getSwId(dstPort.getDpid().toString()));
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700466
Sangho Shin815af0c2014-10-10 13:05:45 -0700467 if ((srcSw == null) || (dstSw == null))
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700468 continue;
469
470 srcSw.addPortToGroups(srcPort.getPortNumber());
471 dstSw.addPortToGroups(dstPort.getPortNumber());
Sangho Shin5be3e532014-10-03 17:20:58 -0700472
Sangho Shin15273b62014-10-16 22:22:05 -0700473 //log.debug("Add a link port {} to switch {} to add link {}", srcPort, srcSw,
474 // link);
475 //log.debug("Add a link port {} to switch {} to add link {}", dstPort, dstSw,
476 // link);
Sangho Shin815af0c2014-10-10 13:05:45 -0700477
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700478 }
Sangho Shinbce900e2014-10-07 17:13:23 -0700479 populateEcmpRoutingRules(false);
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700480 }
481
482 /**
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700483 * Check if all links are gone b/w the two switches. If all links are gone,
484 * then we need to recalculate the path. Otherwise, just report link failure
485 * to the driver.
Sangho Shinfbc572c2014-10-02 16:37:05 -0700486 *
Sangho Shin61535402014-10-01 11:37:14 -0700487 * @param linkEntries
488 */
489 private void processLinkRemoval(Collection<LinkData> linkEntries) {
Sangho Shinbce900e2014-10-07 17:13:23 -0700490 boolean recomputationRequired = false;
491
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700492 for (LinkData link : linkEntries) {
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700493 SwitchPort srcPort = link.getSrc();
494 SwitchPort dstPort = link.getDst();
Sangho Shinc8d2f592014-09-30 16:53:57 -0700495
Sangho Shinfbc572c2014-10-02 16:37:05 -0700496 IOF13Switch srcSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700497 getSwId(srcPort.getDpid().toString()));
Sangho Shinfbc572c2014-10-02 16:37:05 -0700498 IOF13Switch dstSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700499 getSwId(dstPort.getDpid().toString()));
Sangho Shin815af0c2014-10-10 13:05:45 -0700500 if ((srcSw == null) || (dstSw == null))
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700501 /* If this link is not between two switches, ignore it */
502 continue;
Sangho Shin23f898d2014-10-13 16:54:00 -0700503
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700504 srcSw.removePortFromGroups(srcPort.getPortNumber());
505 dstSw.removePortFromGroups(dstPort.getPortNumber());
Sangho Shin815af0c2014-10-10 13:05:45 -0700506 log.debug("Remove port {} from switch {}", srcPort, srcSw);
507 log.debug("Remove port {} from switch {}", dstPort, dstSw);
508
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700509 Switch srcSwitch = mutableTopology.getSwitch(srcPort.getDpid());
510 if (srcSwitch.getLinkToNeighbor(dstPort.getDpid()) == null) {
Sangho Shinbce900e2014-10-07 17:13:23 -0700511 // TODO: it is only for debugging purpose.
Sangho Shin99918bd2014-10-08 15:52:35 -0700512 // We just need to call populateEcmpRoutingRules() and return;
Sangho Shinbce900e2014-10-07 17:13:23 -0700513 recomputationRequired = true;
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700514 log.debug("All links are gone b/w {} and {}", srcPort.getDpid(),
Sangho Shin5be3e532014-10-03 17:20:58 -0700515 dstPort.getDpid());
Sangho Shinc8d2f592014-09-30 16:53:57 -0700516 }
Sangho Shin23f898d2014-10-13 16:54:00 -0700517
518 String key = link.getSrc().getDpid().toString()+
519 link.getDst().getDpid().toString();
520 if (!linksDown.containsKey(key)) {
521 linksDown.put(key, link);
522 }
Sangho Shinc8d2f592014-09-30 16:53:57 -0700523 }
Sangho Shinbce900e2014-10-07 17:13:23 -0700524
525 if (recomputationRequired)
526 populateEcmpRoutingRules(false);
Sangho Shin61535402014-10-01 11:37:14 -0700527 }
Sangho Shinc8d2f592014-09-30 16:53:57 -0700528
Sangho Shin61535402014-10-01 11:37:14 -0700529 /**
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700530 * report ports removed to the driver immediately
Sangho Shinfbc572c2014-10-02 16:37:05 -0700531 *
Sangho Shin61535402014-10-01 11:37:14 -0700532 * @param portEntries
533 */
534 private void processPortRemoval(Collection<PortData> portEntries) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700535 for (PortData port : portEntries) {
Sangho Shin61535402014-10-01 11:37:14 -0700536 Dpid dpid = port.getDpid();
Sangho Shin61535402014-10-01 11:37:14 -0700537
Sangho Shinfbc572c2014-10-02 16:37:05 -0700538 IOF13Switch sw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin61535402014-10-01 11:37:14 -0700539 getSwId(port.getDpid().toString()));
Sangho Shin815af0c2014-10-10 13:05:45 -0700540 if (sw != null) {
Sangho Shinfbc572c2014-10-02 16:37:05 -0700541 sw.removePortFromGroups(port.getPortNumber());
Sangho Shin815af0c2014-10-10 13:05:45 -0700542 log.debug("Remove port {} from switch {}", port, dpid);
543 }
Sangho Shin61535402014-10-01 11:37:14 -0700544 }
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700545 }
Sangho Shin1aa93542014-09-22 09:49:44 -0700546
547 /**
Sangho Shin7330c032014-10-20 10:34:51 -0700548 * Add the link immediately
549 * The function is scheduled when link add event happens and called
550 * DELAY_TO_ADD_LINK seconds after the event to avoid link flip-flop.
551 */
552 private void delayedAddLink() {
553
554 processLinkAdd(linksToAdd.values(), true);
555
556 }
557
558
559 // ************************************
560 // ECMP shorted path routing functions
561 // ************************************
562
563 /**
Sangho Shin43cee112014-09-25 16:43:34 -0700564 * Populate routing rules walking through the ECMP shortest paths
Sangho Shinfbc572c2014-10-02 16:37:05 -0700565 *
Sangho Shin99918bd2014-10-08 15:52:35 -0700566 * @param modified if true, it "modifies" the rules
Sangho Shin1aa93542014-09-22 09:49:44 -0700567 */
Sangho Shin5be3e532014-10-03 17:20:58 -0700568 private void populateEcmpRoutingRules(boolean modified) {
569 graphs.clear();
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700570 Iterable<Switch> switches = mutableTopology.getSwitches();
Sangho Shin43cee112014-09-25 16:43:34 -0700571 for (Switch sw : switches) {
572 ECMPShortestPathGraph ecmpSPG = new ECMPShortestPathGraph(sw);
Sangho Shinfbc572c2014-10-02 16:37:05 -0700573 graphs.put(sw, ecmpSPG);
574 //log.debug("ECMPShortestPathGraph is computed for switch {}",
575 // HexString.toHexString(sw.getDpid().value()));
Sangho Shin5be3e532014-10-03 17:20:58 -0700576 populateEcmpRoutingRulesForPath(sw, ecmpSPG, modified);
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700577
578 // Set adjacency routing rule for all switches
579 try {
580 populateAdjacencyncyRule(sw);
581 } catch (JSONException e) {
582 // TODO Auto-generated catch block
583 e.printStackTrace();
584 }
Sangho Shinfbc572c2014-10-02 16:37:05 -0700585 }
Sangho Shinbce900e2014-10-07 17:13:23 -0700586 numOfPopulation++;
Sangho Shinfbc572c2014-10-02 16:37:05 -0700587 }
Sangho Shin1aa93542014-09-22 09:49:44 -0700588
Sangho Shin204b9972014-10-22 11:08:10 -0700589 /**
590 * populate the MPLS rules to handle Adjacency IDs
591 *
592 * @param sw Switch
593 * @throws JSONException
594 */
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700595 private void populateAdjacencyncyRule(Switch sw) throws JSONException {
596 String adjInfo = sw.getStringAttribute("adjacencySids");
Sangho Shin204b9972014-10-22 11:08:10 -0700597 String nodeSidStr = sw.getStringAttribute("nodeSid");
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700598 String srcMac = sw.getStringAttribute("routerMac");
Sangho Shin204b9972014-10-22 11:08:10 -0700599 String autoAdjInfo = sw.getStringAttribute("autogenAdjSids");
600
Sangho Shinced05b62014-10-22 11:23:14 -0700601 if (autoAdjInfo == null || srcMac == null || nodeSidStr == null)
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700602 return;
603
Sangho Shinced05b62014-10-22 11:23:14 -0700604 // parse adjacency Id
Sangho Shincfef3922014-10-22 12:04:16 -0700605 HashMap<Integer, List<Integer>> adjacencyInfo = null;
Sangho Shinced05b62014-10-22 11:23:14 -0700606 if (adjInfo != null) {
Sangho Shincfef3922014-10-22 12:04:16 -0700607 adjacencyInfo = parseAdjacencySidInfo(adjInfo);
Sangho Shinced05b62014-10-22 11:23:14 -0700608 }
Sangho Shincfef3922014-10-22 12:04:16 -0700609 // parse auto generated adjacency Id
610 adjacencyInfo.putAll(parseAdjacencySidInfo(autoAdjInfo));
Sangho Shinced05b62014-10-22 11:23:14 -0700611
Sangho Shin6471d202014-10-23 10:59:36 -0700612 adjacencySidTable.put(Integer.parseInt(nodeSidStr), adjacencyInfo);
Sangho Shin204b9972014-10-22 11:08:10 -0700613
Sangho Shin6471d202014-10-23 10:59:36 -0700614 for (Integer adjId: adjacencyInfo.keySet()) {
615 List<Integer> ports = adjacencyInfo.get(adjId);
616 if (ports.size() == 1) {
617 setAdjacencyRuleOfOutput(sw, adjId, srcMac, ports.get(0));
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700618 }
619 else {
Sangho Shin6471d202014-10-23 10:59:36 -0700620 setAdjacencyRuleOfGroup(sw, adjId, ports);
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700621 }
Sangho Shin6471d202014-10-23 10:59:36 -0700622 }
623 }
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700624
Sangho Shin6471d202014-10-23 10:59:36 -0700625 /**
626 * Set Adjacency Rule to MPLS table for adjacency Ids attached to multiple
627 * ports
628 *
629 * @param sw Switch
630 * @param adjId Adjacency ID
631 * @param ports List of ports assigned to the Adjacency ID
632 */
633 private void setAdjacencyRuleOfGroup(Switch sw, Integer adjId, List<Integer> ports) {
634
635 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
636 getSwId(sw.getDpid().toString()));
637
638 int groupId = -1;
639 if (sw13 != null) {
640 List<PortNumber> portList = new ArrayList<PortNumber>();
641 for (Integer port: ports)
642 portList.add(PortNumber.uint32(port));
643 groupId = sw13.createGroup(new ArrayList<Integer>(), portList);
644 }
645
646 if (groupId < 0) {
647 log.debug("Failed to create a group at driver for adj ID {}", adjId);
648 }
649
650 pushAdjRule(sw, adjId, null, null, groupId, true);
651 pushAdjRule(sw, adjId, null, null, groupId, false);
652 }
653
654 /**
655 * Set Adjacency Rule to MPLS table for adjacency Ids attached to single port
656 *
657 * @param sw Switch
658 * @param adjId Adjacency ID
659 * @param ports List of ports assigned to the Adjacency ID
660 */
661 private void setAdjacencyRuleOfOutput(Switch sw, Integer adjId, String srcMac, Integer portNo) {
662
663 Dpid dstDpid = null;
664 for (Link link: sw.getOutgoingLinks()) {
665 if (link.getSrcPort().getPortNumber().value() == portNo) {
666 dstDpid = link.getDstPort().getDpid();
667 break;
668 }
669 }
670 if (dstDpid == null) {
671 log.debug("Cannot find the destination switch for the adjacency ID {}", adjId);
672 return;
673 }
674 Switch dstSw = mutableTopology.getSwitch(dstDpid);
675 String dstMac = null;
676 if (dstSw == null) {
677 log.debug("Cannot find SW {}", dstDpid.toString());
678 return;
679 }
680 else {
681 dstMac = dstSw.getStringAttribute("routerMac");
682 }
683
684 pushAdjRule(sw, adjId, srcMac, dstMac, portNo, true); // BoS = 1
685 pushAdjRule(sw, adjId, srcMac, dstMac, portNo, false); // BoS = 0
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700686
687 }
688
Sangho Shin204b9972014-10-22 11:08:10 -0700689 /**
690 * Push the MPLS rule for Adjacency ID
691 *
692 * @param sw Switch to push the rule
693 * @param id Adjacency ID
694 * @param srcMac source MAC address
695 * @param dstMac destination MAC address
696 * @param portNo port number assigned to the ID
697 * @param bos BoS option
698 */
Sangho Shin6471d202014-10-23 10:59:36 -0700699 private void pushAdjRule(Switch sw, int id, String srcMac, String dstMac,
700 int num, boolean bos) {
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700701
702 MplsMatch mplsMatch = new MplsMatch(id, bos);
703 List<Action> actions = new ArrayList<Action>();
704
705 if (bos) {
706 PopMplsAction popAction = new PopMplsAction(EthType.IPv4);
707 CopyTtlInAction copyTtlInAction = new CopyTtlInAction();
708 DecNwTtlAction decNwTtlAction = new DecNwTtlAction(1);
709 actions.add(copyTtlInAction);
710 actions.add(popAction);
711 actions.add(decNwTtlAction);
712 }
713 else {
714 PopMplsAction popAction = new PopMplsAction(EthType.MPLS_UNICAST);
715 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
716 actions.add(popAction);
717 actions.add(decMplsTtlAction);
718 }
719
Sangho Shin6471d202014-10-23 10:59:36 -0700720 // Output action
721 if (srcMac != null && dstMac != null) {
722 ModifyDstMacAction setDstAction = new ModifyDstMacAction(MACAddress.valueOf(srcMac));
723 ModifySrcMacAction setSrcAction = new ModifySrcMacAction(MACAddress.valueOf(dstMac));
724 OutputAction outportAction = new OutputAction(PortNumber.uint32(num));
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700725
Sangho Shin6471d202014-10-23 10:59:36 -0700726 actions.add(setDstAction);
727 actions.add(setSrcAction);
728 actions.add(outportAction);
729 }
730 // Group Action
731 else {
732 GroupAction groupAction = new GroupAction();
733 groupAction.setGroupId(num);
734 actions.add(groupAction);
735 }
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700736
737 MatchAction matchAction = new MatchAction(new MatchActionId(matchActionId++),
738 new SwitchPort((long) 0, (short) 0), mplsMatch, actions);
739 Operator operator = Operator.ADD;
740 MatchActionOperationEntry maEntry =
741 new MatchActionOperationEntry(operator, matchAction);
742
743 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
744 getSwId(sw.getDpid().toString()));
745
746 if (sw13 != null) {
747 try {
748 //printMatchActionOperationEntry(sw, maEntry);
749 sw13.pushFlow(maEntry);
750 } catch (IOException e) {
751 e.printStackTrace();
752 }
753 }
754 }
755
Sangho Shin99918bd2014-10-08 15:52:35 -0700756 /**
757 * populate routing rules to forward packets from the switch given to
758 * all other switches.
759 *
760 * @param sw source switch
761 * @param ecmpSPG shortest path from the the source switch to all others
762 * @param modified modification flag
763 */
Sangho Shinfbc572c2014-10-02 16:37:05 -0700764 private void populateEcmpRoutingRulesForPath(Switch sw,
Sangho Shin5be3e532014-10-03 17:20:58 -0700765 ECMPShortestPathGraph ecmpSPG, boolean modified) {
Sangho Shin43cee112014-09-25 16:43:34 -0700766
Sangho Shinfbc572c2014-10-02 16:37:05 -0700767 HashMap<Integer, HashMap<Switch, ArrayList<ArrayList<Dpid>>>> switchVia =
768 ecmpSPG.getAllLearnedSwitchesAndVia();
769 for (Integer itrIdx : switchVia.keySet()) {
770 //log.debug("ECMPShortestPathGraph:Switches learned in "
771 // + "Iteration{} from switch {}:",
772 // itrIdx,
773 // HexString.toHexString(sw.getDpid().value()));
774 HashMap<Switch, ArrayList<ArrayList<Dpid>>> swViaMap =
775 switchVia.get(itrIdx);
776 for (Switch targetSw : swViaMap.keySet()) {
Sangho Shin5be3e532014-10-03 17:20:58 -0700777 //log.debug("ECMPShortestPathGraph:****switch {} via:",
778 // HexString.toHexString(targetSw.getDpid().value()));
Sangho Shinfbc572c2014-10-02 16:37:05 -0700779 String destSw = sw.getDpid().toString();
780 List<String> fwdToSw = new ArrayList<String>();
781
Sangho Shinfbc572c2014-10-02 16:37:05 -0700782 for (ArrayList<Dpid> via : swViaMap.get(targetSw)) {
Sangho Shin5be3e532014-10-03 17:20:58 -0700783 //log.debug("ECMPShortestPathGraph:******{}) {}", ++i, via);
Sangho Shinfbc572c2014-10-02 16:37:05 -0700784 if (via.isEmpty()) {
785 fwdToSw.add(destSw);
Sangho Shin43cee112014-09-25 16:43:34 -0700786 }
Sangho Shinfbc572c2014-10-02 16:37:05 -0700787 else {
788 fwdToSw.add(via.get(0).toString());
789 }
Sangho Shin43cee112014-09-25 16:43:34 -0700790 }
Sangho Shin5be3e532014-10-03 17:20:58 -0700791 setRoutingRule(targetSw, destSw, fwdToSw, modified);
Sangho Shineb083032014-09-22 16:11:34 -0700792 }
Sangho Shinfbc572c2014-10-02 16:37:05 -0700793
794 // Send Barrier Message and make sure all rules are set
795 // before we set the rules to next routers
Saurav Dasa962a692014-10-17 14:52:38 -0700796 // TODO: barriers to all switches in this update stage
Sangho Shinfbc572c2014-10-02 16:37:05 -0700797 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
798 getSwId(sw.getDpid().toString()));
Sangho Shin5be3e532014-10-03 17:20:58 -0700799 if (sw13 != null) {
Saurav Dasa962a692014-10-17 14:52:38 -0700800 OFBarrierReplyFuture replyFuture = null;
Sangho Shin5be3e532014-10-03 17:20:58 -0700801 try {
Saurav Dasa962a692014-10-17 14:52:38 -0700802 replyFuture = sw13.sendBarrier();
Sangho Shin5be3e532014-10-03 17:20:58 -0700803 } catch (IOException e) {
Saurav Dasa962a692014-10-17 14:52:38 -0700804 log.error("Error sending barrier request to switch {}",
805 sw13.getId(), e.getCause());
Sangho Shin5be3e532014-10-03 17:20:58 -0700806 }
Saurav Dasa962a692014-10-17 14:52:38 -0700807 OFBarrierReply br = null;
808 try {
809 br = replyFuture.get(2, TimeUnit.SECONDS);
810 } catch (TimeoutException | InterruptedException | ExecutionException e) {
811 // XXX for some reason these exceptions are not being thrown
812 }
813 if (br == null) {
814 log.warn("Did not receive barrier-reply from {}", sw13.getId());
815 // XXX take corrective action
816 }
817
Sangho Shinfbc572c2014-10-02 16:37:05 -0700818 }
819 }
820
821 }
822
Sangho Shinfbc572c2014-10-02 16:37:05 -0700823 /**
824 *
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700825 * Set routing rules in targetSw {forward packets to fwdToSw switches in
826 * order to send packets to destSw} - If the target switch is an edge router
827 * and final destnation switch is also an edge router, then set IP
828 * forwarding rules to subnets - If only the target switch is an edge
829 * router, then set IP forwarding rule to the transit router loopback IP
830 * address - If the target is a transit router, then just set the MPLS
831 * forwarding rule
Sangho Shinfbc572c2014-10-02 16:37:05 -0700832 *
Sangho Shin43cee112014-09-25 16:43:34 -0700833 * @param targetSw Switch to set the rules
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700834 * @param destSw Final destination switches
Sangho Shin43cee112014-09-25 16:43:34 -0700835 * @param fwdToSw next hop switches
836 */
Sangho Shin99918bd2014-10-08 15:52:35 -0700837 private void setRoutingRule(Switch targetSw, String destSw,
838 List<String> fwdToSw, boolean modified) {
Sangho Shin43cee112014-09-25 16:43:34 -0700839
Sangho Shin43cee112014-09-25 16:43:34 -0700840 if (fwdToSw.isEmpty()) {
841 fwdToSw.add(destSw);
842 }
843
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700844 // if both target SW and dest SW are an edge router, then set IP table
Sangho Shin43cee112014-09-25 16:43:34 -0700845 if (IsEdgeRouter(targetSw.getDpid().toString()) &&
846 IsEdgeRouter(destSw)) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700847 // We assume that there is at least one transit router b/w edge
848 // routers
Sangho Shin43cee112014-09-25 16:43:34 -0700849 Switch destSwitch = mutableTopology.getSwitch(new Dpid(destSw));
850 String subnets = destSwitch.getStringAttribute("subnets");
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700851 setIpTableRouterSubnet(targetSw, subnets, getMplsLabel(destSw)
Sangho Shin5be3e532014-10-03 17:20:58 -0700852 , fwdToSw, modified);
Sangho Shin43cee112014-09-25 16:43:34 -0700853
Sangho Shin43cee112014-09-25 16:43:34 -0700854 String routerIp = destSwitch.getStringAttribute("routerIp");
Sangho Shin5be3e532014-10-03 17:20:58 -0700855 setIpTableRouter(targetSw, routerIp, getMplsLabel(destSw), fwdToSw,
856 null, modified);
Sangho Shin721ca042014-10-09 13:03:40 -0700857 // Edge router can be a transit router
858 setMplsTable(targetSw, getMplsLabel(destSw), fwdToSw, modified);
Sangho Shin43cee112014-09-25 16:43:34 -0700859 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700860 // Only if the target switch is the edge router, then set the IP rules
Sangho Shin43cee112014-09-25 16:43:34 -0700861 else if (IsEdgeRouter(targetSw.getDpid().toString())) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700862 // We assume that there is at least one transit router b/w edge
863 // routers
Sangho Shin43cee112014-09-25 16:43:34 -0700864 Switch destSwitch = mutableTopology.getSwitch(new Dpid(destSw));
865 String routerIp = destSwitch.getStringAttribute("routerIp");
Sangho Shin5be3e532014-10-03 17:20:58 -0700866 setIpTableRouter(targetSw, routerIp, getMplsLabel(destSw), fwdToSw,
867 null, modified);
Sangho Shin721ca042014-10-09 13:03:40 -0700868 // Edge router can be a transit router
869 setMplsTable(targetSw, getMplsLabel(destSw), fwdToSw, modified);
Sangho Shin43cee112014-09-25 16:43:34 -0700870 }
871 // if it is a transit router, then set rules in the MPLS table
872 else {
Sangho Shin5be3e532014-10-03 17:20:58 -0700873 setMplsTable(targetSw, getMplsLabel(destSw), fwdToSw, modified);
Sangho Shin43cee112014-09-25 16:43:34 -0700874 }
875
876 }
877
Sangho Shinfbc572c2014-10-02 16:37:05 -0700878 /**
879 * Set IP forwarding rule to the gateway of each subnet of switches
880 *
881 * @param targetSw Switch to set rules
882 * @param subnets subnet information
883 * @param mplsLabel destination MPLS label
884 * @param fwdToSw router to forward packets to
885 */
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700886 private void setIpTableRouterSubnet(Switch targetSw, String subnets,
Sangho Shin5be3e532014-10-03 17:20:58 -0700887 String mplsLabel, List<String> fwdToSw, boolean modified) {
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700888
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700889 Collection<MatchActionOperationEntry> entries =
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700890 new ArrayList<MatchActionOperationEntry>();
891
892 try {
893 JSONArray arry = new JSONArray(subnets);
894 for (int i = 0; i < arry.length(); i++) {
895 String subnetIp = (String) arry.getJSONObject(i).get("subnetIp");
Sangho Shin5be3e532014-10-03 17:20:58 -0700896 setIpTableRouter(targetSw, subnetIp, mplsLabel, fwdToSw, entries,
897 modified);
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700898 }
899 } catch (JSONException e) {
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700900 e.printStackTrace();
901 }
902
903 if (!entries.isEmpty()) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700904 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700905 getSwId(targetSw.getDpid().toString()));
906
Sangho Shin721ca042014-10-09 13:03:40 -0700907 if (sw13 != null) {
908 try {
909 sw13.pushFlows(entries);
910 } catch (IOException e) {
911 e.printStackTrace();
912 }
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700913 }
914 }
915
916 }
917
Sangho Shin43cee112014-09-25 16:43:34 -0700918 /**
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700919 * Set IP forwarding rule - If the destination is the next hop, then do not
920 * push MPLS, just decrease the NW TTL - Otherwise, push MPLS label and set
921 * the MPLS ID
Sangho Shinfbc572c2014-10-02 16:37:05 -0700922 *
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700923 * @param sw target switch to set rules
Sangho Shin43cee112014-09-25 16:43:34 -0700924 * @param subnetIp Match IP address
925 * @param mplsLabel MPLS label of final destination router
926 * @param fwdToSws next hop routers
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700927 * @param entries
Sangho Shin43cee112014-09-25 16:43:34 -0700928 */
929 private void setIpTableRouter(Switch sw, String subnetIp, String mplsLabel,
Sangho Shin5be3e532014-10-03 17:20:58 -0700930 List<String> fwdToSws, Collection<MatchActionOperationEntry> entries,
931 boolean modified) {
Sangho Shin43cee112014-09-25 16:43:34 -0700932
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700933 Ipv4Match ipMatch = new Ipv4Match(subnetIp);
Sangho Shin43cee112014-09-25 16:43:34 -0700934 List<Action> actions = new ArrayList<>();
Sangho Shin721ca042014-10-09 13:03:40 -0700935 GroupAction groupAction = new GroupAction();
Sangho Shin43cee112014-09-25 16:43:34 -0700936
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700937 // If destination SW is the same as the fwd SW, then do not push MPLS
938 // label
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700939 if (fwdToSws.size() > 1) {
Sangho Shin43cee112014-09-25 16:43:34 -0700940 PushMplsAction pushMplsAction = new PushMplsAction();
941 SetMplsIdAction setIdAction = new SetMplsIdAction(Integer.parseInt(mplsLabel));
942 CopyTtlOutAction copyTtlOutAction = new CopyTtlOutAction();
Sangho Shin463bee52014-09-29 15:14:43 -0700943 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
Sangho Shin43cee112014-09-25 16:43:34 -0700944
Sangho Shin62ce5c12014-10-08 16:24:40 -0700945 //actions.add(pushMplsAction);
946 //actions.add(copyTtlOutAction);
947 //actions.add(decMplsTtlAction);
Saurav Das82e62972014-10-16 14:53:57 -0700948 // actions.add(setIdAction);
Sangho Shin721ca042014-10-09 13:03:40 -0700949 groupAction.setEdgeLabel(Integer.parseInt(mplsLabel));
Sangho Shin43cee112014-09-25 16:43:34 -0700950 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700951 else {
952 String fwdToSw = fwdToSws.get(0);
953 if (getMplsLabel(fwdToSw).equals(mplsLabel)) {
954 DecNwTtlAction decTtlAction = new DecNwTtlAction(1);
955 actions.add(decTtlAction);
956 }
957 else {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700958 SetMplsIdAction setIdAction = new SetMplsIdAction(
959 Integer.parseInt(mplsLabel));
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700960 CopyTtlOutAction copyTtlOutAction = new CopyTtlOutAction();
Sangho Shin463bee52014-09-29 15:14:43 -0700961 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700962
Sangho Shin62ce5c12014-10-08 16:24:40 -0700963 //actions.add(pushMplsAction);
964 //actions.add(copyTtlOutAction);
965 //actions.add(decMplsTtlAction);
Saurav Das82e62972014-10-16 14:53:57 -0700966 // actions.add(setIdAction);
Sangho Shin721ca042014-10-09 13:03:40 -0700967 groupAction.setEdgeLabel(Integer.parseInt(mplsLabel));
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700968 }
969 }
Sangho Shin43cee112014-09-25 16:43:34 -0700970
Sangho Shin43cee112014-09-25 16:43:34 -0700971 for (String fwdSw : fwdToSws) {
972 groupAction.addSwitch(new Dpid(fwdSw));
973 }
974 actions.add(groupAction);
975
Sangho Shin99918bd2014-10-08 15:52:35 -0700976 MatchAction matchAction = new MatchAction(new MatchActionId(matchActionId++),
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700977 new SwitchPort((long) 0, (short) 0), ipMatch, actions);
Sangho Shin43cee112014-09-25 16:43:34 -0700978
Sangho Shin5be3e532014-10-03 17:20:58 -0700979 Operator operator = null;
980 if (modified)
981 operator = Operator.MODIFY;
982 else
983 operator = Operator.ADD;
984
Sangho Shin43cee112014-09-25 16:43:34 -0700985 MatchActionOperationEntry maEntry =
Sangho Shin5be3e532014-10-03 17:20:58 -0700986 new MatchActionOperationEntry(operator, matchAction);
Sangho Shin43cee112014-09-25 16:43:34 -0700987
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700988 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700989 getSwId(sw.getDpid().toString()));
990
Sangho Shin5be3e532014-10-03 17:20:58 -0700991 if (sw13 != null) {
992 try {
Sangho Shinbce900e2014-10-07 17:13:23 -0700993 //printMatchActionOperationEntry(sw, maEntry);
Sangho Shin5be3e532014-10-03 17:20:58 -0700994 if (entries != null)
995 entries.add(maEntry);
996 else
997 sw13.pushFlow(maEntry);
998 } catch (IOException e) {
999 e.printStackTrace();
1000 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -07001001 }
1002
Sangho Shin43cee112014-09-25 16:43:34 -07001003 }
1004
Sangho Shinac5ee2b2014-09-28 21:27:20 -07001005 /**
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001006 * Set MPLS forwarding rules to MPLS table
1007 * </p>
1008 * If the destination is the same as the next hop to forward packets then,
1009 * pop the MPLS label according to PHP rule. Here, if BoS is set, then
1010 * copy TTL In and decrement NW TTL. Otherwise, it just decrement the MPLS
1011 * TTL of the another MPLS header.
1012 * If the next hop is not the destination, just forward packets to next
1013 * hops using Group action.
Sangho Shinfbc572c2014-10-02 16:37:05 -07001014 *
Sangho Shin204b9972014-10-22 11:08:10 -07001015 * TODO: refactoring required
1016 *
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001017 * @param sw Switch to set the rules
Sangho Shin43cee112014-09-25 16:43:34 -07001018 * @param mplsLabel destination MPLS label
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001019 * @param fwdSws next hop switches
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001020 * */
Sangho Shin5be3e532014-10-03 17:20:58 -07001021 private void setMplsTable(Switch sw, String mplsLabel, List<String> fwdSws,
1022 boolean modified) {
Sangho Shin463bee52014-09-29 15:14:43 -07001023
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001024 if (fwdSws.isEmpty())
1025 return;
Sangho Shin43cee112014-09-25 16:43:34 -07001026
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001027 Collection<MatchActionOperationEntry> maEntries =
1028 new ArrayList<MatchActionOperationEntry>();
1029 String fwdSw1 = fwdSws.get(0);
Sangho Shin43cee112014-09-25 16:43:34 -07001030
Sangho Shine842cad2014-10-24 16:07:35 -07001031 //If the next hop is the destination router, do PHP
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001032 if (fwdSws.size() == 1 && mplsLabel.equals(getMplsLabel(fwdSw1))) {
Sangho Shine842cad2014-10-24 16:07:35 -07001033 maEntries.add(buildMAEntry(sw, mplsLabel, fwdSws, true, true));
1034 maEntries.add(buildMAEntry(sw, mplsLabel, fwdSws, true, false));
Sangho Shin9c0f4c32014-09-26 16:02:38 -07001035 }
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001036 else {
Sangho Shine842cad2014-10-24 16:07:35 -07001037 maEntries.add(buildMAEntry(sw, mplsLabel, fwdSws, false, true));
1038 maEntries.add(buildMAEntry(sw, mplsLabel, fwdSws, false, false));
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001039 }
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001040 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin9c0f4c32014-09-26 16:02:38 -07001041 getSwId(sw.getDpid().toString()));
1042
Sangho Shin5be3e532014-10-03 17:20:58 -07001043 if (sw13 != null) {
1044 try {
Sangho Shinbce900e2014-10-07 17:13:23 -07001045 //printMatchActionOperationEntry(sw, maEntry);
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001046 sw13.pushFlows(maEntries);
Sangho Shin5be3e532014-10-03 17:20:58 -07001047 } catch (IOException e) {
1048 e.printStackTrace();
1049 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -07001050 }
Sangho Shin43cee112014-09-25 16:43:34 -07001051 }
1052
Sangho Shin7330c032014-10-20 10:34:51 -07001053
Sangho Shine842cad2014-10-24 16:07:35 -07001054
Sangho Shin7330c032014-10-20 10:34:51 -07001055 // ************************************
1056 // Policy routing classes and functions
1057 // ************************************
1058
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001059 public class PolicyInfo {
Sangho Shin5b8f5452014-10-20 11:46:01 -07001060
Sangho Shin58182672014-10-21 13:23:38 -07001061 public final int TYPE_EXPLICIT = 1;
1062 public final int TYPE_AVOID = 2;
1063
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001064 private String policyId;
1065 private PacketMatch match;
1066 private int priority;
1067 private String tunnelId;
Sangho Shin58182672014-10-21 13:23:38 -07001068 private int type;
Sangho Shin5b8f5452014-10-20 11:46:01 -07001069
Sangho Shin58182672014-10-21 13:23:38 -07001070 public PolicyInfo(String pid, int type, PacketMatch match, int priority,
1071 String tid) {
1072 this.policyId = pid;
1073 this.match = match;
1074 this.priority = priority;
1075 this.tunnelId = tid;
1076 this.type = type;
1077 }
Sangho Shin204b9972014-10-22 11:08:10 -07001078
Fahad Naeem Khan95aa4012014-10-21 14:07:00 -07001079 public PolicyInfo(String pid, PacketMatch match, int priority,
1080 String tid) {
1081 this.policyId = pid;
1082 this.match = match;
1083 this.priority = priority;
1084 this.tunnelId = tid;
Fahad Naeem Khan788895c2014-10-21 19:00:24 -07001085 this.type = 0;
Fahad Naeem Khan95aa4012014-10-21 14:07:00 -07001086 }
1087 public String getPolicyId(){
1088 return this.policyId;
1089 }
1090 public PacketMatch getMatch(){
1091 return this.match;
1092 }
1093 public int getPriority(){
1094 return this.priority;
1095 }
1096 public String getTunnelId(){
1097 return this.tunnelId;
1098 }
1099 public int getType(){
1100 return this.type;
1101 }
Sangho Shin5b8f5452014-10-20 11:46:01 -07001102 }
1103
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001104 public class TunnelInfo {
1105 private String tunnelId;
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001106 private List<Integer> labelIds;
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001107 private List<TunnelRouteInfo> routes;
Sangho Shin81655442014-10-20 14:22:46 -07001108
Sangho Shin6471d202014-10-23 10:59:36 -07001109 public TunnelInfo(String tid, List<Integer> labelIds,
1110 List<TunnelRouteInfo> routes) {
Sangho Shin81655442014-10-20 14:22:46 -07001111 this.tunnelId = tid;
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001112 this.labelIds = labelIds;
Sangho Shin81655442014-10-20 14:22:46 -07001113 this.routes = routes;
1114 }
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001115 public String getTunnelId(){
1116 return this.tunnelId;
1117 }
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001118
1119 public List<Integer> getLabelids() {
1120 return this.labelIds;
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001121 }
1122 public List<TunnelRouteInfo> getRoutes(){
1123 return this.routes;
1124 }
Sangho Shin81655442014-10-20 14:22:46 -07001125 }
1126
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001127 public class TunnelRouteInfo {
Sangho Shin7330c032014-10-20 10:34:51 -07001128
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001129 private String srcSwDpid;
1130 private List<Dpid> fwdSwDpids;
1131 private List<String> route;
Sangho Shin6471d202014-10-23 10:59:36 -07001132 private int gropuId;
Sangho Shin7330c032014-10-20 10:34:51 -07001133
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001134 public TunnelRouteInfo() {
Sangho Shin7330c032014-10-20 10:34:51 -07001135 fwdSwDpids = new ArrayList<Dpid>();
1136 route = new ArrayList<String>();
1137 }
1138
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001139 private void setSrcDpid(String dpid) {
Sangho Shin7330c032014-10-20 10:34:51 -07001140 this.srcSwDpid = dpid;
1141 }
1142
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001143 private void setFwdSwDpid(List<Dpid> dpid) {
Sangho Shin7330c032014-10-20 10:34:51 -07001144 this.fwdSwDpids = dpid;
1145 }
1146
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001147 private void addRoute(String id) {
Sangho Shin7330c032014-10-20 10:34:51 -07001148 route.add(id);
1149 }
1150
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001151 private void setRoute(List<String> r) {
Sangho Shin7330c032014-10-20 10:34:51 -07001152 this.route = r;
1153 }
1154
Sangho Shin6471d202014-10-23 10:59:36 -07001155 private void setGroupId(int groupId) {
1156 this.gropuId = groupId;
1157 }
1158
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001159 public String getSrcSwDpid() {
Sangho Shin7330c032014-10-20 10:34:51 -07001160 return this.srcSwDpid;
1161 }
1162
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001163 public List<Dpid> getFwdSwDpid() {
Sangho Shin7330c032014-10-20 10:34:51 -07001164 return this.fwdSwDpids;
1165 }
1166
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001167 public List<String> getRoute() {
Sangho Shin7330c032014-10-20 10:34:51 -07001168 return this.route;
1169 }
Sangho Shin6471d202014-10-23 10:59:36 -07001170
1171 public int getGroupId() {
1172 return this.gropuId;
1173 }
Sangho Shin7330c032014-10-20 10:34:51 -07001174 }
1175
Sangho Shin15273b62014-10-16 22:22:05 -07001176 /**
Sangho Shin81655442014-10-20 14:22:46 -07001177 * Return the Tunnel table
1178 *
1179 * @return collection of TunnelInfo
1180 */
1181 public Collection<TunnelInfo> getTunnelTable() {
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001182 return this.tunnelTable.values();
Sangho Shin81655442014-10-20 14:22:46 -07001183 }
Sangho Shin204b9972014-10-22 11:08:10 -07001184
Fahad Naeem Khan12fa63a2014-10-21 17:01:27 -07001185 public Collection<PolicyInfo> getPoclicyTable() {
1186 return this.policyTable.values();
1187 }
Sangho Shin81655442014-10-20 14:22:46 -07001188
1189 /**
Sangho Shin5671cbb2014-10-20 22:35:41 -07001190 * Return router DPIDs for the tunnel
1191 *
1192 * @param tid tunnel ID
1193 * @return List of DPID
1194 */
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001195 public List<Integer> getTunnelInfo(String tid) {
Sangho Shin5671cbb2014-10-20 22:35:41 -07001196 TunnelInfo tunnelInfo = tunnelTable.get(tid);
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001197 return tunnelInfo.labelIds;
Sangho Shin5671cbb2014-10-20 22:35:41 -07001198
1199 }
1200
1201 /**
1202 * Get the first group ID for the tunnel for specific source router
1203 * If Segment Stitching was required to create the tunnel, there are
1204 * mutiple source routers.
1205 *
1206 * @param tunnelId ID for the tunnel
1207 * @param dpid source router DPID
1208 * @return the first group ID of the tunnel
1209 */
1210 public int getTunnelGroupId(String tunnelId, String dpid) {
Sangho Shin6471d202014-10-23 10:59:36 -07001211 TunnelInfo tunnelInfo = tunnelTable.get(tunnelId);
1212 for (TunnelRouteInfo routeInfo: tunnelInfo.getRoutes()) {
1213 String tunnelSrcDpid = routeInfo.getSrcSwDpid();
1214 if (tunnelSrcDpid.equals(dpid))
1215 return routeInfo.getGroupId();
1216 }
Sangho Shin5671cbb2014-10-20 22:35:41 -07001217
Sangho Shin6471d202014-10-23 10:59:36 -07001218 return -1;
Sangho Shin5671cbb2014-10-20 22:35:41 -07001219 }
1220
1221 /**
Sangho Shin15273b62014-10-16 22:22:05 -07001222 * Create a tunnel for policy routing
1223 * It delivers the node IDs of tunnels to driver.
1224 * Split the node IDs if number of IDs exceeds the limit for stitching.
1225 *
1226 * @param tunnelId Node IDs for the tunnel
1227 * @param Ids tunnel ID
1228 */
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001229 public boolean createTunnel(String tunnelId, List<Integer> labelIds) {
Sangho Shin15273b62014-10-16 22:22:05 -07001230
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001231 if (labelIds.isEmpty() || labelIds.size() < 2) {
Sangho Shin15273b62014-10-16 22:22:05 -07001232 log.debug("Wrong tunnel information");
1233 return false;
1234 }
1235
Sangho Shin55d00e12014-10-20 12:13:07 -07001236 List<String> Ids = new ArrayList<String>();
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001237 for (Integer label : labelIds) {
1238 Ids.add(label.toString());
Sangho Shin55d00e12014-10-20 12:13:07 -07001239 }
1240
Sangho Shin81655442014-10-20 14:22:46 -07001241 List<TunnelRouteInfo> stitchingRule = getStitchingRule(Ids);
Sangho Shin15273b62014-10-16 22:22:05 -07001242 if (stitchingRule == null) {
Sangho Shin6471d202014-10-23 10:59:36 -07001243 log.debug("Failed to get a tunnel rule.");
Sangho Shin15273b62014-10-16 22:22:05 -07001244 return false;
1245 }
Sangho Shin81655442014-10-20 14:22:46 -07001246 for (TunnelRouteInfo route: stitchingRule) {
Sangho Shin15273b62014-10-16 22:22:05 -07001247 NeighborSet ns = new NeighborSet();
1248 for (Dpid dpid: route.getFwdSwDpid())
1249 ns.addDpid(dpid);
1250
Sangho Shin6471d202014-10-23 10:59:36 -07001251 printTunnelInfo(route.srcSwDpid, tunnelId, route.getRoute(), ns);
1252 int groupId = -1;
1253 if ((groupId =createGroupsForTunnel(tunnelId, route, ns)) < 0) {
1254 log.debug("Failed to create a tunnel at driver.");
1255 return false;
1256 }
1257 route.setGroupId(groupId);
Sangho Shin15273b62014-10-16 22:22:05 -07001258 }
1259
Sangho Shin6471d202014-10-23 10:59:36 -07001260 TunnelInfo tunnelInfo = new TunnelInfo(tunnelId, labelIds,
1261 stitchingRule);
Sangho Shin81655442014-10-20 14:22:46 -07001262 tunnelTable.put(tunnelId, tunnelInfo);
Sangho Shin15273b62014-10-16 22:22:05 -07001263
1264 return true;
1265 }
1266
Sangho Shin1a692c02014-10-23 17:05:41 -07001267 /**
1268 * Create groups for the tunnel
1269 *
1270 * @param tunnelId tunnel ID
1271 * @param routeInfo label stacks for the tunnel
1272 * @param ns NeighborSet to forward packets
1273 * @return group ID, return -1 if it fails
1274 */
Sangho Shin6471d202014-10-23 10:59:36 -07001275 private int createGroupsForTunnel(String tunnelId, TunnelRouteInfo routeInfo,
1276 NeighborSet ns) {
1277
1278 IOF13Switch targetSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
1279 getSwId(routeInfo.srcSwDpid));
1280
1281 if (targetSw == null) {
1282 log.debug("Switch {} is gone.", routeInfo.srcSwDpid);
1283 return -1;
1284 }
1285
1286 List<Integer> Ids = new ArrayList<Integer>();
1287 for (String IdStr: routeInfo.route)
1288 Ids.add(Integer.parseInt(IdStr));
1289
1290 List<PortNumber> ports = getPortsFromNeighborSet(routeInfo.srcSwDpid, ns);
1291 int groupId = targetSw.createGroup(Ids, ports);
1292
1293 return groupId;
1294 }
1295
Sangho Shin15273b62014-10-16 22:22:05 -07001296 /**
1297 * Set policy table for policy routing
1298 *
1299 * @param sw
1300 * @param mplsLabel
Sangho Shin306633a2014-10-20 14:26:55 -07001301 * @return
Sangho Shin15273b62014-10-16 22:22:05 -07001302 */
Sangho Shin306633a2014-10-20 14:26:55 -07001303 public boolean createPolicy(String pid, MACAddress srcMac, MACAddress dstMac,
Sangho Shin15273b62014-10-16 22:22:05 -07001304 Short etherType, IPv4Net srcIp, IPv4Net dstIp, Byte ipProto,
Sangho Shine020cc32014-10-20 13:28:02 -07001305 Short srcTcpPort, Short dstTcpPort, int priority, String tid) {
Sangho Shin15273b62014-10-16 22:22:05 -07001306
Sangho Shin5b8f5452014-10-20 11:46:01 -07001307 PacketMatchBuilder packetBuilder = new PacketMatchBuilder();
1308
1309 if (srcMac != null)
1310 packetBuilder.setSrcMac(srcMac);
1311 if (dstMac != null)
1312 packetBuilder.setDstMac(dstMac);
Sangho Shin58182672014-10-21 13:23:38 -07001313 if (etherType == null) // Cqpd requires the type of IPV4
1314 packetBuilder.setEtherType(Ethernet.TYPE_IPV4);
1315 else
Sangho Shin5b8f5452014-10-20 11:46:01 -07001316 packetBuilder.setEtherType(etherType);
1317 if (srcIp != null)
1318 packetBuilder.setSrcIp(srcIp.address(), srcIp.prefixLen());
1319 if (dstIp != null)
1320 packetBuilder.setDstIp(dstIp.address(), dstIp.prefixLen());
1321 if (ipProto != null)
1322 packetBuilder.setIpProto(ipProto);
1323 if (srcTcpPort > 0)
1324 packetBuilder.setSrcTcpPort(srcTcpPort);
1325 if (dstTcpPort > 0)
1326 packetBuilder.setDstTcpPort(dstTcpPort);
1327 PacketMatch policyMatch = packetBuilder.build();
Sangho Shin81655442014-10-20 14:22:46 -07001328 TunnelInfo tunnelInfo = tunnelTable.get(tid);
Sangho Shin6471d202014-10-23 10:59:36 -07001329 if (tunnelInfo == null) {
1330 log.debug("Tunnel {} is not defined", tid);
1331 return false;
1332 }
Sangho Shin81655442014-10-20 14:22:46 -07001333 List<TunnelRouteInfo> routes = tunnelInfo.routes;
Sangho Shin5b8f5452014-10-20 11:46:01 -07001334
Sangho Shin81655442014-10-20 14:22:46 -07001335 for (TunnelRouteInfo route : routes) {
Sangho Shin15273b62014-10-16 22:22:05 -07001336 List<Action> actions = new ArrayList<>();
1337 GroupAction groupAction = new GroupAction();
Sangho Shin6471d202014-10-23 10:59:36 -07001338 groupAction.setGroupId(route.getGroupId());
Sangho Shin15273b62014-10-16 22:22:05 -07001339 actions.add(groupAction);
1340
1341 MatchAction matchAction = new MatchAction(new MatchActionId(
1342 matchActionId++),
Sangho Shin5b8f5452014-10-20 11:46:01 -07001343 new SwitchPort((long) 0, (short) 0), policyMatch, priority,
1344 actions);
Sangho Shin15273b62014-10-16 22:22:05 -07001345 MatchActionOperationEntry maEntry =
1346 new MatchActionOperationEntry(Operator.ADD, matchAction);
1347
1348 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin81655442014-10-20 14:22:46 -07001349 getSwId(route.srcSwDpid));
Sangho Shin15273b62014-10-16 22:22:05 -07001350
1351 if (sw13 != null) {
1352 printMatchActionOperationEntry(sw13, maEntry);
1353 try {
1354 sw13.pushFlow(maEntry);
1355 } catch (IOException e) {
1356 e.printStackTrace();
Sangho Shin306633a2014-10-20 14:26:55 -07001357 return false;
Sangho Shin15273b62014-10-16 22:22:05 -07001358 }
1359 }
1360 }
Sangho Shin5b8f5452014-10-20 11:46:01 -07001361
1362 PolicyInfo policyInfo = new PolicyInfo(pid, policyMatch, priority, tid);
Sangho Shine020cc32014-10-20 13:28:02 -07001363 policyTable.put(pid, policyInfo);
Sangho Shin306633a2014-10-20 14:26:55 -07001364
1365 return true;
Sangho Shin15273b62014-10-16 22:22:05 -07001366 }
1367
1368 /**
Sangho Shin1ad7be02014-10-20 16:56:49 -07001369 * Split the nodes IDs into multiple tunnel if Segment Stitching is required.
1370 * We assume that the first node ID is the one of source router, and the last
1371 * node ID is that of the destination router.
Sangho Shin15273b62014-10-16 22:22:05 -07001372 *
Sangho Shin1ad7be02014-10-20 16:56:49 -07001373 * @param route list of node IDs
1374 * @return List of the TunnelRoutInfo
Sangho Shin15273b62014-10-16 22:22:05 -07001375 */
Sangho Shin81655442014-10-20 14:22:46 -07001376 private List<TunnelRouteInfo> getStitchingRule(List<String> route) {
Sangho Shin15273b62014-10-16 22:22:05 -07001377
Sangho Shin1a692c02014-10-23 17:05:41 -07001378 if (route.isEmpty() || route.size() < 3)
Sangho Shin15273b62014-10-16 22:22:05 -07001379 return null;
1380
Sangho Shin81655442014-10-20 14:22:46 -07001381 List<TunnelRouteInfo> rules = new ArrayList<TunnelRouteInfo>();
Sangho Shin15273b62014-10-16 22:22:05 -07001382
1383 Switch srcSw = this.getSwitchFromNodeId(route.get(0));
Sangho Shin6471d202014-10-23 10:59:36 -07001384 if (srcSw == null) {
1385 log.warn("Switch is not found for Node SID {}", route.get(0));
1386 return null;
1387 }
Sangho Shin15273b62014-10-16 22:22:05 -07001388 String srcDpid = srcSw.getDpid().toString();
1389
Sangho Shin15273b62014-10-16 22:22:05 -07001390 int i = 0;
Sangho Shine020cc32014-10-20 13:28:02 -07001391 TunnelRouteInfo routeInfo = new TunnelRouteInfo();
Sangho Shin1a692c02014-10-23 17:05:41 -07001392 boolean checkNeighbor = false;
Sangho Shin6471d202014-10-23 10:59:36 -07001393 String prevAdjacencySid = null;
1394 String prevNodeId = null;
Sangho Shin15273b62014-10-16 22:22:05 -07001395
1396 for (String nodeId: route) {
Sangho Shin6471d202014-10-23 10:59:36 -07001397 // The first node ID is always the source router.
1398 // We assume that the first ID cannot be an Adjacency SID.
Sangho Shin15273b62014-10-16 22:22:05 -07001399 if (i == 0) {
Sangho Shin15273b62014-10-16 22:22:05 -07001400 srcSw = getSwitchFromNodeId(nodeId);
Sangho Shin1a692c02014-10-23 17:05:41 -07001401 if (srcDpid == null)
1402 srcDpid = srcSw.getDpid().toString();
1403 routeInfo.setSrcDpid(srcDpid);
1404 checkNeighbor = true;
Sangho Shin15273b62014-10-16 22:22:05 -07001405 i++;
1406 }
Sangho Shin1a692c02014-10-23 17:05:41 -07001407 // if this is the first node ID to put the label stack..
Sangho Shin6471d202014-10-23 10:59:36 -07001408 else if (i == 1) {
Sangho Shin1a692c02014-10-23 17:05:41 -07001409 if (checkNeighbor) {
1410 List<Dpid> fwdSws = getDpidIfNeighborOf(nodeId, srcSw);
1411 // if nodeId is NOT the neighbor of srcSw..
1412 if (fwdSws.isEmpty()) {
1413 fwdSws = getForwardingSwitchForNodeId(srcSw,nodeId);
1414 if (fwdSws == null || fwdSws.isEmpty()) {
1415 log.warn("There is no route from node {} to node {}",
1416 srcSw.getDpid(), nodeId);
1417 return null;
Sangho Shin6471d202014-10-23 10:59:36 -07001418 }
Sangho Shin6471d202014-10-23 10:59:36 -07001419 routeInfo.addRoute(nodeId);
Sangho Shin6471d202014-10-23 10:59:36 -07001420 i++;
1421 }
Sangho Shin1a692c02014-10-23 17:05:41 -07001422 routeInfo.setFwdSwDpid(fwdSws);
Sangho Shin6471d202014-10-23 10:59:36 -07001423 // we check only the next node ID of the source router
1424 checkNeighbor = false;
Sangho Shin1a692c02014-10-23 17:05:41 -07001425 }
1426 // if neighbor check is already done, then just add it
1427 else {
Sangho Shin6471d202014-10-23 10:59:36 -07001428 routeInfo.addRoute(nodeId);
Sangho Shin15273b62014-10-16 22:22:05 -07001429 i++;
1430 }
1431 }
Sangho Shin6471d202014-10-23 10:59:36 -07001432 // if i > 1
Sangho Shin15273b62014-10-16 22:22:05 -07001433 else {
Sangho Shin6471d202014-10-23 10:59:36 -07001434 // If the adjacency SID is pushed and the next SID is the destination
1435 // of the adjacency SID, then do not add the SID.
1436 if (prevAdjacencySid != null) {
1437 if (isAdjacencySidNeighborOf(prevNodeId, prevAdjacencySid, nodeId)) {
1438 prevAdjacencySid = null;
1439 continue;
1440 }
1441 prevAdjacencySid = null;
1442 }
Sangho Shin15273b62014-10-16 22:22:05 -07001443 routeInfo.addRoute(nodeId);
1444 i++;
1445 }
1446
Sangho Shin1a692c02014-10-23 17:05:41 -07001447 // If the adjacency ID is added the label stack,
1448 // then we need to check if the next node is the destination of the adjacency SID
1449 if (isAdjacencySid(nodeId))
1450 prevAdjacencySid = nodeId;
1451
Sangho Shin1ad7be02014-10-20 16:56:49 -07001452 // If the number of labels reaches the limit, start over the procedure
Sangho Shin15273b62014-10-16 22:22:05 -07001453 if (i == MAX_NUM_LABELS+1) {
Sangho Shin1a692c02014-10-23 17:05:41 -07001454
Sangho Shin81655442014-10-20 14:22:46 -07001455 rules.add(routeInfo);
Sangho Shine020cc32014-10-20 13:28:02 -07001456 routeInfo = new TunnelRouteInfo();
Sangho Shin1a692c02014-10-23 17:05:41 -07001457
Sangho Shin62325582014-10-24 10:36:09 -07001458 if (isAdjacencySid(nodeId)) {
1459 // If the previous sub tunnel finishes with adjacency SID,
1460 // then we need to start the procedure from the adjacency
1461 // destination ID.
1462 List<Switch> destNodeList =
1463 getAdjacencyDestinationNode(prevNodeId, nodeId);
1464 if (destNodeList == null || destNodeList.isEmpty()) {
1465 log.warn("Cannot find destination node for adjacencySID {}",
1466 nodeId);
1467 return null;
1468 }
1469 // If the previous sub tunnel finishes with adjacency SID with
1470 // multiple ports, then we need to remove the adjacency Sid
1471 // from the previous sub tunnel and start the new sub tunnel
1472 // with the adjacency Sid. Technically, the new subtunnel
1473 // forward packets to the port assigned to the adjacency Sid
1474 // and the label stack starts with the next ID.
1475 // This is to avoid to install new policy rule to multiple nodes for stitching when the
1476 // adjacency Sid that has more than one port.
1477 if (destNodeList.size() > 1) {
1478 rules.get(rules.size()-1).route.remove(nodeId);
1479 srcSw = getSwitchFromNodeId(prevNodeId);
1480 List<Dpid> fwdSws = getDpidIfNeighborOf(nodeId, srcSw);
1481 routeInfo.setFwdSwDpid(fwdSws);
1482 routeInfo.setSrcDpid(srcSw.getDpid().toString());
1483 i = 1;
1484 checkNeighbor = false;
1485 continue;
1486 }
1487 else {
Sangho Shin1a692c02014-10-23 17:05:41 -07001488 srcSw = destNodeList.get(0);
Sangho Shin62325582014-10-24 10:36:09 -07001489 }
1490 }
1491 else {
1492 srcSw = getSwitchFromNodeId(nodeId);
Sangho Shin1a692c02014-10-23 17:05:41 -07001493 }
1494 srcDpid = srcSw.getDpid().toString();
Sangho Shin15273b62014-10-16 22:22:05 -07001495 routeInfo.setSrcDpid(srcDpid);
1496 i = 1;
1497 checkNeighbor = true;
1498 }
Sangho Shin6471d202014-10-23 10:59:36 -07001499
1500 if (prevAdjacencySid == null)
1501 prevNodeId = nodeId;
Sangho Shin15273b62014-10-16 22:22:05 -07001502 }
1503
Sangho Shin1a692c02014-10-23 17:05:41 -07001504
Sangho Shineb148ea2014-10-24 12:44:15 -07001505 if (i < MAX_NUM_LABELS+1 && (routeInfo.getFwdSwDpid() != null &&
1506 !routeInfo.getFwdSwDpid().isEmpty())) {
Sangho Shin81655442014-10-20 14:22:46 -07001507 rules.add(routeInfo);
Sangho Shineb148ea2014-10-24 12:44:15 -07001508 // NOTE: empty label stack can happen, but forwarding destination should be set
Sangho Shin15273b62014-10-16 22:22:05 -07001509 }
1510
1511 return rules;
1512 }
1513
Sangho Shin5b8f5452014-10-20 11:46:01 -07001514 /**
1515 * Remove all policies applied to specific tunnel.
1516 *
1517 * @param srcMac
1518 * @param dstMac
1519 * @param etherType
1520 * @param srcIp
1521 * @param dstIp
1522 * @param ipProto
1523 * @param srcTcpPort
1524 * @param dstTcpPort
1525 * @param tid
Sangho Shin306633a2014-10-20 14:26:55 -07001526 * @return
Sangho Shin5b8f5452014-10-20 11:46:01 -07001527 */
Sangho Shin306633a2014-10-20 14:26:55 -07001528 public boolean removePolicy(String pid) {
Sangho Shine020cc32014-10-20 13:28:02 -07001529 PolicyInfo policyInfo = policyTable.get(pid);
Sangho Shin5671cbb2014-10-20 22:35:41 -07001530 if (policyInfo == null)
1531 return false;
Sangho Shin5b8f5452014-10-20 11:46:01 -07001532 PacketMatch policyMatch = policyInfo.match;
Sangho Shine020cc32014-10-20 13:28:02 -07001533 String tid = policyInfo.tunnelId;
Sangho Shin5b8f5452014-10-20 11:46:01 -07001534 int priority = policyInfo.priority;
1535
1536 List<Action> actions = new ArrayList<>();
1537 int gropuId = 0; // dummy group ID
1538 GroupAction groupAction = new GroupAction();
1539 groupAction.setGroupId(gropuId);
1540 actions.add(groupAction);
1541
1542 MatchAction matchAction = new MatchAction(new MatchActionId(
1543 matchActionId++),
1544 new SwitchPort((long) 0, (short) 0), policyMatch, priority,
1545 actions);
1546 MatchActionOperationEntry maEntry =
1547 new MatchActionOperationEntry(Operator.REMOVE, matchAction);
1548
Sangho Shin81655442014-10-20 14:22:46 -07001549 TunnelInfo tunnelInfo = tunnelTable.get(tid);
Sangho Shin5671cbb2014-10-20 22:35:41 -07001550 if (tunnelInfo == null)
1551 return false;
Sangho Shin81655442014-10-20 14:22:46 -07001552 List<TunnelRouteInfo> routes = tunnelInfo.routes;
1553
1554 for (TunnelRouteInfo route : routes) {
Sangho Shin5b8f5452014-10-20 11:46:01 -07001555 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin81655442014-10-20 14:22:46 -07001556 getSwId(route.srcSwDpid));
Sangho Shin5b8f5452014-10-20 11:46:01 -07001557
Sangho Shin5671cbb2014-10-20 22:35:41 -07001558 if (sw13 == null) {
1559 return false;
1560 }
1561 else {
Sangho Shin5b8f5452014-10-20 11:46:01 -07001562 printMatchActionOperationEntry(sw13, maEntry);
1563 try {
1564 sw13.pushFlow(maEntry);
1565 } catch (IOException e) {
1566 e.printStackTrace();
1567 log.debug("policy remove failed due to pushFlow() exception");
Sangho Shin306633a2014-10-20 14:26:55 -07001568 return false;
Sangho Shin5b8f5452014-10-20 11:46:01 -07001569 }
1570 }
1571 }
1572
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001573 policyTable.remove(pid);
Sangho Shin5b8f5452014-10-20 11:46:01 -07001574 log.debug("Policy {} is removed.", pid);
Sangho Shin306633a2014-10-20 14:26:55 -07001575 return true;
Sangho Shine020cc32014-10-20 13:28:02 -07001576 }
Sangho Shin5b8f5452014-10-20 11:46:01 -07001577
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001578 /**
1579 * Remove a tunnel
1580 * It removes all groups for the tunnel if the tunnel is not used for any
1581 * policy.
1582 *
1583 * @param tunnelId tunnel ID to remove
1584 */
Sangho Shin306633a2014-10-20 14:26:55 -07001585 public boolean removeTunnel(String tunnelId) {
Sangho Shin55d00e12014-10-20 12:13:07 -07001586
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001587 // Check if the tunnel is used for any policy
1588 for (PolicyInfo policyInfo: policyTable.values()) {
Sangho Shina000c612014-10-21 14:17:59 -07001589 if (policyInfo.tunnelId.equals(tunnelId)) {
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001590 log.debug("Tunnel {} is still used for the policy {}.",
1591 policyInfo.policyId, tunnelId);
1592 return false;
1593 }
1594 }
1595
1596 TunnelInfo tunnelInfo = tunnelTable.get(tunnelId);
Sangho Shin5671cbb2014-10-20 22:35:41 -07001597 if (tunnelInfo == null)
1598 return false;
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001599
1600 List<TunnelRouteInfo> routes = tunnelInfo.routes;
1601 for (TunnelRouteInfo route: routes) {
1602 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
1603 getSwId(route.srcSwDpid));
1604
Sangho Shin5671cbb2014-10-20 22:35:41 -07001605 if (sw13 == null) {
1606 return false;
1607 }
1608 else {
Sangho Shin93f623c2014-10-24 12:59:53 -07001609 if (!sw13.removeGroup(route.getGroupId())) {
Sangho Shine842cad2014-10-24 16:07:35 -07001610 log.warn("Faied to remove the tunnel {} at driver",
1611 tunnelId);
Sangho Shin93f623c2014-10-24 12:59:53 -07001612 return false; }
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001613 }
1614 }
1615
1616 tunnelTable.remove(tunnelId);
Sangho Shine842cad2014-10-24 16:07:35 -07001617 log.debug("Tunnel {} was removed successfully.", tunnelId);
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001618
Sangho Shin306633a2014-10-20 14:26:55 -07001619 return true;
Sangho Shin55d00e12014-10-20 12:13:07 -07001620 }
1621
Sangho Shin7330c032014-10-20 10:34:51 -07001622 // ************************************
1623 // Utility functions
1624 // ************************************
1625
Sangho Shin1a692c02014-10-23 17:05:41 -07001626 /**
1627 * Get the destination Nodes of the adjacency Sid
1628 *
1629 * @param nodeId node ID of the adjacency Sid
1630 * @param adjacencySid adjacency Sid
1631 * @return List of Switch, empty list if not found
1632 */
1633 private List<Switch> getAdjacencyDestinationNode(String nodeId, String adjacencySid) {
1634 List<Switch> dstSwList = new ArrayList<Switch>();
1635
1636 HashMap<Integer, List<Integer>> adjacencySidInfo =
1637 adjacencySidTable.get(Integer.valueOf(nodeId));
1638 List<Integer> ports = adjacencySidInfo.get(Integer.valueOf(adjacencySid));
1639 Switch srcSw = getSwitchFromNodeId(nodeId);
1640 for (Integer port: ports) {
1641 for (Link link: srcSw.getOutgoingLinks()) {
1642 if (link.getSrcPort().getPortNumber().value() == port) {
1643 dstSwList.add(link.getDstSwitch());
1644 }
1645 }
1646 }
1647
1648 return dstSwList;
1649
1650 }
1651
1652 /**
1653 * Get the DPID of the router with node ID IF the node ID is the neighbor of the
1654 * Switch srcSW.
1655 * If the nodeId is the adjacency Sid, then it returns the destination router DPIDs.
1656 *
1657 * @param nodeId Node ID to check
1658 * @param srcSw target Switch
1659 * @return List of DPID of nodeId, empty list if the nodeId is not the neighbor of srcSW
1660 */
1661 private List<Dpid> getDpidIfNeighborOf(String nodeId, Switch srcSw) {
1662 List<Dpid> fwdSws = new ArrayList<Dpid>();
1663 // if the nodeID is the adjacency ID, then we need to regard it as the
1664 // neighbor node ID and need to return the destination router DPID(s)
1665 if (isAdjacencySid(nodeId)) {
1666 String srcNodeId = this.getMplsLabel(srcSw.getDpid().toString());
1667 HashMap<Integer, List<Integer>> adjacencySidInfo =
1668 adjacencySidTable.get(Integer.valueOf(srcNodeId));
1669 List<Integer> ports = adjacencySidInfo.get(Integer.valueOf(nodeId));
1670
1671 for (Integer port: ports) {
1672 for (Link link: srcSw.getOutgoingLinks()) {
1673 if (link.getSrcPort().getPortNumber().value() == port) {
1674 fwdSws.add(link.getDstSwitch().getDpid());
1675 }
1676 }
1677 }
1678 }
1679 else {
1680 List<Dpid> fwdSwDpids = getForwardingSwitchForNodeId(srcSw,nodeId);
1681 if (fwdSwDpids == null || fwdSwDpids.isEmpty()) {
1682 log.warn("There is no route from node {} to node {}",
1683 srcSw.getDpid(), nodeId);
1684 return null;
1685 }
1686
1687 for (Dpid dpid: fwdSwDpids) {
1688 if (getMplsLabel(dpid.toString()).toString().equals(nodeId)) {
1689 fwdSws.add(dpid);
1690 break;
1691 }
1692 }
1693 }
1694
1695 return fwdSws;
1696 }
1697
1698 /**
1699 * Get port numbers of the neighbor set
1700 *
1701 * @param srcSwDpid source switch
1702 * @param ns Neighbor set of the switch
1703 * @return List of PortNumber, null if not found
1704 */
Sangho Shin6471d202014-10-23 10:59:36 -07001705 private List<PortNumber> getPortsFromNeighborSet(String srcSwDpid, NeighborSet ns) {
1706
1707 List<PortNumber> portList = new ArrayList<PortNumber>();
1708 Switch srcSwitch = mutableTopology.getSwitch(new Dpid(srcSwDpid));
1709 if (srcSwitch == null)
1710 return null;
1711 for (Dpid neighborDpid: ns.getDpids()) {
1712 Link link = srcSwitch.getLinkToNeighbor(neighborDpid);
1713 portList.add(link.getSrcPort().getNumber());
1714 }
1715
1716 return portList;
1717 }
1718
Sangho Shine842cad2014-10-24 16:07:35 -07001719 /**
1720 * Check whether the router with preNodeid is connected to the router
1721 * with nodeId via adjacencySid or not
1722 *
1723 * @param prevNodeId the router node ID of the adjacencySid
1724 * @param adjacencySid adjacency SID
1725 * @param nodeId the router node ID to check
1726 * @return
1727 */
1728 private boolean isAdjacencySidNeighborOf(String prevNodeId, String adjacencySid, String nodeId) {
Sangho Shin6471d202014-10-23 10:59:36 -07001729
1730 HashMap<Integer, List<Integer>> adjacencySidInfo = adjacencySidTable.get(Integer.valueOf(prevNodeId));
Sangho Shine842cad2014-10-24 16:07:35 -07001731 List<Integer> ports = adjacencySidInfo.get(Integer.valueOf(adjacencySid));
Sangho Shin6471d202014-10-23 10:59:36 -07001732
1733 for (Integer port: ports) {
1734 Switch sw = getSwitchFromNodeId(prevNodeId);
1735 for (Link link: sw.getOutgoingLinks()) {
1736 if (link.getSrcPort().getPortNumber().value() == port) {
1737 if (getMplsLabel(link.getDstPort().getDpid().toString()).equals(nodeId)) {
1738 return true;
1739 }
1740 }
1741 }
1742 }
1743
1744 return false;
1745 }
1746
Sangho Shine842cad2014-10-24 16:07:35 -07001747 /**
1748 * Check if the node ID is the adjacency ID or not
1749 *
1750 * @param nodeId to check
1751 * @return true if the node ID is the adjacency ID, false otherwise
1752 */
Sangho Shin6471d202014-10-23 10:59:36 -07001753 private boolean isAdjacencySid(String nodeId) {
1754 // XXX The rule might change
1755 if (Integer.parseInt(nodeId) > 10000)
1756 return true;
1757
1758 return false;
1759 }
1760
Sangho Shin15273b62014-10-16 22:22:05 -07001761 /**
Sangho Shinced05b62014-10-22 11:23:14 -07001762 * Returns the Adjacency IDs for the node
1763 *
1764 * @param nodeSid Node SID
Sangho Shincfef3922014-10-22 12:04:16 -07001765 * @return Collection of Adjacency ID
Sangho Shinced05b62014-10-22 11:23:14 -07001766 */
Sangho Shincfef3922014-10-22 12:04:16 -07001767 public Collection<Integer> getAdjacencyIds(int nodeSid) {
1768 HashMap<Integer, List<Integer>> adjecencyInfo =
Sangho Shin6471d202014-10-23 10:59:36 -07001769 adjacencySidTable.get(Integer.valueOf(nodeSid));
Sangho Shincfef3922014-10-22 12:04:16 -07001770
1771 return adjecencyInfo.keySet();
1772 }
1773
1774 /**
1775 * Returns the Adjacency Info for the node
1776 *
1777 * @param nodeSid Node SID
1778 * @return HashMap of <AdjacencyID, list of ports>
1779 */
1780 public HashMap<Integer, List<Integer>> getAdjacencyInfo(int nodeSid) {
Sangho Shin6471d202014-10-23 10:59:36 -07001781 return adjacencySidTable.get(Integer.valueOf(nodeSid));
Sangho Shincfef3922014-10-22 12:04:16 -07001782 }
1783
Sangho Shine842cad2014-10-24 16:07:35 -07001784 /**
1785 * Parse the adjacency jason string and build the adjacency Table
1786 *
1787 * @param adjInfo adjacency info jason string
1788 * @return HashMap<Adjacency ID, List of ports> object
1789 * @throws JSONException
1790 */
1791 private HashMap<Integer, List<Integer>> parseAdjacencySidInfo(String adjInfo)
1792 throws JSONException {
Sangho Shincfef3922014-10-22 12:04:16 -07001793 JSONArray arry = new JSONArray(adjInfo);
1794 HashMap<Integer, List<Integer>> AdjacencyInfo =
1795 new HashMap<Integer, List<Integer>>();
1796
1797 for (int i = 0; i < arry.length(); i++) {
1798 Integer adjId = (Integer) arry.getJSONObject(i).get("adjSid");
1799 JSONArray portNos = (JSONArray) arry.getJSONObject(i).get("ports");
1800 if (adjId == null || portNos == null)
1801 continue;
1802
1803 List<Integer> portNoList = new ArrayList<Integer>();
1804 for (int j = 0; j < portNos.length(); j++) {
Sangho Shin62325582014-10-24 10:36:09 -07001805 portNoList.add(Integer.valueOf(portNos.getInt(j)));
Sangho Shincfef3922014-10-22 12:04:16 -07001806 }
1807 AdjacencyInfo.put(adjId, portNoList);
1808 }
1809 return AdjacencyInfo;
Sangho Shinced05b62014-10-22 11:23:14 -07001810 }
1811
1812 /**
Sangho Shine842cad2014-10-24 16:07:35 -07001813 * Build the MatchActionOperationEntry according to the flag
1814 *
1815 * @param sw node ID to push for MPLS label
1816 * @param mplsLabel List of Switch DPIDs to forwards packets to
1817 * @param fwdSws PHP flag
1818 * @param Bos BoS flag
1819 * @param isTransitRouter
1820 * @return MatchiACtionOperationEntry object
1821 */
1822 private MatchActionOperationEntry buildMAEntry(Switch sw,
1823 String mplsLabel, List<String> fwdSws, boolean php,
1824 boolean Bos) {
1825 MplsMatch mplsMatch = new MplsMatch(Integer.parseInt(mplsLabel), Bos);
1826 List<Action> actions = new ArrayList<Action>();
1827
1828 PopMplsAction popActionBos = new PopMplsAction(EthType.IPv4);
1829 PopMplsAction popAction = new PopMplsAction(EthType.MPLS_UNICAST);
1830 CopyTtlInAction copyTtlInAction = new CopyTtlInAction();
1831 DecNwTtlAction decNwTtlAction = new DecNwTtlAction(1);
1832 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
1833
1834 if (php) {
1835 actions.add(copyTtlInAction);
1836 if (Bos) {
1837 actions.add(popActionBos);
1838 actions.add(decNwTtlAction);
1839 }
1840 else {
1841 actions.add(popAction);
1842 actions.add(decMplsTtlAction);
1843 }
1844 }
1845 else {
1846 actions.add(decMplsTtlAction);
1847 }
1848
1849 if (!supportTransitECMP && isTransitRouter(sw) && !php) {
1850 PortNumber port = pickOnePort(sw, fwdSws);
1851 if (port == null) {
1852 log.warn("Failed to get a port from NeightborSet");
1853 return null;
1854 }
1855 OutputAction outputAction = new OutputAction(port);
1856 Switch destSwitch =
1857 mutableTopology.getSwitch(new Dpid(fwdSws.get(0)));
1858 MacAddress srcMac =
1859 MacAddress.of(sw.getStringAttribute("routerMac"));
1860 MacAddress dstMac =
1861 MacAddress.of(destSwitch.getStringAttribute("routerMac"));
1862 SetSAAction setSAAction = new SetSAAction(srcMac);
1863 SetDAAction setDAAction = new SetDAAction(dstMac);
1864 actions.add(outputAction);
1865 actions.add(setSAAction);
1866 actions.add(setDAAction);
1867 }
1868 else {
1869 GroupAction groupAction = new GroupAction();
1870 for (String dpid: fwdSws)
1871 groupAction.addSwitch(new Dpid(dpid));
1872 actions.add(groupAction);
1873 }
1874
1875 MatchAction matchAction = new MatchAction(new MatchActionId(matchActionId++),
1876 new SwitchPort((long) 0, (short) 0), mplsMatch, actions);
1877 Operator operator = Operator.ADD;
1878 MatchActionOperationEntry maEntry =
1879 new MatchActionOperationEntry(operator, matchAction);
1880
1881 return maEntry;
1882 }
1883
1884 /**
1885 * Pick a router from the neighbor set and return the port
1886 * connected to the router.
1887 *
1888 * @param sw source switch
1889 * @param fwdSwDpids neighbor set of the switch
1890 * @return PortNumber connected to one of the neighbors
1891 */
1892 private PortNumber pickOnePort(Switch sw, List<String> fwdSwDpids) {
1893 for (Link link: sw.getOutgoingLinks()) {
1894 if (link.getDstSwitch().getDpid().toString().equals(fwdSwDpids.get(0)))
1895 return link.getSrcPort().getNumber();
1896 }
1897
1898 return null;
1899 }
1900
1901 /**
1902 * check if the router is the transit router or not
1903 *
1904 * @param sw router switch to check
1905 * @return true if the switch is the transit router, false otherwise
1906 */
1907 private boolean isTransitRouter(Switch sw) {
1908 int i = 0;
1909 for(Switch neighbor: sw.getNeighbors()) {
1910 i++;
1911 }
1912 if (i > 1)
1913 return true;
1914 else
1915 return false;
1916 }
1917
1918 /**
Sangho Shin7330c032014-10-20 10:34:51 -07001919 * Get the forwarding Switch DPIDs to send packets to a node
Sangho Shin15273b62014-10-16 22:22:05 -07001920 *
Sangho Shin7330c032014-10-20 10:34:51 -07001921 * @param srcSw source switch
1922 * @param nodeId destination node Id
1923 * @return list of switch DPID to forward packets to
Sangho Shin15273b62014-10-16 22:22:05 -07001924 */
Sangho Shin7330c032014-10-20 10:34:51 -07001925 private List<Dpid> getForwardingSwitchForNodeId(Switch srcSw, String nodeId) {
Sangho Shin15273b62014-10-16 22:22:05 -07001926
Sangho Shin7330c032014-10-20 10:34:51 -07001927 List<Dpid> fwdSws = new ArrayList<Dpid>();
1928 Switch destSw = null;
Sangho Shin15273b62014-10-16 22:22:05 -07001929
Sangho Shin7330c032014-10-20 10:34:51 -07001930 destSw = getSwitchFromNodeId(nodeId);
1931
1932 if (destSw == null) {
1933 log.debug("Cannot find the switch with ID {}", nodeId);
1934 return null;
1935 }
1936
1937 ECMPShortestPathGraph ecmpSPG = new ECMPShortestPathGraph(srcSw);
1938
1939 HashMap<Integer, HashMap<Switch, ArrayList<ArrayList<Dpid>>>> switchVia =
1940 ecmpSPG.getAllLearnedSwitchesAndVia();
1941 for (Integer itrIdx : switchVia.keySet()) {
1942 HashMap<Switch, ArrayList<ArrayList<Dpid>>> swViaMap =
1943 switchVia.get(itrIdx);
1944 for (Switch targetSw : swViaMap.keySet()) {
1945 String destSwDpid = destSw.getDpid().toString();
1946 if (targetSw.getDpid().toString().equals(destSwDpid)) {
1947 for (ArrayList<Dpid> via : swViaMap.get(targetSw)) {
1948 if (via.isEmpty()) {
1949 fwdSws.add(destSw.getDpid());
1950 }
1951 else {
Sangho Shina000c612014-10-21 14:17:59 -07001952 Dpid firstVia = via.get(via.size()-1);
1953 fwdSws.add(firstVia);
Sangho Shin7330c032014-10-20 10:34:51 -07001954 }
1955 }
1956 }
1957 }
1958 }
1959
1960 return fwdSws;
Sangho Shin15273b62014-10-16 22:22:05 -07001961 }
1962
Sangho Shin7330c032014-10-20 10:34:51 -07001963 /**
1964 * Get switch for the node Id specified
1965 *
1966 * @param nodeId node ID for switch
1967 * @return Switch
1968 */
1969 private Switch getSwitchFromNodeId(String nodeId) {
Fahad Naeem Khan4444b952014-10-18 22:30:50 -07001970
Sangho Shin7330c032014-10-20 10:34:51 -07001971 for (Switch sw : mutableTopology.getSwitches()) {
1972 String id = sw.getStringAttribute("nodeSid");
1973 if (id.equals(nodeId)) {
1974 return sw;
1975 }
1976 }
1977
1978 return null;
1979 }
Fahad Naeem Khan4444b952014-10-18 22:30:50 -07001980
Sangho Shin43cee112014-09-25 16:43:34 -07001981 /**
Sangho Shin7330c032014-10-20 10:34:51 -07001982 * Convert a string DPID to its Switch Id (integer)
Sangho Shinfbc572c2014-10-02 16:37:05 -07001983 *
Sangho Shin7330c032014-10-20 10:34:51 -07001984 * @param dpid
1985 * @return
Sangho Shin43cee112014-09-25 16:43:34 -07001986 */
Sangho Shin7330c032014-10-20 10:34:51 -07001987 private long getSwId(String dpid) {
Sangho Shin43cee112014-09-25 16:43:34 -07001988
Sangho Shin7330c032014-10-20 10:34:51 -07001989 long swId = 0;
Sangho Shin43cee112014-09-25 16:43:34 -07001990
Sangho Shin7330c032014-10-20 10:34:51 -07001991 String swIdHexStr = "0x"+dpid.substring(dpid.lastIndexOf(":") + 1);
1992 if (swIdHexStr != null)
1993 swId = Integer.decode(swIdHexStr);
Sangho Shin43cee112014-09-25 16:43:34 -07001994
Sangho Shin7330c032014-10-20 10:34:51 -07001995 return swId;
1996 }
Sangho Shin43cee112014-09-25 16:43:34 -07001997
Sangho Shin7330c032014-10-20 10:34:51 -07001998 /**
1999 * Check if the switch is the edge router or not.
2000 *
2001 * @param dpid Dpid of the switch to check
2002 * @return true if it is an edge router, otherwise false
2003 */
2004 private boolean IsEdgeRouter(String dpid) {
Sangho Shin0df01982014-09-25 17:11:18 -07002005
Sangho Shin7330c032014-10-20 10:34:51 -07002006 for (Switch sw : mutableTopology.getSwitches()) {
2007 String dpidStr = sw.getDpid().toString();
2008 if (dpid.equals(dpidStr)) {
2009 /*
2010 String subnetInfo = sw.getStringAttribute("subnets");
2011 if (subnetInfo == null || subnetInfo.equals("[]")) {
2012 return false;
2013 }
2014 else
2015 return true;
2016 */
2017 String isEdge = sw.getStringAttribute("isEdgeRouter");
2018 if (isEdge != null) {
2019 if (isEdge.equals("true"))
2020 return true;
2021 else
2022 return false;
2023 }
Sangho Shin43cee112014-09-25 16:43:34 -07002024 }
2025 }
2026
Sangho Shin7330c032014-10-20 10:34:51 -07002027 return false;
Sangho Shineb083032014-09-22 16:11:34 -07002028 }
2029
2030 /**
2031 * Get MPLS label reading the config file
Sangho Shinfbc572c2014-10-02 16:37:05 -07002032 *
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002033 * @param dipid DPID of the switch
Sangho Shineb083032014-09-22 16:11:34 -07002034 * @return MPLS label for the switch
2035 */
Sangho Shin43cee112014-09-25 16:43:34 -07002036 private String getMplsLabel(String dpid) {
Sangho Shineb083032014-09-22 16:11:34 -07002037
2038 String mplsLabel = null;
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002039 for (Switch sw : mutableTopology.getSwitches()) {
Sangho Shin43cee112014-09-25 16:43:34 -07002040 String dpidStr = sw.getDpid().toString();
2041 if (dpid.equals(dpidStr)) {
Sangho Shineb083032014-09-22 16:11:34 -07002042 mplsLabel = sw.getStringAttribute("nodeSid");
2043 break;
Sangho Shin1aa93542014-09-22 09:49:44 -07002044 }
2045 }
2046
Sangho Shineb083032014-09-22 16:11:34 -07002047 return mplsLabel;
Sangho Shin1aa93542014-09-22 09:49:44 -07002048 }
2049
Sangho Shineb083032014-09-22 16:11:34 -07002050 /**
Sangho Shin1aa93542014-09-22 09:49:44 -07002051 * The function checks if given IP matches to the given subnet mask
Sangho Shinfbc572c2014-10-02 16:37:05 -07002052 *
Sangho Shin1aa93542014-09-22 09:49:44 -07002053 * @param addr - subnet address to match
2054 * @param addr1 - IP address to check
2055 * @return true if the IP address matches to the subnet, otherwise false
2056 */
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002057 public boolean netMatch(String addr, String addr1) { // addr is subnet
2058 // address and addr1 is
2059 // ip address. Function
2060 // will return true, if
2061 // addr1 is within
2062 // addr(subnet)
Sangho Shin1aa93542014-09-22 09:49:44 -07002063
2064 String[] parts = addr.split("/");
2065 String ip = parts[0];
2066 int prefix;
2067
2068 if (parts.length < 2) {
2069 prefix = 0;
2070 } else {
2071 prefix = Integer.parseInt(parts[1]);
2072 }
2073
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002074 Inet4Address a = null;
2075 Inet4Address a1 = null;
Sangho Shin1aa93542014-09-22 09:49:44 -07002076 try {
2077 a = (Inet4Address) InetAddress.getByName(ip);
2078 a1 = (Inet4Address) InetAddress.getByName(addr1);
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002079 } catch (UnknownHostException e) {
2080 }
Sangho Shin1aa93542014-09-22 09:49:44 -07002081
2082 byte[] b = a.getAddress();
2083 int ipInt = ((b[0] & 0xFF) << 24) |
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002084 ((b[1] & 0xFF) << 16) |
2085 ((b[2] & 0xFF) << 8) |
2086 ((b[3] & 0xFF) << 0);
Sangho Shin1aa93542014-09-22 09:49:44 -07002087
2088 byte[] b1 = a1.getAddress();
2089 int ipInt1 = ((b1[0] & 0xFF) << 24) |
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002090 ((b1[1] & 0xFF) << 16) |
2091 ((b1[2] & 0xFF) << 8) |
2092 ((b1[3] & 0xFF) << 0);
Sangho Shin1aa93542014-09-22 09:49:44 -07002093
2094 int mask = ~((1 << (32 - prefix)) - 1);
2095
2096 if ((ipInt & mask) == (ipInt1 & mask)) {
2097 return true;
2098 }
2099 else {
2100 return false;
2101 }
2102 }
Sangho Shineb083032014-09-22 16:11:34 -07002103
Sangho Shinac5ee2b2014-09-28 21:27:20 -07002104 /**
2105 * Add a routing rule for the host
Sangho Shinfbc572c2014-10-02 16:37:05 -07002106 *
Sangho Shinac5ee2b2014-09-28 21:27:20 -07002107 * @param sw - Switch to add the rule
2108 * @param hostIpAddress Destination host IP address
2109 * @param hostMacAddress Destination host MAC address
2110 */
Sangho Shineb083032014-09-22 16:11:34 -07002111 public void addRouteToHost(Switch sw, int hostIpAddress, byte[] hostMacAddress) {
2112 ipHandler.addRouteToHost(sw, hostIpAddress, hostMacAddress);
Sangho Shineb083032014-09-22 16:11:34 -07002113 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -07002114
Sangho Shin463bee52014-09-29 15:14:43 -07002115 /**
2116 * Add IP packet to a buffer queue
Sangho Shinfbc572c2014-10-02 16:37:05 -07002117 *
Sangho Shin463bee52014-09-29 15:14:43 -07002118 * @param ipv4
2119 */
Sangho Shin7330c032014-10-20 10:34:51 -07002120 public void addPacketToPacketBuffer(IPv4 ipv4) {
Sangho Shin61535402014-10-01 11:37:14 -07002121 ipPacketQueue.add(ipv4);
Sangho Shin463bee52014-09-29 15:14:43 -07002122 }
2123
2124 /**
2125 * Retrieve all packets whose destination is the given address.
Sangho Shinfbc572c2014-10-02 16:37:05 -07002126 *
Sangho Shin463bee52014-09-29 15:14:43 -07002127 * @param destIp Destination address of packets to retrieve
2128 */
2129 public List<IPv4> getIpPacketFromQueue(byte[] destIp) {
2130
2131 List<IPv4> bufferedPackets = new ArrayList<IPv4>();
2132
Sangho Shin61535402014-10-01 11:37:14 -07002133 if (!ipPacketQueue.isEmpty()) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002134 for (IPv4 ip : ipPacketQueue) {
Sangho Shin61535402014-10-01 11:37:14 -07002135 int dest = ip.getDestinationAddress();
2136 IPv4Address ip1 = IPv4Address.of(dest);
2137 IPv4Address ip2 = IPv4Address.of(destIp);
2138 if (ip1.equals(ip2)) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002139 bufferedPackets.add((IPv4) (ipPacketQueue.poll()).clone());
Sangho Shin463bee52014-09-29 15:14:43 -07002140 }
2141 }
2142 }
2143
2144 return bufferedPackets;
2145 }
2146
Sangho Shin7330c032014-10-20 10:34:51 -07002147 /**
2148 * Get MAC address to known hosts
2149 *
2150 * @param destinationAddress IP address to get MAC address
2151 * @return MAC Address to given IP address
2152 */
2153 public byte[] getMacAddressFromIpAddress(int destinationAddress) {
2154
2155 // Can't we get the host IP address from the TopologyService ??
2156
2157 Iterator<ArpEntry> iterator = arpEntries.iterator();
2158
2159 IPv4Address ipAddress = IPv4Address.of(destinationAddress);
2160 byte[] ipAddressInByte = ipAddress.getBytes();
2161
2162 while (iterator.hasNext()) {
2163 ArpEntry arpEntry = iterator.next();
2164 byte[] address = arpEntry.targetIpAddress;
2165
2166 IPv4Address a = IPv4Address.of(address);
2167 IPv4Address b = IPv4Address.of(ipAddressInByte);
2168
2169 if (a.equals(b)) {
2170 log.debug("Found an arp entry");
2171 return arpEntry.targetMacAddress;
2172 }
2173 }
2174
2175 return null;
2176 }
2177
2178 /**
2179 * Send an ARP request via ArpHandler
2180 *
2181 * @param destinationAddress
2182 * @param sw
2183 * @param inPort
2184 *
2185 */
2186 public void sendArpRequest(Switch sw, int destinationAddress, Port inPort) {
2187 arpHandler.sendArpRequest(sw, destinationAddress, inPort);
2188 }
2189
Sangho Shin7330c032014-10-20 10:34:51 -07002190 // ************************************
2191 // Test functions
2192 // ************************************
2193
Sangho Shin55d00e12014-10-20 12:13:07 -07002194 private void runTest() {
2195
2196 if (testMode == POLICY_ADD1) {
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07002197 Integer[] routeArray = {101, 105, 110};
2198 /*List<Dpid> routeList = new ArrayList<Dpid>();
Sangho Shin55d00e12014-10-20 12:13:07 -07002199 for (int i = 0; i < routeArray.length; i++) {
2200 Dpid dpid = getSwitchFromNodeId(routeArray[i]).getDpid();
2201 routeList.add(dpid);
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07002202 }*/
Sangho Shin55d00e12014-10-20 12:13:07 -07002203
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07002204 if (createTunnel("1", Arrays.asList(routeArray))) {
Sangho Shin55d00e12014-10-20 12:13:07 -07002205 IPv4Net srcIp = new IPv4Net("10.0.1.1/24");
2206 IPv4Net dstIp = new IPv4Net("10.1.2.1/24");
2207
2208 log.debug("Set the policy 1");
Sangho Shine020cc32014-10-20 13:28:02 -07002209 this.createPolicy("1", null, null, Ethernet.TYPE_IPV4, srcIp,
Sangho Shin55d00e12014-10-20 12:13:07 -07002210 dstIp, IPv4.PROTOCOL_ICMP, (short)-1, (short)-1, 10000,
Sangho Shine020cc32014-10-20 13:28:02 -07002211 "1");
Sangho Shin55d00e12014-10-20 12:13:07 -07002212 testMode = POLICY_ADD2;
Sangho Shin4b46bcd2014-10-20 15:48:47 -07002213 testTask.reschedule(5, TimeUnit.SECONDS);
Sangho Shin55d00e12014-10-20 12:13:07 -07002214 }
2215 else {
2216 // retry it
2217 testTask.reschedule(5, TimeUnit.SECONDS);
2218 }
2219 }
2220 else if (testMode == POLICY_ADD2) {
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07002221 Integer[] routeArray = {101, 102, 103, 104, 105, 108, 110};
Sangho Shin55d00e12014-10-20 12:13:07 -07002222
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07002223 if (createTunnel("2", Arrays.asList(routeArray))) {
Sangho Shin55d00e12014-10-20 12:13:07 -07002224 IPv4Net srcIp = new IPv4Net("10.0.1.1/24");
2225 IPv4Net dstIp = new IPv4Net("10.1.2.1/24");
2226
2227 log.debug("Set the policy 2");
Sangho Shine020cc32014-10-20 13:28:02 -07002228 this.createPolicy("2", null, null, Ethernet.TYPE_IPV4, srcIp,
Sangho Shin55d00e12014-10-20 12:13:07 -07002229 dstIp, IPv4.PROTOCOL_ICMP, (short)-1, (short)-1, 20000,
Sangho Shine020cc32014-10-20 13:28:02 -07002230 "2");
Fahad Naeem Khan95aa4012014-10-21 14:07:00 -07002231 //testMode = POLICY_REMOVE2;
2232 //testTask.reschedule(5, TimeUnit.SECONDS);
Sangho Shin55d00e12014-10-20 12:13:07 -07002233 }
2234 else {
2235 log.debug("Retry it");
2236 testTask.reschedule(5, TimeUnit.SECONDS);
2237 }
2238 }
2239 else if (testMode == POLICY_REMOVE2){
2240 log.debug("Remove the policy 2");
Sangho Shine020cc32014-10-20 13:28:02 -07002241 this.removePolicy("2");
Sangho Shin55d00e12014-10-20 12:13:07 -07002242 testMode = POLICY_REMOVE1;
Sangho Shin4b46bcd2014-10-20 15:48:47 -07002243 testTask.reschedule(5, TimeUnit.SECONDS);
Sangho Shin55d00e12014-10-20 12:13:07 -07002244 }
2245 else if (testMode == POLICY_REMOVE1){
2246 log.debug("Remove the policy 1");
Sangho Shine020cc32014-10-20 13:28:02 -07002247 this.removePolicy("1");
Sangho Shin55d00e12014-10-20 12:13:07 -07002248
Sangho Shin4b46bcd2014-10-20 15:48:47 -07002249 testMode = TUNNEL_REMOVE1;
2250 testTask.reschedule(5, TimeUnit.SECONDS);
2251 }
2252 else if (testMode == TUNNEL_REMOVE1) {
2253 log.debug("Remove the tunnel 1");
2254 this.removeTunnel("1");
2255
2256 testMode = TUNNEL_REMOVE2;
2257 testTask.reschedule(5, TimeUnit.SECONDS);
2258 }
2259 else if (testMode == TUNNEL_REMOVE2) {
2260 log.debug("Remove the tunnel 2");
2261 this.removeTunnel("2");
2262 log.debug("The end of test");
2263 }
Sangho Shin55d00e12014-10-20 12:13:07 -07002264 }
Sangho Shin7330c032014-10-20 10:34:51 -07002265
2266 private void runTest1() {
2267
2268 String dpid1 = "00:00:00:00:00:00:00:01";
2269 String dpid2 = "00:00:00:00:00:00:00:0a";
2270 Switch srcSw = mutableTopology.getSwitch(new Dpid(dpid1));
2271 Switch dstSw = mutableTopology.getSwitch(new Dpid(dpid2));
2272
2273 if (srcSw == null || dstSw == null) {
2274 testTask.reschedule(1, TimeUnit.SECONDS);
2275 log.debug("Switch is gone. Reschedule the test");
2276 return;
2277 }
2278
2279 String[] routeArray = {"101", "102", "105", "108", "110"};
2280 List<String> routeList = new ArrayList<String>();
2281 for (int i = 0; i < routeArray.length; i++)
2282 routeList.add(routeArray[i]);
2283
2284 List<String> optimizedRoute = this.getOptimizedPath(srcSw, dstSw, routeList);
2285
2286 log.debug("Test set is {}", routeList.toString());
2287 log.debug("Result set is {}", optimizedRoute.toString());
2288
2289
2290 }
2291
2292 /**
2293 * print tunnel info - used only for debugging.
2294 * @param targetSw
2295 *
2296 * @param fwdSwDpids
2297 * @param ids
2298 * @param tunnelId
2299 */
Sangho Shin6471d202014-10-23 10:59:36 -07002300 private void printTunnelInfo(String targetSw, String tunnelId,
Sangho Shin7330c032014-10-20 10:34:51 -07002301 List<String> ids, NeighborSet ns) {
2302 StringBuilder logStr = new StringBuilder("In switch " +
Sangho Shin6471d202014-10-23 10:59:36 -07002303 targetSw + ", create a tunnel " + tunnelId + " " + " of push ");
Sangho Shin7330c032014-10-20 10:34:51 -07002304 for (String id: ids)
2305 logStr.append(id + "-");
2306 logStr.append(" output to ");
2307 for (Dpid dpid: ns.getDpids())
2308 logStr.append(dpid + " - ");
2309
2310 log.debug(logStr.toString());
2311
2312 }
2313
2314 /**
2315 * Debugging function to print out the Match Action Entry
2316 * @param sw13
2317 *
2318 * @param maEntry
2319 */
2320 private void printMatchActionOperationEntry(
2321 IOF13Switch sw13, MatchActionOperationEntry maEntry) {
2322
2323 StringBuilder logStr = new StringBuilder("In switch " + sw13.getId() + ", ");
2324
2325 MatchAction ma = maEntry.getTarget();
2326 Match m = ma.getMatch();
2327 List<Action> actions = ma.getActions();
2328
2329 if (m instanceof Ipv4Match) {
2330 logStr.append("If the IP matches with ");
2331 IPv4Net ip = ((Ipv4Match) m).getDestination();
2332 logStr.append(ip.toString());
2333 logStr.append(" then ");
2334 }
2335 else if (m instanceof MplsMatch) {
2336 logStr.append("If the MPLS label matches with ");
2337 int mplsLabel = ((MplsMatch) m).getMplsLabel();
2338 logStr.append(mplsLabel);
2339 logStr.append(" then ");
2340 }
2341 else if (m instanceof PacketMatch) {
2342 GroupAction ga = (GroupAction)actions.get(0);
2343 logStr.append("if the policy match is XXX then go to group " +
2344 ga.getGroupId());
2345 log.debug(logStr.toString());
2346 return;
2347 }
2348
2349 logStr.append(" do { ");
2350 for (Action action : actions) {
2351 if (action instanceof CopyTtlInAction) {
2352 logStr.append("copy ttl In, ");
2353 }
2354 else if (action instanceof CopyTtlOutAction) {
2355 logStr.append("copy ttl Out, ");
2356 }
2357 else if (action instanceof DecMplsTtlAction) {
2358 logStr.append("Dec MPLS TTL , ");
2359 }
2360 else if (action instanceof GroupAction) {
2361 logStr.append("Forward packet to < ");
2362 NeighborSet dpids = ((GroupAction) action).getDpids();
2363 logStr.append(dpids.toString() + ",");
2364
2365 }
2366 else if (action instanceof PopMplsAction) {
2367 logStr.append("Pop MPLS label, ");
2368 }
2369 else if (action instanceof PushMplsAction) {
2370 logStr.append("Push MPLS label, ");
2371 }
2372 else if (action instanceof SetMplsIdAction) {
2373 int id = ((SetMplsIdAction) action).getMplsId();
2374 logStr.append("Set MPLS ID as " + id + ", ");
2375 }
2376 }
2377
2378 log.debug(logStr.toString());
2379
2380 }
2381
Sangho Shin7330c032014-10-20 10:34:51 -07002382 // ************************************
2383 // Unused classes and functions
2384 // ************************************
2385
2386 /**
2387 * Temporary class to to keep ARP entry
2388 *
2389 */
2390 private class ArpEntry {
2391
2392 byte[] targetMacAddress;
2393 byte[] targetIpAddress;
2394
2395 private ArpEntry(byte[] macAddress, byte[] ipAddress) {
2396 this.targetMacAddress = macAddress;
2397 this.targetIpAddress = ipAddress;
2398 }
2399 }
2400
2401 /**
2402 * This class is used only for link recovery optimization in
2403 * modifyEcmpRoutingRules() function.
2404 * TODO: please remove if the optimization is not used at all
2405 */
2406 private class SwitchPair {
2407 private Switch src;
2408 private Switch dst;
2409
2410 public SwitchPair(Switch src, Switch dst) {
2411 this.src = src;
2412 this.dst = dst;
2413 }
2414
2415 public Switch getSource() {
2416 return src;
2417 }
2418
2419 public Switch getDestination() {
2420 return dst;
2421 }
2422 }
2423
2424 /**
2425 * Update ARP Cache using ARP packets It is used to set destination MAC
2426 * address to forward packets to known hosts. But, it will be replace with
2427 * Host information of Topology service later.
2428 *
2429 * @param arp APR packets to use for updating ARP entries
2430 */
2431 public void updateArpCache(ARP arp) {
2432
2433 ArpEntry arpEntry = new ArpEntry(arp.getSenderHardwareAddress(),
2434 arp.getSenderProtocolAddress());
2435 // TODO: Need to check the duplication
2436 arpEntries.add(arpEntry);
2437 }
2438
2439 /**
2440 * Modify the routing rules for the lost links
2441 * - Recompute the path if the link failed is included in the path
2442 * (including src and dest).
2443 *
2444 * @param newLink
2445 */
2446 private void modifyEcmpRoutingRules(LinkData linkRemoved) {
2447
2448 //HashMap<Switch, SwitchPair> linksToRecompute = new HashMap<Switch, SwitchPair>();
2449 Set<SwitchPair> linksToRecompute = new HashSet<SwitchPair>();
2450
2451 for (ECMPShortestPathGraph ecmpSPG : graphs.values()) {
2452 Switch rootSw = ecmpSPG.getRootSwitch();
2453 HashMap<Integer, HashMap<Switch, ArrayList<Path>>> paths =
2454 ecmpSPG.getCompleteLearnedSwitchesAndPaths();
2455 for (HashMap<Switch, ArrayList<Path>> p: paths.values()) {
2456 for (Switch destSw: p.keySet()) {
2457 ArrayList<Path> path = p.get(destSw);
2458 if (checkPath(path, linkRemoved)) {
2459 boolean found = false;
2460 for (SwitchPair pair: linksToRecompute) {
2461 if (pair.getSource().getDpid() == rootSw.getDpid() &&
2462 pair.getSource().getDpid() == destSw.getDpid()) {
2463 found = true;
2464 }
2465 }
2466 if (!found) {
2467 linksToRecompute.add(new SwitchPair(rootSw, destSw));
2468 }
2469 }
2470 }
2471 }
2472 }
2473
2474 // Recompute the path for the specific route
2475 for (SwitchPair pair: linksToRecompute) {
2476
2477 log.debug("Recompute path from {} to {}", pair.getSource(), pair.getDestination());
2478 // We need the following function for optimization
2479 //ECMPShortestPathGraph ecmpSPG =
2480 // new ECMPShortestPathGraph(pair.getSource(), pair.getDestination());
2481 ECMPShortestPathGraph ecmpSPG =
2482 new ECMPShortestPathGraph(pair.getSource());
2483 populateEcmpRoutingRulesForPath(pair.getSource(), ecmpSPG, true);
2484 }
2485 }
2486
2487 /**
2488 * Optimize the mpls label
2489 * The feature will be used only for policy of "avoid a specific switch".
2490 * Check route to each router in route backward.
2491 * If there is only one route to the router and the routers are included in
2492 * the route, remove the id from the path.
2493 * A-B-C-D-E => A-B-C-D-E -> A-E
2494 * | | => A-B-H-I -> A-I
Sangho Shin5b8f5452014-10-20 11:46:01 -07002495 * F-G-H-I => A-D-I > A-D-I
Sangho Shin7330c032014-10-20 10:34:51 -07002496 */
2497 private List<String> getOptimizedPath(Switch srcSw, Switch dstSw, List<String> route) {
2498
2499 List<String> optimizedPath = new ArrayList<String>();
2500 optimizedPath.addAll(route);
2501 ECMPShortestPathGraph ecmpSPG = new ECMPShortestPathGraph(srcSw);
2502
2503 HashMap<Integer, HashMap<Switch, ArrayList<Path>>> paths =
2504 ecmpSPG.getCompleteLearnedSwitchesAndPaths();
2505 for (HashMap<Switch, ArrayList<Path>> p: paths.values()) {
2506 for (Switch s: p.keySet()) {
2507 if (s.getDpid().toString().equals(dstSw.getDpid().toString())) {
2508 ArrayList<Path> ecmpPaths = p.get(s);
2509 if (ecmpPaths!= null && ecmpPaths.size() == 1) {
2510 for (Path path: ecmpPaths) {
2511 for (LinkData link: path) {
2512 String srcId = getMplsLabel(link.getSrc().getDpid().toString());
2513 String dstId = getMplsLabel(link.getSrc().getDpid().toString());
2514 if (optimizedPath.contains(srcId)) {
2515 optimizedPath.remove(srcId);
2516 }
2517 if (optimizedPath.contains(dstId)) {
2518 optimizedPath.remove(dstId);
2519 }
2520 }
2521 }
2522 }
2523 }
2524 }
2525 }
2526
2527 return optimizedPath;
2528
2529 }
2530
2531 /**
2532 * Check if the path is affected from the link removed
2533 *
2534 * @param path Path to check
2535 * @param linkRemoved link removed
2536 * @return true if the path contains the link removed
2537 */
2538 private boolean checkPath(ArrayList<Path> path, LinkData linkRemoved) {
2539
2540 for (Path ppp: path) {
2541 // TODO: need to check if this is a bidirectional or
2542 // unidirectional
2543 for (LinkData link: ppp) {
2544 if (link.getDst().getDpid().equals(linkRemoved.getDst().getDpid()) &&
2545 link.getSrc().getDpid().equals(linkRemoved.getSrc().getDpid()))
2546 return true;
2547 }
2548 }
2549
2550 return false;
2551 }
Sangho Shin15273b62014-10-16 22:22:05 -07002552
2553
Sangho Shin2f263692014-09-15 14:09:41 -07002554}