blob: 4d95d244fc2d2591aed11b57772fd88bdcbdf13d [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
Sangho Shin20b5acb2014-10-27 11:42:19 -0700121 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
Sangho Shin370e17b2014-10-27 11:39:08 -0700485 * to the driver. IF the switches do not support ECMP in transit routers and
486 * the link removed is between transit routers, then just recompute the path
487 * regardless of ECMP.
Sangho Shinfbc572c2014-10-02 16:37:05 -0700488 *
Sangho Shin61535402014-10-01 11:37:14 -0700489 * @param linkEntries
490 */
491 private void processLinkRemoval(Collection<LinkData> linkEntries) {
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 Shin370e17b2014-10-27 11:39:08 -0700509 if (!supportTransitECMP &&
510 isTransitRouter(mutableTopology.getSwitch(srcPort.getDpid())) &&
511 isTransitRouter(mutableTopology.getSwitch(dstPort.getDpid()))) {
512 populateEcmpRoutingRules(false);
513 }
514 else {
515 Switch srcSwitch = mutableTopology.getSwitch(srcPort.getDpid());
516 if (srcSwitch.getLinkToNeighbor(dstPort.getDpid()) == null) {
517 log.debug("All links are gone b/w {} and {}", srcPort.getDpid(),
518 dstPort.getDpid());
519 log.debug("All paths will recomputed regardless of the rest "
520 + "of the event");
521 populateEcmpRoutingRules(false);
522 }
Sangho Shinc8d2f592014-09-30 16:53:57 -0700523 }
Sangho Shin23f898d2014-10-13 16:54:00 -0700524
525 String key = link.getSrc().getDpid().toString()+
526 link.getDst().getDpid().toString();
527 if (!linksDown.containsKey(key)) {
528 linksDown.put(key, link);
529 }
Sangho Shinc8d2f592014-09-30 16:53:57 -0700530 }
Sangho Shinbce900e2014-10-07 17:13:23 -0700531
Sangho Shin61535402014-10-01 11:37:14 -0700532 }
Sangho Shinc8d2f592014-09-30 16:53:57 -0700533
Sangho Shin61535402014-10-01 11:37:14 -0700534 /**
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700535 * report ports removed to the driver immediately
Sangho Shinfbc572c2014-10-02 16:37:05 -0700536 *
Sangho Shin61535402014-10-01 11:37:14 -0700537 * @param portEntries
538 */
539 private void processPortRemoval(Collection<PortData> portEntries) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700540 for (PortData port : portEntries) {
Sangho Shin61535402014-10-01 11:37:14 -0700541 Dpid dpid = port.getDpid();
Sangho Shin61535402014-10-01 11:37:14 -0700542
Sangho Shinfbc572c2014-10-02 16:37:05 -0700543 IOF13Switch sw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin61535402014-10-01 11:37:14 -0700544 getSwId(port.getDpid().toString()));
Sangho Shin815af0c2014-10-10 13:05:45 -0700545 if (sw != null) {
Sangho Shinfbc572c2014-10-02 16:37:05 -0700546 sw.removePortFromGroups(port.getPortNumber());
Sangho Shin815af0c2014-10-10 13:05:45 -0700547 log.debug("Remove port {} from switch {}", port, dpid);
548 }
Sangho Shin61535402014-10-01 11:37:14 -0700549 }
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700550 }
Sangho Shin1aa93542014-09-22 09:49:44 -0700551
552 /**
Sangho Shin7330c032014-10-20 10:34:51 -0700553 * Add the link immediately
554 * The function is scheduled when link add event happens and called
555 * DELAY_TO_ADD_LINK seconds after the event to avoid link flip-flop.
556 */
557 private void delayedAddLink() {
558
559 processLinkAdd(linksToAdd.values(), true);
560
561 }
562
563
564 // ************************************
565 // ECMP shorted path routing functions
566 // ************************************
567
568 /**
Sangho Shin43cee112014-09-25 16:43:34 -0700569 * Populate routing rules walking through the ECMP shortest paths
Sangho Shinfbc572c2014-10-02 16:37:05 -0700570 *
Sangho Shin99918bd2014-10-08 15:52:35 -0700571 * @param modified if true, it "modifies" the rules
Sangho Shin1aa93542014-09-22 09:49:44 -0700572 */
Sangho Shin5be3e532014-10-03 17:20:58 -0700573 private void populateEcmpRoutingRules(boolean modified) {
574 graphs.clear();
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700575 Iterable<Switch> switches = mutableTopology.getSwitches();
Sangho Shin43cee112014-09-25 16:43:34 -0700576 for (Switch sw : switches) {
577 ECMPShortestPathGraph ecmpSPG = new ECMPShortestPathGraph(sw);
Sangho Shinfbc572c2014-10-02 16:37:05 -0700578 graphs.put(sw, ecmpSPG);
579 //log.debug("ECMPShortestPathGraph is computed for switch {}",
580 // HexString.toHexString(sw.getDpid().value()));
Sangho Shin5be3e532014-10-03 17:20:58 -0700581 populateEcmpRoutingRulesForPath(sw, ecmpSPG, modified);
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700582
583 // Set adjacency routing rule for all switches
584 try {
585 populateAdjacencyncyRule(sw);
586 } catch (JSONException e) {
587 // TODO Auto-generated catch block
588 e.printStackTrace();
589 }
Sangho Shinfbc572c2014-10-02 16:37:05 -0700590 }
Sangho Shinbce900e2014-10-07 17:13:23 -0700591 numOfPopulation++;
Sangho Shinfbc572c2014-10-02 16:37:05 -0700592 }
Sangho Shin1aa93542014-09-22 09:49:44 -0700593
Sangho Shin204b9972014-10-22 11:08:10 -0700594 /**
595 * populate the MPLS rules to handle Adjacency IDs
596 *
597 * @param sw Switch
598 * @throws JSONException
599 */
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700600 private void populateAdjacencyncyRule(Switch sw) throws JSONException {
601 String adjInfo = sw.getStringAttribute("adjacencySids");
Sangho Shin204b9972014-10-22 11:08:10 -0700602 String nodeSidStr = sw.getStringAttribute("nodeSid");
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700603 String srcMac = sw.getStringAttribute("routerMac");
Sangho Shin204b9972014-10-22 11:08:10 -0700604 String autoAdjInfo = sw.getStringAttribute("autogenAdjSids");
605
Sangho Shinced05b62014-10-22 11:23:14 -0700606 if (autoAdjInfo == null || srcMac == null || nodeSidStr == null)
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700607 return;
608
Sangho Shinced05b62014-10-22 11:23:14 -0700609 // parse adjacency Id
Sangho Shincfef3922014-10-22 12:04:16 -0700610 HashMap<Integer, List<Integer>> adjacencyInfo = null;
Sangho Shinced05b62014-10-22 11:23:14 -0700611 if (adjInfo != null) {
Sangho Shincfef3922014-10-22 12:04:16 -0700612 adjacencyInfo = parseAdjacencySidInfo(adjInfo);
Sangho Shinced05b62014-10-22 11:23:14 -0700613 }
Sangho Shincfef3922014-10-22 12:04:16 -0700614 // parse auto generated adjacency Id
615 adjacencyInfo.putAll(parseAdjacencySidInfo(autoAdjInfo));
Sangho Shinced05b62014-10-22 11:23:14 -0700616
Sangho Shin6471d202014-10-23 10:59:36 -0700617 adjacencySidTable.put(Integer.parseInt(nodeSidStr), adjacencyInfo);
Sangho Shin204b9972014-10-22 11:08:10 -0700618
Sangho Shin6471d202014-10-23 10:59:36 -0700619 for (Integer adjId: adjacencyInfo.keySet()) {
620 List<Integer> ports = adjacencyInfo.get(adjId);
621 if (ports.size() == 1) {
622 setAdjacencyRuleOfOutput(sw, adjId, srcMac, ports.get(0));
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700623 }
624 else {
Sangho Shin6471d202014-10-23 10:59:36 -0700625 setAdjacencyRuleOfGroup(sw, adjId, ports);
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700626 }
Sangho Shin6471d202014-10-23 10:59:36 -0700627 }
628 }
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700629
Sangho Shin6471d202014-10-23 10:59:36 -0700630 /**
631 * Set Adjacency Rule to MPLS table for adjacency Ids attached to multiple
632 * ports
633 *
634 * @param sw Switch
635 * @param adjId Adjacency ID
636 * @param ports List of ports assigned to the Adjacency ID
637 */
638 private void setAdjacencyRuleOfGroup(Switch sw, Integer adjId, List<Integer> ports) {
639
640 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
641 getSwId(sw.getDpid().toString()));
642
643 int groupId = -1;
644 if (sw13 != null) {
645 List<PortNumber> portList = new ArrayList<PortNumber>();
646 for (Integer port: ports)
647 portList.add(PortNumber.uint32(port));
648 groupId = sw13.createGroup(new ArrayList<Integer>(), portList);
649 }
650
651 if (groupId < 0) {
652 log.debug("Failed to create a group at driver for adj ID {}", adjId);
653 }
654
655 pushAdjRule(sw, adjId, null, null, groupId, true);
656 pushAdjRule(sw, adjId, null, null, groupId, false);
657 }
658
659 /**
660 * Set Adjacency Rule to MPLS table for adjacency Ids attached to single port
661 *
662 * @param sw Switch
663 * @param adjId Adjacency ID
664 * @param ports List of ports assigned to the Adjacency ID
665 */
666 private void setAdjacencyRuleOfOutput(Switch sw, Integer adjId, String srcMac, Integer portNo) {
667
668 Dpid dstDpid = null;
669 for (Link link: sw.getOutgoingLinks()) {
670 if (link.getSrcPort().getPortNumber().value() == portNo) {
671 dstDpid = link.getDstPort().getDpid();
672 break;
673 }
674 }
675 if (dstDpid == null) {
676 log.debug("Cannot find the destination switch for the adjacency ID {}", adjId);
677 return;
678 }
679 Switch dstSw = mutableTopology.getSwitch(dstDpid);
680 String dstMac = null;
681 if (dstSw == null) {
682 log.debug("Cannot find SW {}", dstDpid.toString());
683 return;
684 }
685 else {
686 dstMac = dstSw.getStringAttribute("routerMac");
687 }
688
689 pushAdjRule(sw, adjId, srcMac, dstMac, portNo, true); // BoS = 1
690 pushAdjRule(sw, adjId, srcMac, dstMac, portNo, false); // BoS = 0
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700691
692 }
693
Sangho Shin204b9972014-10-22 11:08:10 -0700694 /**
695 * Push the MPLS rule for Adjacency ID
696 *
697 * @param sw Switch to push the rule
698 * @param id Adjacency ID
699 * @param srcMac source MAC address
700 * @param dstMac destination MAC address
701 * @param portNo port number assigned to the ID
702 * @param bos BoS option
703 */
Sangho Shin6471d202014-10-23 10:59:36 -0700704 private void pushAdjRule(Switch sw, int id, String srcMac, String dstMac,
705 int num, boolean bos) {
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700706
707 MplsMatch mplsMatch = new MplsMatch(id, bos);
708 List<Action> actions = new ArrayList<Action>();
709
710 if (bos) {
711 PopMplsAction popAction = new PopMplsAction(EthType.IPv4);
712 CopyTtlInAction copyTtlInAction = new CopyTtlInAction();
713 DecNwTtlAction decNwTtlAction = new DecNwTtlAction(1);
714 actions.add(copyTtlInAction);
715 actions.add(popAction);
716 actions.add(decNwTtlAction);
717 }
718 else {
719 PopMplsAction popAction = new PopMplsAction(EthType.MPLS_UNICAST);
720 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
721 actions.add(popAction);
722 actions.add(decMplsTtlAction);
723 }
724
Sangho Shin6471d202014-10-23 10:59:36 -0700725 // Output action
726 if (srcMac != null && dstMac != null) {
727 ModifyDstMacAction setDstAction = new ModifyDstMacAction(MACAddress.valueOf(srcMac));
728 ModifySrcMacAction setSrcAction = new ModifySrcMacAction(MACAddress.valueOf(dstMac));
729 OutputAction outportAction = new OutputAction(PortNumber.uint32(num));
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700730
Sangho Shin6471d202014-10-23 10:59:36 -0700731 actions.add(setDstAction);
732 actions.add(setSrcAction);
733 actions.add(outportAction);
734 }
735 // Group Action
736 else {
737 GroupAction groupAction = new GroupAction();
738 groupAction.setGroupId(num);
739 actions.add(groupAction);
740 }
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700741
742 MatchAction matchAction = new MatchAction(new MatchActionId(matchActionId++),
743 new SwitchPort((long) 0, (short) 0), mplsMatch, actions);
744 Operator operator = Operator.ADD;
745 MatchActionOperationEntry maEntry =
746 new MatchActionOperationEntry(operator, matchAction);
747
748 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
749 getSwId(sw.getDpid().toString()));
750
751 if (sw13 != null) {
752 try {
753 //printMatchActionOperationEntry(sw, maEntry);
754 sw13.pushFlow(maEntry);
755 } catch (IOException e) {
756 e.printStackTrace();
757 }
758 }
759 }
760
Sangho Shin99918bd2014-10-08 15:52:35 -0700761 /**
762 * populate routing rules to forward packets from the switch given to
763 * all other switches.
764 *
765 * @param sw source switch
766 * @param ecmpSPG shortest path from the the source switch to all others
767 * @param modified modification flag
768 */
Sangho Shinfbc572c2014-10-02 16:37:05 -0700769 private void populateEcmpRoutingRulesForPath(Switch sw,
Sangho Shin5be3e532014-10-03 17:20:58 -0700770 ECMPShortestPathGraph ecmpSPG, boolean modified) {
Sangho Shin43cee112014-09-25 16:43:34 -0700771
Sangho Shinfbc572c2014-10-02 16:37:05 -0700772 HashMap<Integer, HashMap<Switch, ArrayList<ArrayList<Dpid>>>> switchVia =
773 ecmpSPG.getAllLearnedSwitchesAndVia();
774 for (Integer itrIdx : switchVia.keySet()) {
775 //log.debug("ECMPShortestPathGraph:Switches learned in "
776 // + "Iteration{} from switch {}:",
777 // itrIdx,
778 // HexString.toHexString(sw.getDpid().value()));
779 HashMap<Switch, ArrayList<ArrayList<Dpid>>> swViaMap =
780 switchVia.get(itrIdx);
781 for (Switch targetSw : swViaMap.keySet()) {
Sangho Shin5be3e532014-10-03 17:20:58 -0700782 //log.debug("ECMPShortestPathGraph:****switch {} via:",
783 // HexString.toHexString(targetSw.getDpid().value()));
Sangho Shinfbc572c2014-10-02 16:37:05 -0700784 String destSw = sw.getDpid().toString();
785 List<String> fwdToSw = new ArrayList<String>();
786
Sangho Shinfbc572c2014-10-02 16:37:05 -0700787 for (ArrayList<Dpid> via : swViaMap.get(targetSw)) {
Sangho Shin5be3e532014-10-03 17:20:58 -0700788 //log.debug("ECMPShortestPathGraph:******{}) {}", ++i, via);
Sangho Shinfbc572c2014-10-02 16:37:05 -0700789 if (via.isEmpty()) {
790 fwdToSw.add(destSw);
Sangho Shin43cee112014-09-25 16:43:34 -0700791 }
Sangho Shinfbc572c2014-10-02 16:37:05 -0700792 else {
793 fwdToSw.add(via.get(0).toString());
794 }
Sangho Shin43cee112014-09-25 16:43:34 -0700795 }
Sangho Shin5be3e532014-10-03 17:20:58 -0700796 setRoutingRule(targetSw, destSw, fwdToSw, modified);
Sangho Shineb083032014-09-22 16:11:34 -0700797 }
Sangho Shinfbc572c2014-10-02 16:37:05 -0700798
799 // Send Barrier Message and make sure all rules are set
800 // before we set the rules to next routers
Saurav Dasa962a692014-10-17 14:52:38 -0700801 // TODO: barriers to all switches in this update stage
Sangho Shinfbc572c2014-10-02 16:37:05 -0700802 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
803 getSwId(sw.getDpid().toString()));
Sangho Shin5be3e532014-10-03 17:20:58 -0700804 if (sw13 != null) {
Saurav Dasa962a692014-10-17 14:52:38 -0700805 OFBarrierReplyFuture replyFuture = null;
Sangho Shin5be3e532014-10-03 17:20:58 -0700806 try {
Saurav Dasa962a692014-10-17 14:52:38 -0700807 replyFuture = sw13.sendBarrier();
Sangho Shin5be3e532014-10-03 17:20:58 -0700808 } catch (IOException e) {
Saurav Dasa962a692014-10-17 14:52:38 -0700809 log.error("Error sending barrier request to switch {}",
810 sw13.getId(), e.getCause());
Sangho Shin5be3e532014-10-03 17:20:58 -0700811 }
Saurav Dasa962a692014-10-17 14:52:38 -0700812 OFBarrierReply br = null;
813 try {
814 br = replyFuture.get(2, TimeUnit.SECONDS);
815 } catch (TimeoutException | InterruptedException | ExecutionException e) {
816 // XXX for some reason these exceptions are not being thrown
817 }
818 if (br == null) {
819 log.warn("Did not receive barrier-reply from {}", sw13.getId());
820 // XXX take corrective action
821 }
822
Sangho Shinfbc572c2014-10-02 16:37:05 -0700823 }
824 }
825
826 }
827
Sangho Shinfbc572c2014-10-02 16:37:05 -0700828 /**
829 *
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700830 * Set routing rules in targetSw {forward packets to fwdToSw switches in
831 * order to send packets to destSw} - If the target switch is an edge router
832 * and final destnation switch is also an edge router, then set IP
833 * forwarding rules to subnets - If only the target switch is an edge
834 * router, then set IP forwarding rule to the transit router loopback IP
835 * address - If the target is a transit router, then just set the MPLS
836 * forwarding rule
Sangho Shinfbc572c2014-10-02 16:37:05 -0700837 *
Sangho Shin43cee112014-09-25 16:43:34 -0700838 * @param targetSw Switch to set the rules
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700839 * @param destSw Final destination switches
Sangho Shin43cee112014-09-25 16:43:34 -0700840 * @param fwdToSw next hop switches
841 */
Sangho Shin99918bd2014-10-08 15:52:35 -0700842 private void setRoutingRule(Switch targetSw, String destSw,
843 List<String> fwdToSw, boolean modified) {
Sangho Shin43cee112014-09-25 16:43:34 -0700844
Sangho Shin43cee112014-09-25 16:43:34 -0700845 if (fwdToSw.isEmpty()) {
846 fwdToSw.add(destSw);
847 }
848
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700849 // if both target SW and dest SW are an edge router, then set IP table
Sangho Shin43cee112014-09-25 16:43:34 -0700850 if (IsEdgeRouter(targetSw.getDpid().toString()) &&
851 IsEdgeRouter(destSw)) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700852 // We assume that there is at least one transit router b/w edge
853 // routers
Sangho Shin43cee112014-09-25 16:43:34 -0700854 Switch destSwitch = mutableTopology.getSwitch(new Dpid(destSw));
855 String subnets = destSwitch.getStringAttribute("subnets");
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700856 setIpTableRouterSubnet(targetSw, subnets, getMplsLabel(destSw)
Sangho Shin5be3e532014-10-03 17:20:58 -0700857 , fwdToSw, modified);
Sangho Shin43cee112014-09-25 16:43:34 -0700858
Sangho Shin43cee112014-09-25 16:43:34 -0700859 String routerIp = destSwitch.getStringAttribute("routerIp");
Sangho Shin5be3e532014-10-03 17:20:58 -0700860 setIpTableRouter(targetSw, routerIp, getMplsLabel(destSw), fwdToSw,
861 null, modified);
Sangho Shin721ca042014-10-09 13:03:40 -0700862 // Edge router can be a transit router
863 setMplsTable(targetSw, getMplsLabel(destSw), fwdToSw, modified);
Sangho Shin43cee112014-09-25 16:43:34 -0700864 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700865 // Only if the target switch is the edge router, then set the IP rules
Sangho Shin43cee112014-09-25 16:43:34 -0700866 else if (IsEdgeRouter(targetSw.getDpid().toString())) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700867 // We assume that there is at least one transit router b/w edge
868 // routers
Sangho Shin43cee112014-09-25 16:43:34 -0700869 Switch destSwitch = mutableTopology.getSwitch(new Dpid(destSw));
870 String routerIp = destSwitch.getStringAttribute("routerIp");
Sangho Shin5be3e532014-10-03 17:20:58 -0700871 setIpTableRouter(targetSw, routerIp, getMplsLabel(destSw), fwdToSw,
872 null, modified);
Sangho Shin721ca042014-10-09 13:03:40 -0700873 // Edge router can be a transit router
874 setMplsTable(targetSw, getMplsLabel(destSw), fwdToSw, modified);
Sangho Shin43cee112014-09-25 16:43:34 -0700875 }
876 // if it is a transit router, then set rules in the MPLS table
877 else {
Sangho Shin5be3e532014-10-03 17:20:58 -0700878 setMplsTable(targetSw, getMplsLabel(destSw), fwdToSw, modified);
Sangho Shin43cee112014-09-25 16:43:34 -0700879 }
880
881 }
882
Sangho Shinfbc572c2014-10-02 16:37:05 -0700883 /**
884 * Set IP forwarding rule to the gateway of each subnet of switches
885 *
886 * @param targetSw Switch to set rules
887 * @param subnets subnet information
888 * @param mplsLabel destination MPLS label
889 * @param fwdToSw router to forward packets to
890 */
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700891 private void setIpTableRouterSubnet(Switch targetSw, String subnets,
Sangho Shin5be3e532014-10-03 17:20:58 -0700892 String mplsLabel, List<String> fwdToSw, boolean modified) {
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700893
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700894 Collection<MatchActionOperationEntry> entries =
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700895 new ArrayList<MatchActionOperationEntry>();
896
897 try {
898 JSONArray arry = new JSONArray(subnets);
899 for (int i = 0; i < arry.length(); i++) {
900 String subnetIp = (String) arry.getJSONObject(i).get("subnetIp");
Sangho Shin5be3e532014-10-03 17:20:58 -0700901 setIpTableRouter(targetSw, subnetIp, mplsLabel, fwdToSw, entries,
902 modified);
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700903 }
904 } catch (JSONException e) {
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700905 e.printStackTrace();
906 }
907
908 if (!entries.isEmpty()) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700909 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700910 getSwId(targetSw.getDpid().toString()));
911
Sangho Shin721ca042014-10-09 13:03:40 -0700912 if (sw13 != null) {
913 try {
914 sw13.pushFlows(entries);
915 } catch (IOException e) {
916 e.printStackTrace();
917 }
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700918 }
919 }
920
921 }
922
Sangho Shin43cee112014-09-25 16:43:34 -0700923 /**
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700924 * Set IP forwarding rule - If the destination is the next hop, then do not
925 * push MPLS, just decrease the NW TTL - Otherwise, push MPLS label and set
926 * the MPLS ID
Sangho Shinfbc572c2014-10-02 16:37:05 -0700927 *
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700928 * @param sw target switch to set rules
Sangho Shin43cee112014-09-25 16:43:34 -0700929 * @param subnetIp Match IP address
930 * @param mplsLabel MPLS label of final destination router
931 * @param fwdToSws next hop routers
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700932 * @param entries
Sangho Shin43cee112014-09-25 16:43:34 -0700933 */
934 private void setIpTableRouter(Switch sw, String subnetIp, String mplsLabel,
Sangho Shin5be3e532014-10-03 17:20:58 -0700935 List<String> fwdToSws, Collection<MatchActionOperationEntry> entries,
936 boolean modified) {
Sangho Shin43cee112014-09-25 16:43:34 -0700937
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700938 Ipv4Match ipMatch = new Ipv4Match(subnetIp);
Sangho Shin43cee112014-09-25 16:43:34 -0700939 List<Action> actions = new ArrayList<>();
Sangho Shin721ca042014-10-09 13:03:40 -0700940 GroupAction groupAction = new GroupAction();
Sangho Shin43cee112014-09-25 16:43:34 -0700941
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700942 // If destination SW is the same as the fwd SW, then do not push MPLS
943 // label
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700944 if (fwdToSws.size() > 1) {
Sangho Shin43cee112014-09-25 16:43:34 -0700945 PushMplsAction pushMplsAction = new PushMplsAction();
946 SetMplsIdAction setIdAction = new SetMplsIdAction(Integer.parseInt(mplsLabel));
947 CopyTtlOutAction copyTtlOutAction = new CopyTtlOutAction();
Sangho Shin463bee52014-09-29 15:14:43 -0700948 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
Sangho Shin43cee112014-09-25 16:43:34 -0700949
Sangho Shin62ce5c12014-10-08 16:24:40 -0700950 //actions.add(pushMplsAction);
951 //actions.add(copyTtlOutAction);
952 //actions.add(decMplsTtlAction);
Saurav Das82e62972014-10-16 14:53:57 -0700953 // actions.add(setIdAction);
Sangho Shin721ca042014-10-09 13:03:40 -0700954 groupAction.setEdgeLabel(Integer.parseInt(mplsLabel));
Sangho Shin43cee112014-09-25 16:43:34 -0700955 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700956 else {
957 String fwdToSw = fwdToSws.get(0);
958 if (getMplsLabel(fwdToSw).equals(mplsLabel)) {
959 DecNwTtlAction decTtlAction = new DecNwTtlAction(1);
960 actions.add(decTtlAction);
961 }
962 else {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700963 SetMplsIdAction setIdAction = new SetMplsIdAction(
964 Integer.parseInt(mplsLabel));
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700965 CopyTtlOutAction copyTtlOutAction = new CopyTtlOutAction();
Sangho Shin463bee52014-09-29 15:14:43 -0700966 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700967
Sangho Shin62ce5c12014-10-08 16:24:40 -0700968 //actions.add(pushMplsAction);
969 //actions.add(copyTtlOutAction);
970 //actions.add(decMplsTtlAction);
Saurav Das82e62972014-10-16 14:53:57 -0700971 // actions.add(setIdAction);
Sangho Shin721ca042014-10-09 13:03:40 -0700972 groupAction.setEdgeLabel(Integer.parseInt(mplsLabel));
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700973 }
974 }
Sangho Shin43cee112014-09-25 16:43:34 -0700975
Sangho Shin43cee112014-09-25 16:43:34 -0700976 for (String fwdSw : fwdToSws) {
977 groupAction.addSwitch(new Dpid(fwdSw));
978 }
979 actions.add(groupAction);
980
Sangho Shin99918bd2014-10-08 15:52:35 -0700981 MatchAction matchAction = new MatchAction(new MatchActionId(matchActionId++),
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700982 new SwitchPort((long) 0, (short) 0), ipMatch, actions);
Sangho Shin43cee112014-09-25 16:43:34 -0700983
Sangho Shin5be3e532014-10-03 17:20:58 -0700984 Operator operator = null;
985 if (modified)
986 operator = Operator.MODIFY;
987 else
988 operator = Operator.ADD;
989
Sangho Shin43cee112014-09-25 16:43:34 -0700990 MatchActionOperationEntry maEntry =
Sangho Shin5be3e532014-10-03 17:20:58 -0700991 new MatchActionOperationEntry(operator, matchAction);
Sangho Shin43cee112014-09-25 16:43:34 -0700992
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700993 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700994 getSwId(sw.getDpid().toString()));
995
Sangho Shin5be3e532014-10-03 17:20:58 -0700996 if (sw13 != null) {
997 try {
Sangho Shinbce900e2014-10-07 17:13:23 -0700998 //printMatchActionOperationEntry(sw, maEntry);
Sangho Shin5be3e532014-10-03 17:20:58 -0700999 if (entries != null)
1000 entries.add(maEntry);
1001 else
1002 sw13.pushFlow(maEntry);
1003 } catch (IOException e) {
1004 e.printStackTrace();
1005 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -07001006 }
1007
Sangho Shin43cee112014-09-25 16:43:34 -07001008 }
1009
Sangho Shinac5ee2b2014-09-28 21:27:20 -07001010 /**
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001011 * Set MPLS forwarding rules to MPLS table
1012 * </p>
1013 * If the destination is the same as the next hop to forward packets then,
1014 * pop the MPLS label according to PHP rule. Here, if BoS is set, then
1015 * copy TTL In and decrement NW TTL. Otherwise, it just decrement the MPLS
1016 * TTL of the another MPLS header.
1017 * If the next hop is not the destination, just forward packets to next
1018 * hops using Group action.
Sangho Shinfbc572c2014-10-02 16:37:05 -07001019 *
Sangho Shin204b9972014-10-22 11:08:10 -07001020 * TODO: refactoring required
1021 *
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001022 * @param sw Switch to set the rules
Sangho Shin43cee112014-09-25 16:43:34 -07001023 * @param mplsLabel destination MPLS label
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001024 * @param fwdSws next hop switches
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001025 * */
Sangho Shin5be3e532014-10-03 17:20:58 -07001026 private void setMplsTable(Switch sw, String mplsLabel, List<String> fwdSws,
1027 boolean modified) {
Sangho Shin463bee52014-09-29 15:14:43 -07001028
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001029 if (fwdSws.isEmpty())
1030 return;
Sangho Shin43cee112014-09-25 16:43:34 -07001031
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001032 Collection<MatchActionOperationEntry> maEntries =
1033 new ArrayList<MatchActionOperationEntry>();
1034 String fwdSw1 = fwdSws.get(0);
Sangho Shin43cee112014-09-25 16:43:34 -07001035
Sangho Shine842cad2014-10-24 16:07:35 -07001036 //If the next hop is the destination router, do PHP
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001037 if (fwdSws.size() == 1 && mplsLabel.equals(getMplsLabel(fwdSw1))) {
Sangho Shine842cad2014-10-24 16:07:35 -07001038 maEntries.add(buildMAEntry(sw, mplsLabel, fwdSws, true, true));
1039 maEntries.add(buildMAEntry(sw, mplsLabel, fwdSws, true, false));
Sangho Shin9c0f4c32014-09-26 16:02:38 -07001040 }
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001041 else {
Sangho Shine842cad2014-10-24 16:07:35 -07001042 maEntries.add(buildMAEntry(sw, mplsLabel, fwdSws, false, true));
1043 maEntries.add(buildMAEntry(sw, mplsLabel, fwdSws, false, false));
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001044 }
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001045 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin9c0f4c32014-09-26 16:02:38 -07001046 getSwId(sw.getDpid().toString()));
1047
Sangho Shin5be3e532014-10-03 17:20:58 -07001048 if (sw13 != null) {
1049 try {
Sangho Shinbce900e2014-10-07 17:13:23 -07001050 //printMatchActionOperationEntry(sw, maEntry);
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001051 sw13.pushFlows(maEntries);
Sangho Shin5be3e532014-10-03 17:20:58 -07001052 } catch (IOException e) {
1053 e.printStackTrace();
1054 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -07001055 }
Sangho Shin43cee112014-09-25 16:43:34 -07001056 }
1057
Sangho Shin7330c032014-10-20 10:34:51 -07001058
Sangho Shine842cad2014-10-24 16:07:35 -07001059
Sangho Shin7330c032014-10-20 10:34:51 -07001060 // ************************************
1061 // Policy routing classes and functions
1062 // ************************************
1063
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001064 public class PolicyInfo {
Sangho Shin5b8f5452014-10-20 11:46:01 -07001065
Sangho Shin58182672014-10-21 13:23:38 -07001066 public final int TYPE_EXPLICIT = 1;
1067 public final int TYPE_AVOID = 2;
1068
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001069 private String policyId;
1070 private PacketMatch match;
1071 private int priority;
1072 private String tunnelId;
Sangho Shin58182672014-10-21 13:23:38 -07001073 private int type;
Sangho Shin5b8f5452014-10-20 11:46:01 -07001074
Sangho Shin58182672014-10-21 13:23:38 -07001075 public PolicyInfo(String pid, int type, PacketMatch match, int priority,
1076 String tid) {
1077 this.policyId = pid;
1078 this.match = match;
1079 this.priority = priority;
1080 this.tunnelId = tid;
1081 this.type = type;
1082 }
Sangho Shin204b9972014-10-22 11:08:10 -07001083
Fahad Naeem Khan95aa4012014-10-21 14:07:00 -07001084 public PolicyInfo(String pid, PacketMatch match, int priority,
1085 String tid) {
1086 this.policyId = pid;
1087 this.match = match;
1088 this.priority = priority;
1089 this.tunnelId = tid;
Fahad Naeem Khan788895c2014-10-21 19:00:24 -07001090 this.type = 0;
Fahad Naeem Khan95aa4012014-10-21 14:07:00 -07001091 }
1092 public String getPolicyId(){
1093 return this.policyId;
1094 }
1095 public PacketMatch getMatch(){
1096 return this.match;
1097 }
1098 public int getPriority(){
1099 return this.priority;
1100 }
1101 public String getTunnelId(){
1102 return this.tunnelId;
1103 }
1104 public int getType(){
1105 return this.type;
1106 }
Sangho Shin5b8f5452014-10-20 11:46:01 -07001107 }
1108
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001109 public class TunnelInfo {
1110 private String tunnelId;
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001111 private List<Integer> labelIds;
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001112 private List<TunnelRouteInfo> routes;
Sangho Shin81655442014-10-20 14:22:46 -07001113
Sangho Shin6471d202014-10-23 10:59:36 -07001114 public TunnelInfo(String tid, List<Integer> labelIds,
1115 List<TunnelRouteInfo> routes) {
Sangho Shin81655442014-10-20 14:22:46 -07001116 this.tunnelId = tid;
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001117 this.labelIds = labelIds;
Sangho Shin81655442014-10-20 14:22:46 -07001118 this.routes = routes;
1119 }
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001120 public String getTunnelId(){
1121 return this.tunnelId;
1122 }
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001123
1124 public List<Integer> getLabelids() {
1125 return this.labelIds;
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001126 }
1127 public List<TunnelRouteInfo> getRoutes(){
1128 return this.routes;
1129 }
Sangho Shin81655442014-10-20 14:22:46 -07001130 }
1131
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001132 public class TunnelRouteInfo {
Sangho Shin7330c032014-10-20 10:34:51 -07001133
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001134 private String srcSwDpid;
1135 private List<Dpid> fwdSwDpids;
1136 private List<String> route;
Sangho Shin6471d202014-10-23 10:59:36 -07001137 private int gropuId;
Sangho Shin7330c032014-10-20 10:34:51 -07001138
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001139 public TunnelRouteInfo() {
Sangho Shin7330c032014-10-20 10:34:51 -07001140 fwdSwDpids = new ArrayList<Dpid>();
1141 route = new ArrayList<String>();
1142 }
1143
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001144 private void setSrcDpid(String dpid) {
Sangho Shin7330c032014-10-20 10:34:51 -07001145 this.srcSwDpid = dpid;
1146 }
1147
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001148 private void setFwdSwDpid(List<Dpid> dpid) {
Sangho Shin7330c032014-10-20 10:34:51 -07001149 this.fwdSwDpids = dpid;
1150 }
1151
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001152 private void addRoute(String id) {
Sangho Shin7330c032014-10-20 10:34:51 -07001153 route.add(id);
1154 }
1155
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001156 private void setRoute(List<String> r) {
Sangho Shin7330c032014-10-20 10:34:51 -07001157 this.route = r;
1158 }
1159
Sangho Shin6471d202014-10-23 10:59:36 -07001160 private void setGroupId(int groupId) {
1161 this.gropuId = groupId;
1162 }
1163
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001164 public String getSrcSwDpid() {
Sangho Shin7330c032014-10-20 10:34:51 -07001165 return this.srcSwDpid;
1166 }
1167
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001168 public List<Dpid> getFwdSwDpid() {
Sangho Shin7330c032014-10-20 10:34:51 -07001169 return this.fwdSwDpids;
1170 }
1171
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001172 public List<String> getRoute() {
Sangho Shin7330c032014-10-20 10:34:51 -07001173 return this.route;
1174 }
Sangho Shin6471d202014-10-23 10:59:36 -07001175
1176 public int getGroupId() {
1177 return this.gropuId;
1178 }
Sangho Shin7330c032014-10-20 10:34:51 -07001179 }
1180
Sangho Shin15273b62014-10-16 22:22:05 -07001181 /**
Sangho Shin81655442014-10-20 14:22:46 -07001182 * Return the Tunnel table
1183 *
1184 * @return collection of TunnelInfo
1185 */
1186 public Collection<TunnelInfo> getTunnelTable() {
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001187 return this.tunnelTable.values();
Sangho Shin81655442014-10-20 14:22:46 -07001188 }
Sangho Shin204b9972014-10-22 11:08:10 -07001189
Fahad Naeem Khan12fa63a2014-10-21 17:01:27 -07001190 public Collection<PolicyInfo> getPoclicyTable() {
1191 return this.policyTable.values();
1192 }
Sangho Shin81655442014-10-20 14:22:46 -07001193
1194 /**
Sangho Shin5671cbb2014-10-20 22:35:41 -07001195 * Return router DPIDs for the tunnel
1196 *
1197 * @param tid tunnel ID
1198 * @return List of DPID
1199 */
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001200 public List<Integer> getTunnelInfo(String tid) {
Sangho Shin5671cbb2014-10-20 22:35:41 -07001201 TunnelInfo tunnelInfo = tunnelTable.get(tid);
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001202 return tunnelInfo.labelIds;
Sangho Shin5671cbb2014-10-20 22:35:41 -07001203
1204 }
1205
1206 /**
1207 * Get the first group ID for the tunnel for specific source router
1208 * If Segment Stitching was required to create the tunnel, there are
1209 * mutiple source routers.
1210 *
1211 * @param tunnelId ID for the tunnel
1212 * @param dpid source router DPID
1213 * @return the first group ID of the tunnel
1214 */
1215 public int getTunnelGroupId(String tunnelId, String dpid) {
Sangho Shin6471d202014-10-23 10:59:36 -07001216 TunnelInfo tunnelInfo = tunnelTable.get(tunnelId);
1217 for (TunnelRouteInfo routeInfo: tunnelInfo.getRoutes()) {
1218 String tunnelSrcDpid = routeInfo.getSrcSwDpid();
1219 if (tunnelSrcDpid.equals(dpid))
1220 return routeInfo.getGroupId();
1221 }
Sangho Shin5671cbb2014-10-20 22:35:41 -07001222
Sangho Shin6471d202014-10-23 10:59:36 -07001223 return -1;
Sangho Shin5671cbb2014-10-20 22:35:41 -07001224 }
1225
1226 /**
Sangho Shin15273b62014-10-16 22:22:05 -07001227 * Create a tunnel for policy routing
1228 * It delivers the node IDs of tunnels to driver.
1229 * Split the node IDs if number of IDs exceeds the limit for stitching.
1230 *
1231 * @param tunnelId Node IDs for the tunnel
1232 * @param Ids tunnel ID
1233 */
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001234 public boolean createTunnel(String tunnelId, List<Integer> labelIds) {
Sangho Shin15273b62014-10-16 22:22:05 -07001235
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001236 if (labelIds.isEmpty() || labelIds.size() < 2) {
Sangho Shin15273b62014-10-16 22:22:05 -07001237 log.debug("Wrong tunnel information");
1238 return false;
1239 }
1240
Sangho Shin55d00e12014-10-20 12:13:07 -07001241 List<String> Ids = new ArrayList<String>();
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001242 for (Integer label : labelIds) {
1243 Ids.add(label.toString());
Sangho Shin55d00e12014-10-20 12:13:07 -07001244 }
1245
Sangho Shin81655442014-10-20 14:22:46 -07001246 List<TunnelRouteInfo> stitchingRule = getStitchingRule(Ids);
Sangho Shin15273b62014-10-16 22:22:05 -07001247 if (stitchingRule == null) {
Sangho Shin6471d202014-10-23 10:59:36 -07001248 log.debug("Failed to get a tunnel rule.");
Sangho Shin15273b62014-10-16 22:22:05 -07001249 return false;
1250 }
Sangho Shin81655442014-10-20 14:22:46 -07001251 for (TunnelRouteInfo route: stitchingRule) {
Sangho Shin15273b62014-10-16 22:22:05 -07001252 NeighborSet ns = new NeighborSet();
1253 for (Dpid dpid: route.getFwdSwDpid())
1254 ns.addDpid(dpid);
1255
Sangho Shin6471d202014-10-23 10:59:36 -07001256 printTunnelInfo(route.srcSwDpid, tunnelId, route.getRoute(), ns);
1257 int groupId = -1;
1258 if ((groupId =createGroupsForTunnel(tunnelId, route, ns)) < 0) {
1259 log.debug("Failed to create a tunnel at driver.");
1260 return false;
1261 }
1262 route.setGroupId(groupId);
Sangho Shin15273b62014-10-16 22:22:05 -07001263 }
1264
Sangho Shin6471d202014-10-23 10:59:36 -07001265 TunnelInfo tunnelInfo = new TunnelInfo(tunnelId, labelIds,
1266 stitchingRule);
Sangho Shin81655442014-10-20 14:22:46 -07001267 tunnelTable.put(tunnelId, tunnelInfo);
Sangho Shin15273b62014-10-16 22:22:05 -07001268
1269 return true;
1270 }
1271
Sangho Shin1a692c02014-10-23 17:05:41 -07001272 /**
1273 * Create groups for the tunnel
1274 *
1275 * @param tunnelId tunnel ID
1276 * @param routeInfo label stacks for the tunnel
1277 * @param ns NeighborSet to forward packets
1278 * @return group ID, return -1 if it fails
1279 */
Sangho Shin6471d202014-10-23 10:59:36 -07001280 private int createGroupsForTunnel(String tunnelId, TunnelRouteInfo routeInfo,
1281 NeighborSet ns) {
1282
1283 IOF13Switch targetSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
1284 getSwId(routeInfo.srcSwDpid));
1285
1286 if (targetSw == null) {
1287 log.debug("Switch {} is gone.", routeInfo.srcSwDpid);
1288 return -1;
1289 }
1290
1291 List<Integer> Ids = new ArrayList<Integer>();
1292 for (String IdStr: routeInfo.route)
1293 Ids.add(Integer.parseInt(IdStr));
1294
1295 List<PortNumber> ports = getPortsFromNeighborSet(routeInfo.srcSwDpid, ns);
1296 int groupId = targetSw.createGroup(Ids, ports);
1297
1298 return groupId;
1299 }
1300
Sangho Shin15273b62014-10-16 22:22:05 -07001301 /**
1302 * Set policy table for policy routing
1303 *
1304 * @param sw
1305 * @param mplsLabel
Sangho Shin306633a2014-10-20 14:26:55 -07001306 * @return
Sangho Shin15273b62014-10-16 22:22:05 -07001307 */
Sangho Shin306633a2014-10-20 14:26:55 -07001308 public boolean createPolicy(String pid, MACAddress srcMac, MACAddress dstMac,
Sangho Shin15273b62014-10-16 22:22:05 -07001309 Short etherType, IPv4Net srcIp, IPv4Net dstIp, Byte ipProto,
Sangho Shine020cc32014-10-20 13:28:02 -07001310 Short srcTcpPort, Short dstTcpPort, int priority, String tid) {
Sangho Shin15273b62014-10-16 22:22:05 -07001311
Sangho Shin5b8f5452014-10-20 11:46:01 -07001312 PacketMatchBuilder packetBuilder = new PacketMatchBuilder();
1313
1314 if (srcMac != null)
1315 packetBuilder.setSrcMac(srcMac);
1316 if (dstMac != null)
1317 packetBuilder.setDstMac(dstMac);
Sangho Shin58182672014-10-21 13:23:38 -07001318 if (etherType == null) // Cqpd requires the type of IPV4
1319 packetBuilder.setEtherType(Ethernet.TYPE_IPV4);
1320 else
Sangho Shin5b8f5452014-10-20 11:46:01 -07001321 packetBuilder.setEtherType(etherType);
1322 if (srcIp != null)
1323 packetBuilder.setSrcIp(srcIp.address(), srcIp.prefixLen());
1324 if (dstIp != null)
1325 packetBuilder.setDstIp(dstIp.address(), dstIp.prefixLen());
1326 if (ipProto != null)
1327 packetBuilder.setIpProto(ipProto);
1328 if (srcTcpPort > 0)
1329 packetBuilder.setSrcTcpPort(srcTcpPort);
1330 if (dstTcpPort > 0)
1331 packetBuilder.setDstTcpPort(dstTcpPort);
1332 PacketMatch policyMatch = packetBuilder.build();
Sangho Shin81655442014-10-20 14:22:46 -07001333 TunnelInfo tunnelInfo = tunnelTable.get(tid);
Sangho Shin6471d202014-10-23 10:59:36 -07001334 if (tunnelInfo == null) {
1335 log.debug("Tunnel {} is not defined", tid);
1336 return false;
1337 }
Sangho Shin81655442014-10-20 14:22:46 -07001338 List<TunnelRouteInfo> routes = tunnelInfo.routes;
Sangho Shin5b8f5452014-10-20 11:46:01 -07001339
Sangho Shin81655442014-10-20 14:22:46 -07001340 for (TunnelRouteInfo route : routes) {
Sangho Shin15273b62014-10-16 22:22:05 -07001341 List<Action> actions = new ArrayList<>();
1342 GroupAction groupAction = new GroupAction();
Sangho Shin6471d202014-10-23 10:59:36 -07001343 groupAction.setGroupId(route.getGroupId());
Sangho Shin15273b62014-10-16 22:22:05 -07001344 actions.add(groupAction);
1345
1346 MatchAction matchAction = new MatchAction(new MatchActionId(
1347 matchActionId++),
Sangho Shin5b8f5452014-10-20 11:46:01 -07001348 new SwitchPort((long) 0, (short) 0), policyMatch, priority,
1349 actions);
Sangho Shin15273b62014-10-16 22:22:05 -07001350 MatchActionOperationEntry maEntry =
1351 new MatchActionOperationEntry(Operator.ADD, matchAction);
1352
1353 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin81655442014-10-20 14:22:46 -07001354 getSwId(route.srcSwDpid));
Sangho Shin15273b62014-10-16 22:22:05 -07001355
1356 if (sw13 != null) {
1357 printMatchActionOperationEntry(sw13, maEntry);
1358 try {
1359 sw13.pushFlow(maEntry);
1360 } catch (IOException e) {
1361 e.printStackTrace();
Sangho Shin306633a2014-10-20 14:26:55 -07001362 return false;
Sangho Shin15273b62014-10-16 22:22:05 -07001363 }
1364 }
1365 }
Sangho Shin5b8f5452014-10-20 11:46:01 -07001366
1367 PolicyInfo policyInfo = new PolicyInfo(pid, policyMatch, priority, tid);
Sangho Shine020cc32014-10-20 13:28:02 -07001368 policyTable.put(pid, policyInfo);
Sangho Shin306633a2014-10-20 14:26:55 -07001369
1370 return true;
Sangho Shin15273b62014-10-16 22:22:05 -07001371 }
1372
1373 /**
Sangho Shin1ad7be02014-10-20 16:56:49 -07001374 * Split the nodes IDs into multiple tunnel if Segment Stitching is required.
1375 * We assume that the first node ID is the one of source router, and the last
1376 * node ID is that of the destination router.
Sangho Shin15273b62014-10-16 22:22:05 -07001377 *
Sangho Shin1ad7be02014-10-20 16:56:49 -07001378 * @param route list of node IDs
1379 * @return List of the TunnelRoutInfo
Sangho Shin15273b62014-10-16 22:22:05 -07001380 */
Sangho Shin81655442014-10-20 14:22:46 -07001381 private List<TunnelRouteInfo> getStitchingRule(List<String> route) {
Sangho Shin15273b62014-10-16 22:22:05 -07001382
Sangho Shin1a692c02014-10-23 17:05:41 -07001383 if (route.isEmpty() || route.size() < 3)
Sangho Shin15273b62014-10-16 22:22:05 -07001384 return null;
1385
Sangho Shin81655442014-10-20 14:22:46 -07001386 List<TunnelRouteInfo> rules = new ArrayList<TunnelRouteInfo>();
Sangho Shin15273b62014-10-16 22:22:05 -07001387
1388 Switch srcSw = this.getSwitchFromNodeId(route.get(0));
Sangho Shin6471d202014-10-23 10:59:36 -07001389 if (srcSw == null) {
1390 log.warn("Switch is not found for Node SID {}", route.get(0));
1391 return null;
1392 }
Sangho Shin15273b62014-10-16 22:22:05 -07001393 String srcDpid = srcSw.getDpid().toString();
1394
Sangho Shin15273b62014-10-16 22:22:05 -07001395 int i = 0;
Sangho Shine020cc32014-10-20 13:28:02 -07001396 TunnelRouteInfo routeInfo = new TunnelRouteInfo();
Sangho Shin1a692c02014-10-23 17:05:41 -07001397 boolean checkNeighbor = false;
Sangho Shin6471d202014-10-23 10:59:36 -07001398 String prevAdjacencySid = null;
1399 String prevNodeId = null;
Sangho Shin15273b62014-10-16 22:22:05 -07001400
1401 for (String nodeId: route) {
Sangho Shin6471d202014-10-23 10:59:36 -07001402 // The first node ID is always the source router.
1403 // We assume that the first ID cannot be an Adjacency SID.
Sangho Shin15273b62014-10-16 22:22:05 -07001404 if (i == 0) {
Sangho Shin15273b62014-10-16 22:22:05 -07001405 srcSw = getSwitchFromNodeId(nodeId);
Sangho Shin1a692c02014-10-23 17:05:41 -07001406 if (srcDpid == null)
1407 srcDpid = srcSw.getDpid().toString();
1408 routeInfo.setSrcDpid(srcDpid);
1409 checkNeighbor = true;
Sangho Shin15273b62014-10-16 22:22:05 -07001410 i++;
1411 }
Sangho Shin1a692c02014-10-23 17:05:41 -07001412 // if this is the first node ID to put the label stack..
Sangho Shin6471d202014-10-23 10:59:36 -07001413 else if (i == 1) {
Sangho Shin1a692c02014-10-23 17:05:41 -07001414 if (checkNeighbor) {
1415 List<Dpid> fwdSws = getDpidIfNeighborOf(nodeId, srcSw);
1416 // if nodeId is NOT the neighbor of srcSw..
1417 if (fwdSws.isEmpty()) {
1418 fwdSws = getForwardingSwitchForNodeId(srcSw,nodeId);
1419 if (fwdSws == null || fwdSws.isEmpty()) {
1420 log.warn("There is no route from node {} to node {}",
1421 srcSw.getDpid(), nodeId);
1422 return null;
Sangho Shin6471d202014-10-23 10:59:36 -07001423 }
Sangho Shin6471d202014-10-23 10:59:36 -07001424 routeInfo.addRoute(nodeId);
Sangho Shin6471d202014-10-23 10:59:36 -07001425 i++;
1426 }
Sangho Shin1a692c02014-10-23 17:05:41 -07001427 routeInfo.setFwdSwDpid(fwdSws);
Sangho Shin6471d202014-10-23 10:59:36 -07001428 // we check only the next node ID of the source router
1429 checkNeighbor = false;
Sangho Shin1a692c02014-10-23 17:05:41 -07001430 }
1431 // if neighbor check is already done, then just add it
1432 else {
Sangho Shin6471d202014-10-23 10:59:36 -07001433 routeInfo.addRoute(nodeId);
Sangho Shin15273b62014-10-16 22:22:05 -07001434 i++;
1435 }
1436 }
Sangho Shin6471d202014-10-23 10:59:36 -07001437 // if i > 1
Sangho Shin15273b62014-10-16 22:22:05 -07001438 else {
Sangho Shin6471d202014-10-23 10:59:36 -07001439 // If the adjacency SID is pushed and the next SID is the destination
1440 // of the adjacency SID, then do not add the SID.
1441 if (prevAdjacencySid != null) {
1442 if (isAdjacencySidNeighborOf(prevNodeId, prevAdjacencySid, nodeId)) {
1443 prevAdjacencySid = null;
1444 continue;
1445 }
1446 prevAdjacencySid = null;
1447 }
Sangho Shin15273b62014-10-16 22:22:05 -07001448 routeInfo.addRoute(nodeId);
1449 i++;
1450 }
1451
Sangho Shin1a692c02014-10-23 17:05:41 -07001452 // If the adjacency ID is added the label stack,
1453 // then we need to check if the next node is the destination of the adjacency SID
1454 if (isAdjacencySid(nodeId))
1455 prevAdjacencySid = nodeId;
1456
Sangho Shin1ad7be02014-10-20 16:56:49 -07001457 // If the number of labels reaches the limit, start over the procedure
Sangho Shin15273b62014-10-16 22:22:05 -07001458 if (i == MAX_NUM_LABELS+1) {
Sangho Shin1a692c02014-10-23 17:05:41 -07001459
Sangho Shin81655442014-10-20 14:22:46 -07001460 rules.add(routeInfo);
Sangho Shine020cc32014-10-20 13:28:02 -07001461 routeInfo = new TunnelRouteInfo();
Sangho Shin1a692c02014-10-23 17:05:41 -07001462
Sangho Shin62325582014-10-24 10:36:09 -07001463 if (isAdjacencySid(nodeId)) {
1464 // If the previous sub tunnel finishes with adjacency SID,
1465 // then we need to start the procedure from the adjacency
1466 // destination ID.
1467 List<Switch> destNodeList =
1468 getAdjacencyDestinationNode(prevNodeId, nodeId);
1469 if (destNodeList == null || destNodeList.isEmpty()) {
1470 log.warn("Cannot find destination node for adjacencySID {}",
1471 nodeId);
1472 return null;
1473 }
1474 // If the previous sub tunnel finishes with adjacency SID with
1475 // multiple ports, then we need to remove the adjacency Sid
1476 // from the previous sub tunnel and start the new sub tunnel
1477 // with the adjacency Sid. Technically, the new subtunnel
1478 // forward packets to the port assigned to the adjacency Sid
1479 // and the label stack starts with the next ID.
1480 // This is to avoid to install new policy rule to multiple nodes for stitching when the
1481 // adjacency Sid that has more than one port.
1482 if (destNodeList.size() > 1) {
1483 rules.get(rules.size()-1).route.remove(nodeId);
1484 srcSw = getSwitchFromNodeId(prevNodeId);
1485 List<Dpid> fwdSws = getDpidIfNeighborOf(nodeId, srcSw);
1486 routeInfo.setFwdSwDpid(fwdSws);
1487 routeInfo.setSrcDpid(srcSw.getDpid().toString());
1488 i = 1;
1489 checkNeighbor = false;
1490 continue;
1491 }
1492 else {
Sangho Shin1a692c02014-10-23 17:05:41 -07001493 srcSw = destNodeList.get(0);
Sangho Shin62325582014-10-24 10:36:09 -07001494 }
1495 }
1496 else {
1497 srcSw = getSwitchFromNodeId(nodeId);
Sangho Shin1a692c02014-10-23 17:05:41 -07001498 }
1499 srcDpid = srcSw.getDpid().toString();
Sangho Shin15273b62014-10-16 22:22:05 -07001500 routeInfo.setSrcDpid(srcDpid);
1501 i = 1;
1502 checkNeighbor = true;
1503 }
Sangho Shin6471d202014-10-23 10:59:36 -07001504
1505 if (prevAdjacencySid == null)
1506 prevNodeId = nodeId;
Sangho Shin15273b62014-10-16 22:22:05 -07001507 }
1508
Sangho Shin1a692c02014-10-23 17:05:41 -07001509
Sangho Shineb148ea2014-10-24 12:44:15 -07001510 if (i < MAX_NUM_LABELS+1 && (routeInfo.getFwdSwDpid() != null &&
1511 !routeInfo.getFwdSwDpid().isEmpty())) {
Sangho Shin81655442014-10-20 14:22:46 -07001512 rules.add(routeInfo);
Sangho Shineb148ea2014-10-24 12:44:15 -07001513 // NOTE: empty label stack can happen, but forwarding destination should be set
Sangho Shin15273b62014-10-16 22:22:05 -07001514 }
1515
1516 return rules;
1517 }
1518
Sangho Shin5b8f5452014-10-20 11:46:01 -07001519 /**
1520 * Remove all policies applied to specific tunnel.
1521 *
1522 * @param srcMac
1523 * @param dstMac
1524 * @param etherType
1525 * @param srcIp
1526 * @param dstIp
1527 * @param ipProto
1528 * @param srcTcpPort
1529 * @param dstTcpPort
1530 * @param tid
Sangho Shin306633a2014-10-20 14:26:55 -07001531 * @return
Sangho Shin5b8f5452014-10-20 11:46:01 -07001532 */
Sangho Shin306633a2014-10-20 14:26:55 -07001533 public boolean removePolicy(String pid) {
Sangho Shine020cc32014-10-20 13:28:02 -07001534 PolicyInfo policyInfo = policyTable.get(pid);
Sangho Shin5671cbb2014-10-20 22:35:41 -07001535 if (policyInfo == null)
1536 return false;
Sangho Shin5b8f5452014-10-20 11:46:01 -07001537 PacketMatch policyMatch = policyInfo.match;
Sangho Shine020cc32014-10-20 13:28:02 -07001538 String tid = policyInfo.tunnelId;
Sangho Shin5b8f5452014-10-20 11:46:01 -07001539 int priority = policyInfo.priority;
1540
1541 List<Action> actions = new ArrayList<>();
1542 int gropuId = 0; // dummy group ID
1543 GroupAction groupAction = new GroupAction();
1544 groupAction.setGroupId(gropuId);
1545 actions.add(groupAction);
1546
1547 MatchAction matchAction = new MatchAction(new MatchActionId(
1548 matchActionId++),
1549 new SwitchPort((long) 0, (short) 0), policyMatch, priority,
1550 actions);
1551 MatchActionOperationEntry maEntry =
1552 new MatchActionOperationEntry(Operator.REMOVE, matchAction);
1553
Sangho Shin81655442014-10-20 14:22:46 -07001554 TunnelInfo tunnelInfo = tunnelTable.get(tid);
Sangho Shin5671cbb2014-10-20 22:35:41 -07001555 if (tunnelInfo == null)
1556 return false;
Sangho Shin81655442014-10-20 14:22:46 -07001557 List<TunnelRouteInfo> routes = tunnelInfo.routes;
1558
1559 for (TunnelRouteInfo route : routes) {
Sangho Shin5b8f5452014-10-20 11:46:01 -07001560 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin81655442014-10-20 14:22:46 -07001561 getSwId(route.srcSwDpid));
Sangho Shin5b8f5452014-10-20 11:46:01 -07001562
Sangho Shin5671cbb2014-10-20 22:35:41 -07001563 if (sw13 == null) {
1564 return false;
1565 }
1566 else {
Sangho Shin5b8f5452014-10-20 11:46:01 -07001567 printMatchActionOperationEntry(sw13, maEntry);
1568 try {
1569 sw13.pushFlow(maEntry);
1570 } catch (IOException e) {
1571 e.printStackTrace();
1572 log.debug("policy remove failed due to pushFlow() exception");
Sangho Shin306633a2014-10-20 14:26:55 -07001573 return false;
Sangho Shin5b8f5452014-10-20 11:46:01 -07001574 }
1575 }
1576 }
1577
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001578 policyTable.remove(pid);
Sangho Shin5b8f5452014-10-20 11:46:01 -07001579 log.debug("Policy {} is removed.", pid);
Sangho Shin306633a2014-10-20 14:26:55 -07001580 return true;
Sangho Shine020cc32014-10-20 13:28:02 -07001581 }
Sangho Shin5b8f5452014-10-20 11:46:01 -07001582
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001583 /**
1584 * Remove a tunnel
1585 * It removes all groups for the tunnel if the tunnel is not used for any
1586 * policy.
1587 *
1588 * @param tunnelId tunnel ID to remove
1589 */
Sangho Shin306633a2014-10-20 14:26:55 -07001590 public boolean removeTunnel(String tunnelId) {
Sangho Shin55d00e12014-10-20 12:13:07 -07001591
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001592 // Check if the tunnel is used for any policy
1593 for (PolicyInfo policyInfo: policyTable.values()) {
Sangho Shina000c612014-10-21 14:17:59 -07001594 if (policyInfo.tunnelId.equals(tunnelId)) {
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001595 log.debug("Tunnel {} is still used for the policy {}.",
1596 policyInfo.policyId, tunnelId);
1597 return false;
1598 }
1599 }
1600
1601 TunnelInfo tunnelInfo = tunnelTable.get(tunnelId);
Sangho Shin5671cbb2014-10-20 22:35:41 -07001602 if (tunnelInfo == null)
1603 return false;
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001604
1605 List<TunnelRouteInfo> routes = tunnelInfo.routes;
1606 for (TunnelRouteInfo route: routes) {
1607 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
1608 getSwId(route.srcSwDpid));
1609
Sangho Shin5671cbb2014-10-20 22:35:41 -07001610 if (sw13 == null) {
1611 return false;
1612 }
1613 else {
Sangho Shin93f623c2014-10-24 12:59:53 -07001614 if (!sw13.removeGroup(route.getGroupId())) {
Sangho Shine842cad2014-10-24 16:07:35 -07001615 log.warn("Faied to remove the tunnel {} at driver",
1616 tunnelId);
Sangho Shin93f623c2014-10-24 12:59:53 -07001617 return false; }
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001618 }
1619 }
1620
1621 tunnelTable.remove(tunnelId);
Sangho Shine842cad2014-10-24 16:07:35 -07001622 log.debug("Tunnel {} was removed successfully.", tunnelId);
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001623
Sangho Shin306633a2014-10-20 14:26:55 -07001624 return true;
Sangho Shin55d00e12014-10-20 12:13:07 -07001625 }
1626
Sangho Shin7330c032014-10-20 10:34:51 -07001627 // ************************************
1628 // Utility functions
1629 // ************************************
1630
Sangho Shin1a692c02014-10-23 17:05:41 -07001631 /**
1632 * Get the destination Nodes of the adjacency Sid
1633 *
1634 * @param nodeId node ID of the adjacency Sid
1635 * @param adjacencySid adjacency Sid
1636 * @return List of Switch, empty list if not found
1637 */
1638 private List<Switch> getAdjacencyDestinationNode(String nodeId, String adjacencySid) {
1639 List<Switch> dstSwList = new ArrayList<Switch>();
1640
1641 HashMap<Integer, List<Integer>> adjacencySidInfo =
1642 adjacencySidTable.get(Integer.valueOf(nodeId));
1643 List<Integer> ports = adjacencySidInfo.get(Integer.valueOf(adjacencySid));
1644 Switch srcSw = getSwitchFromNodeId(nodeId);
1645 for (Integer port: ports) {
1646 for (Link link: srcSw.getOutgoingLinks()) {
1647 if (link.getSrcPort().getPortNumber().value() == port) {
1648 dstSwList.add(link.getDstSwitch());
1649 }
1650 }
1651 }
1652
1653 return dstSwList;
1654
1655 }
1656
1657 /**
1658 * Get the DPID of the router with node ID IF the node ID is the neighbor of the
1659 * Switch srcSW.
1660 * If the nodeId is the adjacency Sid, then it returns the destination router DPIDs.
1661 *
1662 * @param nodeId Node ID to check
1663 * @param srcSw target Switch
1664 * @return List of DPID of nodeId, empty list if the nodeId is not the neighbor of srcSW
1665 */
1666 private List<Dpid> getDpidIfNeighborOf(String nodeId, Switch srcSw) {
1667 List<Dpid> fwdSws = new ArrayList<Dpid>();
1668 // if the nodeID is the adjacency ID, then we need to regard it as the
1669 // neighbor node ID and need to return the destination router DPID(s)
1670 if (isAdjacencySid(nodeId)) {
1671 String srcNodeId = this.getMplsLabel(srcSw.getDpid().toString());
1672 HashMap<Integer, List<Integer>> adjacencySidInfo =
1673 adjacencySidTable.get(Integer.valueOf(srcNodeId));
1674 List<Integer> ports = adjacencySidInfo.get(Integer.valueOf(nodeId));
1675
1676 for (Integer port: ports) {
1677 for (Link link: srcSw.getOutgoingLinks()) {
1678 if (link.getSrcPort().getPortNumber().value() == port) {
1679 fwdSws.add(link.getDstSwitch().getDpid());
1680 }
1681 }
1682 }
1683 }
1684 else {
1685 List<Dpid> fwdSwDpids = getForwardingSwitchForNodeId(srcSw,nodeId);
1686 if (fwdSwDpids == null || fwdSwDpids.isEmpty()) {
1687 log.warn("There is no route from node {} to node {}",
1688 srcSw.getDpid(), nodeId);
1689 return null;
1690 }
1691
1692 for (Dpid dpid: fwdSwDpids) {
1693 if (getMplsLabel(dpid.toString()).toString().equals(nodeId)) {
1694 fwdSws.add(dpid);
1695 break;
1696 }
1697 }
1698 }
1699
1700 return fwdSws;
1701 }
1702
1703 /**
1704 * Get port numbers of the neighbor set
1705 *
1706 * @param srcSwDpid source switch
1707 * @param ns Neighbor set of the switch
1708 * @return List of PortNumber, null if not found
1709 */
Sangho Shin6471d202014-10-23 10:59:36 -07001710 private List<PortNumber> getPortsFromNeighborSet(String srcSwDpid, NeighborSet ns) {
1711
1712 List<PortNumber> portList = new ArrayList<PortNumber>();
1713 Switch srcSwitch = mutableTopology.getSwitch(new Dpid(srcSwDpid));
1714 if (srcSwitch == null)
1715 return null;
1716 for (Dpid neighborDpid: ns.getDpids()) {
1717 Link link = srcSwitch.getLinkToNeighbor(neighborDpid);
1718 portList.add(link.getSrcPort().getNumber());
1719 }
1720
1721 return portList;
1722 }
1723
Sangho Shine842cad2014-10-24 16:07:35 -07001724 /**
1725 * Check whether the router with preNodeid is connected to the router
1726 * with nodeId via adjacencySid or not
1727 *
1728 * @param prevNodeId the router node ID of the adjacencySid
1729 * @param adjacencySid adjacency SID
1730 * @param nodeId the router node ID to check
1731 * @return
1732 */
1733 private boolean isAdjacencySidNeighborOf(String prevNodeId, String adjacencySid, String nodeId) {
Sangho Shin6471d202014-10-23 10:59:36 -07001734
1735 HashMap<Integer, List<Integer>> adjacencySidInfo = adjacencySidTable.get(Integer.valueOf(prevNodeId));
Sangho Shine842cad2014-10-24 16:07:35 -07001736 List<Integer> ports = adjacencySidInfo.get(Integer.valueOf(adjacencySid));
Sangho Shin6471d202014-10-23 10:59:36 -07001737
1738 for (Integer port: ports) {
1739 Switch sw = getSwitchFromNodeId(prevNodeId);
1740 for (Link link: sw.getOutgoingLinks()) {
1741 if (link.getSrcPort().getPortNumber().value() == port) {
1742 if (getMplsLabel(link.getDstPort().getDpid().toString()).equals(nodeId)) {
1743 return true;
1744 }
1745 }
1746 }
1747 }
1748
1749 return false;
1750 }
1751
Sangho Shine842cad2014-10-24 16:07:35 -07001752 /**
1753 * Check if the node ID is the adjacency ID or not
1754 *
1755 * @param nodeId to check
1756 * @return true if the node ID is the adjacency ID, false otherwise
1757 */
Sangho Shin6471d202014-10-23 10:59:36 -07001758 private boolean isAdjacencySid(String nodeId) {
1759 // XXX The rule might change
1760 if (Integer.parseInt(nodeId) > 10000)
1761 return true;
1762
1763 return false;
1764 }
1765
Sangho Shin15273b62014-10-16 22:22:05 -07001766 /**
Sangho Shinced05b62014-10-22 11:23:14 -07001767 * Returns the Adjacency IDs for the node
1768 *
1769 * @param nodeSid Node SID
Sangho Shincfef3922014-10-22 12:04:16 -07001770 * @return Collection of Adjacency ID
Sangho Shinced05b62014-10-22 11:23:14 -07001771 */
Sangho Shincfef3922014-10-22 12:04:16 -07001772 public Collection<Integer> getAdjacencyIds(int nodeSid) {
1773 HashMap<Integer, List<Integer>> adjecencyInfo =
Sangho Shin6471d202014-10-23 10:59:36 -07001774 adjacencySidTable.get(Integer.valueOf(nodeSid));
Sangho Shincfef3922014-10-22 12:04:16 -07001775
1776 return adjecencyInfo.keySet();
1777 }
1778
1779 /**
1780 * Returns the Adjacency Info for the node
1781 *
1782 * @param nodeSid Node SID
1783 * @return HashMap of <AdjacencyID, list of ports>
1784 */
1785 public HashMap<Integer, List<Integer>> getAdjacencyInfo(int nodeSid) {
Sangho Shin6471d202014-10-23 10:59:36 -07001786 return adjacencySidTable.get(Integer.valueOf(nodeSid));
Sangho Shincfef3922014-10-22 12:04:16 -07001787 }
1788
Sangho Shine842cad2014-10-24 16:07:35 -07001789 /**
1790 * Parse the adjacency jason string and build the adjacency Table
1791 *
1792 * @param adjInfo adjacency info jason string
1793 * @return HashMap<Adjacency ID, List of ports> object
1794 * @throws JSONException
1795 */
1796 private HashMap<Integer, List<Integer>> parseAdjacencySidInfo(String adjInfo)
1797 throws JSONException {
Sangho Shincfef3922014-10-22 12:04:16 -07001798 JSONArray arry = new JSONArray(adjInfo);
1799 HashMap<Integer, List<Integer>> AdjacencyInfo =
1800 new HashMap<Integer, List<Integer>>();
1801
1802 for (int i = 0; i < arry.length(); i++) {
1803 Integer adjId = (Integer) arry.getJSONObject(i).get("adjSid");
1804 JSONArray portNos = (JSONArray) arry.getJSONObject(i).get("ports");
1805 if (adjId == null || portNos == null)
1806 continue;
1807
1808 List<Integer> portNoList = new ArrayList<Integer>();
1809 for (int j = 0; j < portNos.length(); j++) {
Sangho Shin62325582014-10-24 10:36:09 -07001810 portNoList.add(Integer.valueOf(portNos.getInt(j)));
Sangho Shincfef3922014-10-22 12:04:16 -07001811 }
1812 AdjacencyInfo.put(adjId, portNoList);
1813 }
1814 return AdjacencyInfo;
Sangho Shinced05b62014-10-22 11:23:14 -07001815 }
1816
1817 /**
Sangho Shine842cad2014-10-24 16:07:35 -07001818 * Build the MatchActionOperationEntry according to the flag
1819 *
1820 * @param sw node ID to push for MPLS label
1821 * @param mplsLabel List of Switch DPIDs to forwards packets to
1822 * @param fwdSws PHP flag
1823 * @param Bos BoS flag
1824 * @param isTransitRouter
1825 * @return MatchiACtionOperationEntry object
1826 */
1827 private MatchActionOperationEntry buildMAEntry(Switch sw,
1828 String mplsLabel, List<String> fwdSws, boolean php,
1829 boolean Bos) {
1830 MplsMatch mplsMatch = new MplsMatch(Integer.parseInt(mplsLabel), Bos);
1831 List<Action> actions = new ArrayList<Action>();
1832
1833 PopMplsAction popActionBos = new PopMplsAction(EthType.IPv4);
1834 PopMplsAction popAction = new PopMplsAction(EthType.MPLS_UNICAST);
1835 CopyTtlInAction copyTtlInAction = new CopyTtlInAction();
1836 DecNwTtlAction decNwTtlAction = new DecNwTtlAction(1);
1837 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
1838
1839 if (php) {
1840 actions.add(copyTtlInAction);
1841 if (Bos) {
1842 actions.add(popActionBos);
1843 actions.add(decNwTtlAction);
1844 }
1845 else {
1846 actions.add(popAction);
1847 actions.add(decMplsTtlAction);
1848 }
1849 }
1850 else {
1851 actions.add(decMplsTtlAction);
1852 }
1853
1854 if (!supportTransitECMP && isTransitRouter(sw) && !php) {
1855 PortNumber port = pickOnePort(sw, fwdSws);
1856 if (port == null) {
1857 log.warn("Failed to get a port from NeightborSet");
1858 return null;
1859 }
1860 OutputAction outputAction = new OutputAction(port);
1861 Switch destSwitch =
1862 mutableTopology.getSwitch(new Dpid(fwdSws.get(0)));
1863 MacAddress srcMac =
1864 MacAddress.of(sw.getStringAttribute("routerMac"));
1865 MacAddress dstMac =
1866 MacAddress.of(destSwitch.getStringAttribute("routerMac"));
1867 SetSAAction setSAAction = new SetSAAction(srcMac);
1868 SetDAAction setDAAction = new SetDAAction(dstMac);
1869 actions.add(outputAction);
1870 actions.add(setSAAction);
1871 actions.add(setDAAction);
1872 }
1873 else {
1874 GroupAction groupAction = new GroupAction();
1875 for (String dpid: fwdSws)
1876 groupAction.addSwitch(new Dpid(dpid));
1877 actions.add(groupAction);
1878 }
1879
1880 MatchAction matchAction = new MatchAction(new MatchActionId(matchActionId++),
1881 new SwitchPort((long) 0, (short) 0), mplsMatch, actions);
1882 Operator operator = Operator.ADD;
1883 MatchActionOperationEntry maEntry =
1884 new MatchActionOperationEntry(operator, matchAction);
1885
1886 return maEntry;
1887 }
1888
1889 /**
1890 * Pick a router from the neighbor set and return the port
1891 * connected to the router.
1892 *
1893 * @param sw source switch
1894 * @param fwdSwDpids neighbor set of the switch
1895 * @return PortNumber connected to one of the neighbors
1896 */
1897 private PortNumber pickOnePort(Switch sw, List<String> fwdSwDpids) {
1898 for (Link link: sw.getOutgoingLinks()) {
1899 if (link.getDstSwitch().getDpid().toString().equals(fwdSwDpids.get(0)))
1900 return link.getSrcPort().getNumber();
1901 }
1902
1903 return null;
1904 }
1905
1906 /**
1907 * check if the router is the transit router or not
1908 *
1909 * @param sw router switch to check
1910 * @return true if the switch is the transit router, false otherwise
1911 */
1912 private boolean isTransitRouter(Switch sw) {
1913 int i = 0;
1914 for(Switch neighbor: sw.getNeighbors()) {
1915 i++;
1916 }
1917 if (i > 1)
1918 return true;
1919 else
1920 return false;
1921 }
1922
1923 /**
Sangho Shin7330c032014-10-20 10:34:51 -07001924 * Get the forwarding Switch DPIDs to send packets to a node
Sangho Shin15273b62014-10-16 22:22:05 -07001925 *
Sangho Shin7330c032014-10-20 10:34:51 -07001926 * @param srcSw source switch
1927 * @param nodeId destination node Id
1928 * @return list of switch DPID to forward packets to
Sangho Shin15273b62014-10-16 22:22:05 -07001929 */
Sangho Shin7330c032014-10-20 10:34:51 -07001930 private List<Dpid> getForwardingSwitchForNodeId(Switch srcSw, String nodeId) {
Sangho Shin15273b62014-10-16 22:22:05 -07001931
Sangho Shin7330c032014-10-20 10:34:51 -07001932 List<Dpid> fwdSws = new ArrayList<Dpid>();
1933 Switch destSw = null;
Sangho Shin15273b62014-10-16 22:22:05 -07001934
Sangho Shin7330c032014-10-20 10:34:51 -07001935 destSw = getSwitchFromNodeId(nodeId);
1936
1937 if (destSw == null) {
1938 log.debug("Cannot find the switch with ID {}", nodeId);
1939 return null;
1940 }
1941
1942 ECMPShortestPathGraph ecmpSPG = new ECMPShortestPathGraph(srcSw);
1943
1944 HashMap<Integer, HashMap<Switch, ArrayList<ArrayList<Dpid>>>> switchVia =
1945 ecmpSPG.getAllLearnedSwitchesAndVia();
1946 for (Integer itrIdx : switchVia.keySet()) {
1947 HashMap<Switch, ArrayList<ArrayList<Dpid>>> swViaMap =
1948 switchVia.get(itrIdx);
1949 for (Switch targetSw : swViaMap.keySet()) {
1950 String destSwDpid = destSw.getDpid().toString();
1951 if (targetSw.getDpid().toString().equals(destSwDpid)) {
1952 for (ArrayList<Dpid> via : swViaMap.get(targetSw)) {
1953 if (via.isEmpty()) {
1954 fwdSws.add(destSw.getDpid());
1955 }
1956 else {
Sangho Shina000c612014-10-21 14:17:59 -07001957 Dpid firstVia = via.get(via.size()-1);
1958 fwdSws.add(firstVia);
Sangho Shin7330c032014-10-20 10:34:51 -07001959 }
1960 }
1961 }
1962 }
1963 }
1964
1965 return fwdSws;
Sangho Shin15273b62014-10-16 22:22:05 -07001966 }
1967
Sangho Shin7330c032014-10-20 10:34:51 -07001968 /**
1969 * Get switch for the node Id specified
1970 *
1971 * @param nodeId node ID for switch
1972 * @return Switch
1973 */
1974 private Switch getSwitchFromNodeId(String nodeId) {
Fahad Naeem Khan4444b952014-10-18 22:30:50 -07001975
Sangho Shin7330c032014-10-20 10:34:51 -07001976 for (Switch sw : mutableTopology.getSwitches()) {
1977 String id = sw.getStringAttribute("nodeSid");
1978 if (id.equals(nodeId)) {
1979 return sw;
1980 }
1981 }
1982
1983 return null;
1984 }
Fahad Naeem Khan4444b952014-10-18 22:30:50 -07001985
Sangho Shin43cee112014-09-25 16:43:34 -07001986 /**
Sangho Shin7330c032014-10-20 10:34:51 -07001987 * Convert a string DPID to its Switch Id (integer)
Sangho Shinfbc572c2014-10-02 16:37:05 -07001988 *
Sangho Shin7330c032014-10-20 10:34:51 -07001989 * @param dpid
1990 * @return
Sangho Shin43cee112014-09-25 16:43:34 -07001991 */
Sangho Shin7330c032014-10-20 10:34:51 -07001992 private long getSwId(String dpid) {
Sangho Shin43cee112014-09-25 16:43:34 -07001993
Sangho Shin7330c032014-10-20 10:34:51 -07001994 long swId = 0;
Sangho Shin43cee112014-09-25 16:43:34 -07001995
Sangho Shin7330c032014-10-20 10:34:51 -07001996 String swIdHexStr = "0x"+dpid.substring(dpid.lastIndexOf(":") + 1);
1997 if (swIdHexStr != null)
1998 swId = Integer.decode(swIdHexStr);
Sangho Shin43cee112014-09-25 16:43:34 -07001999
Sangho Shin7330c032014-10-20 10:34:51 -07002000 return swId;
2001 }
Sangho Shin43cee112014-09-25 16:43:34 -07002002
Sangho Shin7330c032014-10-20 10:34:51 -07002003 /**
2004 * Check if the switch is the edge router or not.
2005 *
2006 * @param dpid Dpid of the switch to check
2007 * @return true if it is an edge router, otherwise false
2008 */
2009 private boolean IsEdgeRouter(String dpid) {
Sangho Shin0df01982014-09-25 17:11:18 -07002010
Sangho Shin7330c032014-10-20 10:34:51 -07002011 for (Switch sw : mutableTopology.getSwitches()) {
2012 String dpidStr = sw.getDpid().toString();
2013 if (dpid.equals(dpidStr)) {
2014 /*
2015 String subnetInfo = sw.getStringAttribute("subnets");
2016 if (subnetInfo == null || subnetInfo.equals("[]")) {
2017 return false;
2018 }
2019 else
2020 return true;
2021 */
2022 String isEdge = sw.getStringAttribute("isEdgeRouter");
2023 if (isEdge != null) {
2024 if (isEdge.equals("true"))
2025 return true;
2026 else
2027 return false;
2028 }
Sangho Shin43cee112014-09-25 16:43:34 -07002029 }
2030 }
2031
Sangho Shin7330c032014-10-20 10:34:51 -07002032 return false;
Sangho Shineb083032014-09-22 16:11:34 -07002033 }
2034
2035 /**
2036 * Get MPLS label reading the config file
Sangho Shinfbc572c2014-10-02 16:37:05 -07002037 *
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002038 * @param dipid DPID of the switch
Sangho Shineb083032014-09-22 16:11:34 -07002039 * @return MPLS label for the switch
2040 */
Sangho Shin43cee112014-09-25 16:43:34 -07002041 private String getMplsLabel(String dpid) {
Sangho Shineb083032014-09-22 16:11:34 -07002042
2043 String mplsLabel = null;
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002044 for (Switch sw : mutableTopology.getSwitches()) {
Sangho Shin43cee112014-09-25 16:43:34 -07002045 String dpidStr = sw.getDpid().toString();
2046 if (dpid.equals(dpidStr)) {
Sangho Shineb083032014-09-22 16:11:34 -07002047 mplsLabel = sw.getStringAttribute("nodeSid");
2048 break;
Sangho Shin1aa93542014-09-22 09:49:44 -07002049 }
2050 }
2051
Sangho Shineb083032014-09-22 16:11:34 -07002052 return mplsLabel;
Sangho Shin1aa93542014-09-22 09:49:44 -07002053 }
2054
Sangho Shineb083032014-09-22 16:11:34 -07002055 /**
Sangho Shin1aa93542014-09-22 09:49:44 -07002056 * The function checks if given IP matches to the given subnet mask
Sangho Shinfbc572c2014-10-02 16:37:05 -07002057 *
Sangho Shin1aa93542014-09-22 09:49:44 -07002058 * @param addr - subnet address to match
2059 * @param addr1 - IP address to check
2060 * @return true if the IP address matches to the subnet, otherwise false
2061 */
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002062 public boolean netMatch(String addr, String addr1) { // addr is subnet
2063 // address and addr1 is
2064 // ip address. Function
2065 // will return true, if
2066 // addr1 is within
2067 // addr(subnet)
Sangho Shin1aa93542014-09-22 09:49:44 -07002068
2069 String[] parts = addr.split("/");
2070 String ip = parts[0];
2071 int prefix;
2072
2073 if (parts.length < 2) {
2074 prefix = 0;
2075 } else {
2076 prefix = Integer.parseInt(parts[1]);
2077 }
2078
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002079 Inet4Address a = null;
2080 Inet4Address a1 = null;
Sangho Shin1aa93542014-09-22 09:49:44 -07002081 try {
2082 a = (Inet4Address) InetAddress.getByName(ip);
2083 a1 = (Inet4Address) InetAddress.getByName(addr1);
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002084 } catch (UnknownHostException e) {
2085 }
Sangho Shin1aa93542014-09-22 09:49:44 -07002086
2087 byte[] b = a.getAddress();
2088 int ipInt = ((b[0] & 0xFF) << 24) |
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002089 ((b[1] & 0xFF) << 16) |
2090 ((b[2] & 0xFF) << 8) |
2091 ((b[3] & 0xFF) << 0);
Sangho Shin1aa93542014-09-22 09:49:44 -07002092
2093 byte[] b1 = a1.getAddress();
2094 int ipInt1 = ((b1[0] & 0xFF) << 24) |
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002095 ((b1[1] & 0xFF) << 16) |
2096 ((b1[2] & 0xFF) << 8) |
2097 ((b1[3] & 0xFF) << 0);
Sangho Shin1aa93542014-09-22 09:49:44 -07002098
2099 int mask = ~((1 << (32 - prefix)) - 1);
2100
2101 if ((ipInt & mask) == (ipInt1 & mask)) {
2102 return true;
2103 }
2104 else {
2105 return false;
2106 }
2107 }
Sangho Shineb083032014-09-22 16:11:34 -07002108
Sangho Shinac5ee2b2014-09-28 21:27:20 -07002109 /**
2110 * Add a routing rule for the host
Sangho Shinfbc572c2014-10-02 16:37:05 -07002111 *
Sangho Shinac5ee2b2014-09-28 21:27:20 -07002112 * @param sw - Switch to add the rule
2113 * @param hostIpAddress Destination host IP address
2114 * @param hostMacAddress Destination host MAC address
2115 */
Sangho Shineb083032014-09-22 16:11:34 -07002116 public void addRouteToHost(Switch sw, int hostIpAddress, byte[] hostMacAddress) {
2117 ipHandler.addRouteToHost(sw, hostIpAddress, hostMacAddress);
Sangho Shineb083032014-09-22 16:11:34 -07002118 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -07002119
Sangho Shin463bee52014-09-29 15:14:43 -07002120 /**
2121 * Add IP packet to a buffer queue
Sangho Shinfbc572c2014-10-02 16:37:05 -07002122 *
Sangho Shin463bee52014-09-29 15:14:43 -07002123 * @param ipv4
2124 */
Sangho Shin7330c032014-10-20 10:34:51 -07002125 public void addPacketToPacketBuffer(IPv4 ipv4) {
Sangho Shin61535402014-10-01 11:37:14 -07002126 ipPacketQueue.add(ipv4);
Sangho Shin463bee52014-09-29 15:14:43 -07002127 }
2128
2129 /**
2130 * Retrieve all packets whose destination is the given address.
Sangho Shinfbc572c2014-10-02 16:37:05 -07002131 *
Sangho Shin463bee52014-09-29 15:14:43 -07002132 * @param destIp Destination address of packets to retrieve
2133 */
2134 public List<IPv4> getIpPacketFromQueue(byte[] destIp) {
2135
2136 List<IPv4> bufferedPackets = new ArrayList<IPv4>();
2137
Sangho Shin61535402014-10-01 11:37:14 -07002138 if (!ipPacketQueue.isEmpty()) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002139 for (IPv4 ip : ipPacketQueue) {
Sangho Shin61535402014-10-01 11:37:14 -07002140 int dest = ip.getDestinationAddress();
2141 IPv4Address ip1 = IPv4Address.of(dest);
2142 IPv4Address ip2 = IPv4Address.of(destIp);
2143 if (ip1.equals(ip2)) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002144 bufferedPackets.add((IPv4) (ipPacketQueue.poll()).clone());
Sangho Shin463bee52014-09-29 15:14:43 -07002145 }
2146 }
2147 }
2148
2149 return bufferedPackets;
2150 }
2151
Sangho Shin7330c032014-10-20 10:34:51 -07002152 /**
2153 * Get MAC address to known hosts
2154 *
2155 * @param destinationAddress IP address to get MAC address
2156 * @return MAC Address to given IP address
2157 */
2158 public byte[] getMacAddressFromIpAddress(int destinationAddress) {
2159
2160 // Can't we get the host IP address from the TopologyService ??
2161
2162 Iterator<ArpEntry> iterator = arpEntries.iterator();
2163
2164 IPv4Address ipAddress = IPv4Address.of(destinationAddress);
2165 byte[] ipAddressInByte = ipAddress.getBytes();
2166
2167 while (iterator.hasNext()) {
2168 ArpEntry arpEntry = iterator.next();
2169 byte[] address = arpEntry.targetIpAddress;
2170
2171 IPv4Address a = IPv4Address.of(address);
2172 IPv4Address b = IPv4Address.of(ipAddressInByte);
2173
2174 if (a.equals(b)) {
2175 log.debug("Found an arp entry");
2176 return arpEntry.targetMacAddress;
2177 }
2178 }
2179
2180 return null;
2181 }
2182
2183 /**
2184 * Send an ARP request via ArpHandler
2185 *
2186 * @param destinationAddress
2187 * @param sw
2188 * @param inPort
2189 *
2190 */
2191 public void sendArpRequest(Switch sw, int destinationAddress, Port inPort) {
2192 arpHandler.sendArpRequest(sw, destinationAddress, inPort);
2193 }
2194
Sangho Shin7330c032014-10-20 10:34:51 -07002195 // ************************************
2196 // Test functions
2197 // ************************************
2198
Sangho Shin55d00e12014-10-20 12:13:07 -07002199 private void runTest() {
2200
2201 if (testMode == POLICY_ADD1) {
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07002202 Integer[] routeArray = {101, 105, 110};
2203 /*List<Dpid> routeList = new ArrayList<Dpid>();
Sangho Shin55d00e12014-10-20 12:13:07 -07002204 for (int i = 0; i < routeArray.length; i++) {
2205 Dpid dpid = getSwitchFromNodeId(routeArray[i]).getDpid();
2206 routeList.add(dpid);
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07002207 }*/
Sangho Shin55d00e12014-10-20 12:13:07 -07002208
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07002209 if (createTunnel("1", Arrays.asList(routeArray))) {
Sangho Shin55d00e12014-10-20 12:13:07 -07002210 IPv4Net srcIp = new IPv4Net("10.0.1.1/24");
2211 IPv4Net dstIp = new IPv4Net("10.1.2.1/24");
2212
2213 log.debug("Set the policy 1");
Sangho Shine020cc32014-10-20 13:28:02 -07002214 this.createPolicy("1", null, null, Ethernet.TYPE_IPV4, srcIp,
Sangho Shin55d00e12014-10-20 12:13:07 -07002215 dstIp, IPv4.PROTOCOL_ICMP, (short)-1, (short)-1, 10000,
Sangho Shine020cc32014-10-20 13:28:02 -07002216 "1");
Sangho Shin55d00e12014-10-20 12:13:07 -07002217 testMode = POLICY_ADD2;
Sangho Shin4b46bcd2014-10-20 15:48:47 -07002218 testTask.reschedule(5, TimeUnit.SECONDS);
Sangho Shin55d00e12014-10-20 12:13:07 -07002219 }
2220 else {
2221 // retry it
2222 testTask.reschedule(5, TimeUnit.SECONDS);
2223 }
2224 }
2225 else if (testMode == POLICY_ADD2) {
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07002226 Integer[] routeArray = {101, 102, 103, 104, 105, 108, 110};
Sangho Shin55d00e12014-10-20 12:13:07 -07002227
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07002228 if (createTunnel("2", Arrays.asList(routeArray))) {
Sangho Shin55d00e12014-10-20 12:13:07 -07002229 IPv4Net srcIp = new IPv4Net("10.0.1.1/24");
2230 IPv4Net dstIp = new IPv4Net("10.1.2.1/24");
2231
2232 log.debug("Set the policy 2");
Sangho Shine020cc32014-10-20 13:28:02 -07002233 this.createPolicy("2", null, null, Ethernet.TYPE_IPV4, srcIp,
Sangho Shin55d00e12014-10-20 12:13:07 -07002234 dstIp, IPv4.PROTOCOL_ICMP, (short)-1, (short)-1, 20000,
Sangho Shine020cc32014-10-20 13:28:02 -07002235 "2");
Fahad Naeem Khan95aa4012014-10-21 14:07:00 -07002236 //testMode = POLICY_REMOVE2;
2237 //testTask.reschedule(5, TimeUnit.SECONDS);
Sangho Shin55d00e12014-10-20 12:13:07 -07002238 }
2239 else {
2240 log.debug("Retry it");
2241 testTask.reschedule(5, TimeUnit.SECONDS);
2242 }
2243 }
2244 else if (testMode == POLICY_REMOVE2){
2245 log.debug("Remove the policy 2");
Sangho Shine020cc32014-10-20 13:28:02 -07002246 this.removePolicy("2");
Sangho Shin55d00e12014-10-20 12:13:07 -07002247 testMode = POLICY_REMOVE1;
Sangho Shin4b46bcd2014-10-20 15:48:47 -07002248 testTask.reschedule(5, TimeUnit.SECONDS);
Sangho Shin55d00e12014-10-20 12:13:07 -07002249 }
2250 else if (testMode == POLICY_REMOVE1){
2251 log.debug("Remove the policy 1");
Sangho Shine020cc32014-10-20 13:28:02 -07002252 this.removePolicy("1");
Sangho Shin55d00e12014-10-20 12:13:07 -07002253
Sangho Shin4b46bcd2014-10-20 15:48:47 -07002254 testMode = TUNNEL_REMOVE1;
2255 testTask.reschedule(5, TimeUnit.SECONDS);
2256 }
2257 else if (testMode == TUNNEL_REMOVE1) {
2258 log.debug("Remove the tunnel 1");
2259 this.removeTunnel("1");
2260
2261 testMode = TUNNEL_REMOVE2;
2262 testTask.reschedule(5, TimeUnit.SECONDS);
2263 }
2264 else if (testMode == TUNNEL_REMOVE2) {
2265 log.debug("Remove the tunnel 2");
2266 this.removeTunnel("2");
2267 log.debug("The end of test");
2268 }
Sangho Shin55d00e12014-10-20 12:13:07 -07002269 }
Sangho Shin7330c032014-10-20 10:34:51 -07002270
2271 private void runTest1() {
2272
2273 String dpid1 = "00:00:00:00:00:00:00:01";
2274 String dpid2 = "00:00:00:00:00:00:00:0a";
2275 Switch srcSw = mutableTopology.getSwitch(new Dpid(dpid1));
2276 Switch dstSw = mutableTopology.getSwitch(new Dpid(dpid2));
2277
2278 if (srcSw == null || dstSw == null) {
2279 testTask.reschedule(1, TimeUnit.SECONDS);
2280 log.debug("Switch is gone. Reschedule the test");
2281 return;
2282 }
2283
2284 String[] routeArray = {"101", "102", "105", "108", "110"};
2285 List<String> routeList = new ArrayList<String>();
2286 for (int i = 0; i < routeArray.length; i++)
2287 routeList.add(routeArray[i]);
2288
2289 List<String> optimizedRoute = this.getOptimizedPath(srcSw, dstSw, routeList);
2290
2291 log.debug("Test set is {}", routeList.toString());
2292 log.debug("Result set is {}", optimizedRoute.toString());
2293
2294
2295 }
2296
2297 /**
2298 * print tunnel info - used only for debugging.
2299 * @param targetSw
2300 *
2301 * @param fwdSwDpids
2302 * @param ids
2303 * @param tunnelId
2304 */
Sangho Shin6471d202014-10-23 10:59:36 -07002305 private void printTunnelInfo(String targetSw, String tunnelId,
Sangho Shin7330c032014-10-20 10:34:51 -07002306 List<String> ids, NeighborSet ns) {
2307 StringBuilder logStr = new StringBuilder("In switch " +
Sangho Shin6471d202014-10-23 10:59:36 -07002308 targetSw + ", create a tunnel " + tunnelId + " " + " of push ");
Sangho Shin7330c032014-10-20 10:34:51 -07002309 for (String id: ids)
2310 logStr.append(id + "-");
2311 logStr.append(" output to ");
2312 for (Dpid dpid: ns.getDpids())
2313 logStr.append(dpid + " - ");
2314
2315 log.debug(logStr.toString());
2316
2317 }
2318
2319 /**
2320 * Debugging function to print out the Match Action Entry
2321 * @param sw13
2322 *
2323 * @param maEntry
2324 */
2325 private void printMatchActionOperationEntry(
2326 IOF13Switch sw13, MatchActionOperationEntry maEntry) {
2327
2328 StringBuilder logStr = new StringBuilder("In switch " + sw13.getId() + ", ");
2329
2330 MatchAction ma = maEntry.getTarget();
2331 Match m = ma.getMatch();
2332 List<Action> actions = ma.getActions();
2333
2334 if (m instanceof Ipv4Match) {
2335 logStr.append("If the IP matches with ");
2336 IPv4Net ip = ((Ipv4Match) m).getDestination();
2337 logStr.append(ip.toString());
2338 logStr.append(" then ");
2339 }
2340 else if (m instanceof MplsMatch) {
2341 logStr.append("If the MPLS label matches with ");
2342 int mplsLabel = ((MplsMatch) m).getMplsLabel();
2343 logStr.append(mplsLabel);
2344 logStr.append(" then ");
2345 }
2346 else if (m instanceof PacketMatch) {
2347 GroupAction ga = (GroupAction)actions.get(0);
2348 logStr.append("if the policy match is XXX then go to group " +
2349 ga.getGroupId());
2350 log.debug(logStr.toString());
2351 return;
2352 }
2353
2354 logStr.append(" do { ");
2355 for (Action action : actions) {
2356 if (action instanceof CopyTtlInAction) {
2357 logStr.append("copy ttl In, ");
2358 }
2359 else if (action instanceof CopyTtlOutAction) {
2360 logStr.append("copy ttl Out, ");
2361 }
2362 else if (action instanceof DecMplsTtlAction) {
2363 logStr.append("Dec MPLS TTL , ");
2364 }
2365 else if (action instanceof GroupAction) {
2366 logStr.append("Forward packet to < ");
2367 NeighborSet dpids = ((GroupAction) action).getDpids();
2368 logStr.append(dpids.toString() + ",");
2369
2370 }
2371 else if (action instanceof PopMplsAction) {
2372 logStr.append("Pop MPLS label, ");
2373 }
2374 else if (action instanceof PushMplsAction) {
2375 logStr.append("Push MPLS label, ");
2376 }
2377 else if (action instanceof SetMplsIdAction) {
2378 int id = ((SetMplsIdAction) action).getMplsId();
2379 logStr.append("Set MPLS ID as " + id + ", ");
2380 }
2381 }
2382
2383 log.debug(logStr.toString());
2384
2385 }
2386
Sangho Shin7330c032014-10-20 10:34:51 -07002387 // ************************************
2388 // Unused classes and functions
2389 // ************************************
2390
2391 /**
2392 * Temporary class to to keep ARP entry
2393 *
2394 */
2395 private class ArpEntry {
2396
2397 byte[] targetMacAddress;
2398 byte[] targetIpAddress;
2399
2400 private ArpEntry(byte[] macAddress, byte[] ipAddress) {
2401 this.targetMacAddress = macAddress;
2402 this.targetIpAddress = ipAddress;
2403 }
2404 }
2405
2406 /**
2407 * This class is used only for link recovery optimization in
2408 * modifyEcmpRoutingRules() function.
2409 * TODO: please remove if the optimization is not used at all
2410 */
2411 private class SwitchPair {
2412 private Switch src;
2413 private Switch dst;
2414
2415 public SwitchPair(Switch src, Switch dst) {
2416 this.src = src;
2417 this.dst = dst;
2418 }
2419
2420 public Switch getSource() {
2421 return src;
2422 }
2423
2424 public Switch getDestination() {
2425 return dst;
2426 }
2427 }
2428
2429 /**
2430 * Update ARP Cache using ARP packets It is used to set destination MAC
2431 * address to forward packets to known hosts. But, it will be replace with
2432 * Host information of Topology service later.
2433 *
2434 * @param arp APR packets to use for updating ARP entries
2435 */
2436 public void updateArpCache(ARP arp) {
2437
2438 ArpEntry arpEntry = new ArpEntry(arp.getSenderHardwareAddress(),
2439 arp.getSenderProtocolAddress());
2440 // TODO: Need to check the duplication
2441 arpEntries.add(arpEntry);
2442 }
2443
2444 /**
2445 * Modify the routing rules for the lost links
2446 * - Recompute the path if the link failed is included in the path
2447 * (including src and dest).
2448 *
2449 * @param newLink
2450 */
2451 private void modifyEcmpRoutingRules(LinkData linkRemoved) {
2452
2453 //HashMap<Switch, SwitchPair> linksToRecompute = new HashMap<Switch, SwitchPair>();
2454 Set<SwitchPair> linksToRecompute = new HashSet<SwitchPair>();
2455
2456 for (ECMPShortestPathGraph ecmpSPG : graphs.values()) {
2457 Switch rootSw = ecmpSPG.getRootSwitch();
2458 HashMap<Integer, HashMap<Switch, ArrayList<Path>>> paths =
2459 ecmpSPG.getCompleteLearnedSwitchesAndPaths();
2460 for (HashMap<Switch, ArrayList<Path>> p: paths.values()) {
2461 for (Switch destSw: p.keySet()) {
2462 ArrayList<Path> path = p.get(destSw);
2463 if (checkPath(path, linkRemoved)) {
2464 boolean found = false;
2465 for (SwitchPair pair: linksToRecompute) {
2466 if (pair.getSource().getDpid() == rootSw.getDpid() &&
2467 pair.getSource().getDpid() == destSw.getDpid()) {
2468 found = true;
2469 }
2470 }
2471 if (!found) {
2472 linksToRecompute.add(new SwitchPair(rootSw, destSw));
2473 }
2474 }
2475 }
2476 }
2477 }
2478
2479 // Recompute the path for the specific route
2480 for (SwitchPair pair: linksToRecompute) {
2481
2482 log.debug("Recompute path from {} to {}", pair.getSource(), pair.getDestination());
2483 // We need the following function for optimization
2484 //ECMPShortestPathGraph ecmpSPG =
2485 // new ECMPShortestPathGraph(pair.getSource(), pair.getDestination());
2486 ECMPShortestPathGraph ecmpSPG =
2487 new ECMPShortestPathGraph(pair.getSource());
2488 populateEcmpRoutingRulesForPath(pair.getSource(), ecmpSPG, true);
2489 }
2490 }
2491
2492 /**
2493 * Optimize the mpls label
2494 * The feature will be used only for policy of "avoid a specific switch".
2495 * Check route to each router in route backward.
2496 * If there is only one route to the router and the routers are included in
2497 * the route, remove the id from the path.
2498 * A-B-C-D-E => A-B-C-D-E -> A-E
2499 * | | => A-B-H-I -> A-I
Sangho Shin5b8f5452014-10-20 11:46:01 -07002500 * F-G-H-I => A-D-I > A-D-I
Sangho Shin7330c032014-10-20 10:34:51 -07002501 */
2502 private List<String> getOptimizedPath(Switch srcSw, Switch dstSw, List<String> route) {
2503
2504 List<String> optimizedPath = new ArrayList<String>();
2505 optimizedPath.addAll(route);
2506 ECMPShortestPathGraph ecmpSPG = new ECMPShortestPathGraph(srcSw);
2507
2508 HashMap<Integer, HashMap<Switch, ArrayList<Path>>> paths =
2509 ecmpSPG.getCompleteLearnedSwitchesAndPaths();
2510 for (HashMap<Switch, ArrayList<Path>> p: paths.values()) {
2511 for (Switch s: p.keySet()) {
2512 if (s.getDpid().toString().equals(dstSw.getDpid().toString())) {
2513 ArrayList<Path> ecmpPaths = p.get(s);
2514 if (ecmpPaths!= null && ecmpPaths.size() == 1) {
2515 for (Path path: ecmpPaths) {
2516 for (LinkData link: path) {
2517 String srcId = getMplsLabel(link.getSrc().getDpid().toString());
2518 String dstId = getMplsLabel(link.getSrc().getDpid().toString());
2519 if (optimizedPath.contains(srcId)) {
2520 optimizedPath.remove(srcId);
2521 }
2522 if (optimizedPath.contains(dstId)) {
2523 optimizedPath.remove(dstId);
2524 }
2525 }
2526 }
2527 }
2528 }
2529 }
2530 }
2531
2532 return optimizedPath;
2533
2534 }
2535
2536 /**
2537 * Check if the path is affected from the link removed
2538 *
2539 * @param path Path to check
2540 * @param linkRemoved link removed
2541 * @return true if the path contains the link removed
2542 */
2543 private boolean checkPath(ArrayList<Path> path, LinkData linkRemoved) {
2544
2545 for (Path ppp: path) {
2546 // TODO: need to check if this is a bidirectional or
2547 // unidirectional
2548 for (LinkData link: ppp) {
2549 if (link.getDst().getDpid().equals(linkRemoved.getDst().getDpid()) &&
2550 link.getSrc().getDpid().equals(linkRemoved.getSrc().getDpid()))
2551 return true;
2552 }
2553 }
2554
2555 return false;
2556 }
Sangho Shin15273b62014-10-16 22:22:05 -07002557
2558
Sangho Shin2f263692014-09-15 14:09:41 -07002559}