blob: 2d90495b143bed39dbdcc4189f4d1fc3c34fa5e4 [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;
Srikanth Vavilapalli8a661e72014-10-27 15:40:22 -070037import net.onrc.onos.core.drivermanager.OFSwitchImplDellOSR;
Sangho Shin2f263692014-09-15 14:09:41 -070038import net.onrc.onos.core.flowprogrammer.IFlowPusherService;
Sangho Shinfbc572c2014-10-02 16:37:05 -070039import net.onrc.onos.core.intent.Path;
Sangho Shin2f263692014-09-15 14:09:41 -070040import net.onrc.onos.core.main.config.IConfigInfoService;
Sangho Shin43cee112014-09-25 16:43:34 -070041import net.onrc.onos.core.matchaction.MatchAction;
42import net.onrc.onos.core.matchaction.MatchActionId;
43import net.onrc.onos.core.matchaction.MatchActionOperationEntry;
Sangho Shin5be3e532014-10-03 17:20:58 -070044import net.onrc.onos.core.matchaction.MatchActionOperations.Operator;
Sangho Shin43cee112014-09-25 16:43:34 -070045import net.onrc.onos.core.matchaction.action.Action;
46import net.onrc.onos.core.matchaction.action.CopyTtlInAction;
47import net.onrc.onos.core.matchaction.action.CopyTtlOutAction;
48import net.onrc.onos.core.matchaction.action.DecMplsTtlAction;
49import net.onrc.onos.core.matchaction.action.DecNwTtlAction;
50import net.onrc.onos.core.matchaction.action.GroupAction;
Sangho Shin6d3c2f02014-10-22 10:10:55 -070051import net.onrc.onos.core.matchaction.action.ModifyDstMacAction;
52import net.onrc.onos.core.matchaction.action.ModifySrcMacAction;
53import net.onrc.onos.core.matchaction.action.OutputAction;
Sangho Shin43cee112014-09-25 16:43:34 -070054import net.onrc.onos.core.matchaction.action.PopMplsAction;
55import net.onrc.onos.core.matchaction.action.PushMplsAction;
Sangho Shine842cad2014-10-24 16:07:35 -070056import net.onrc.onos.core.matchaction.action.SetDAAction;
Sangho Shin43cee112014-09-25 16:43:34 -070057import net.onrc.onos.core.matchaction.action.SetMplsIdAction;
Sangho Shine842cad2014-10-24 16:07:35 -070058import net.onrc.onos.core.matchaction.action.SetSAAction;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -070059import net.onrc.onos.core.matchaction.match.Ipv4Match;
Sangho Shin43cee112014-09-25 16:43:34 -070060import net.onrc.onos.core.matchaction.match.Match;
61import net.onrc.onos.core.matchaction.match.MplsMatch;
Sangho Shin15273b62014-10-16 22:22:05 -070062import net.onrc.onos.core.matchaction.match.PacketMatch;
63import net.onrc.onos.core.matchaction.match.PacketMatchBuilder;
Sangho Shin2f263692014-09-15 14:09:41 -070064import net.onrc.onos.core.packet.ARP;
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070065import net.onrc.onos.core.packet.Ethernet;
66import net.onrc.onos.core.packet.IPv4;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070067import net.onrc.onos.core.topology.ITopologyListener;
Sangho Shin1aa93542014-09-22 09:49:44 -070068import net.onrc.onos.core.topology.ITopologyService;
Sangho Shinbce900e2014-10-07 17:13:23 -070069import net.onrc.onos.core.topology.Link;
Sangho Shinc8d2f592014-09-30 16:53:57 -070070import net.onrc.onos.core.topology.LinkData;
Sangho Shinbce900e2014-10-07 17:13:23 -070071import net.onrc.onos.core.topology.MastershipData;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070072import net.onrc.onos.core.topology.MutableTopology;
Sangho Shineb083032014-09-22 16:11:34 -070073import net.onrc.onos.core.topology.Port;
Sangho Shinc8d2f592014-09-30 16:53:57 -070074import net.onrc.onos.core.topology.PortData;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070075import net.onrc.onos.core.topology.Switch;
Sangho Shin5be3e532014-10-03 17:20:58 -070076import net.onrc.onos.core.topology.SwitchData;
Sangho Shin1aa93542014-09-22 09:49:44 -070077import net.onrc.onos.core.topology.TopologyEvents;
Srikanth Vavilapalli363f1dc2014-09-22 14:30:23 -070078import net.onrc.onos.core.util.Dpid;
Sangho Shin43cee112014-09-25 16:43:34 -070079import net.onrc.onos.core.util.IPv4Net;
Sangho Shin6d3c2f02014-10-22 10:10:55 -070080import net.onrc.onos.core.util.PortNumber;
Sangho Shin43cee112014-09-25 16:43:34 -070081import net.onrc.onos.core.util.SwitchPort;
Sangho Shin2f263692014-09-15 14:09:41 -070082
Sangho Shin43cee112014-09-25 16:43:34 -070083import org.json.JSONArray;
84import org.json.JSONException;
Saurav Dasa962a692014-10-17 14:52:38 -070085import org.projectfloodlight.openflow.protocol.OFBarrierReply;
Saurav Dasbc594a42014-09-25 20:13:50 -070086import org.projectfloodlight.openflow.types.EthType;
Sangho Shin2f263692014-09-15 14:09:41 -070087import org.projectfloodlight.openflow.types.IPv4Address;
Sangho Shine842cad2014-10-24 16:07:35 -070088import org.projectfloodlight.openflow.types.MacAddress;
Sangho Shin2f263692014-09-15 14:09:41 -070089import org.slf4j.Logger;
90import org.slf4j.LoggerFactory;
91
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070092public class SegmentRoutingManager implements IFloodlightModule,
Srikanth Vavilapalli8c49db72014-10-20 13:35:08 -070093 ITopologyListener, IPacketListener, ISegmentRoutingService {
Sangho Shin2f263692014-09-15 14:09:41 -070094
95 private static final Logger log = LoggerFactory
96 .getLogger(SegmentRoutingManager.class);
Sangho Shin23f898d2014-10-13 16:54:00 -070097
Fahad Naeem Khan5b558f22014-10-16 10:35:20 -070098 private ITopologyService topologyService;
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070099 private IPacketService packetService;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700100 private MutableTopology mutableTopology;
Sangho Shin61535402014-10-01 11:37:14 -0700101 private ConcurrentLinkedQueue<IPv4> ipPacketQueue;
Fahad Naeem Khan4444b952014-10-18 22:30:50 -0700102 private IRestApiService restApi;
Sangho Shin2f263692014-09-15 14:09:41 -0700103 private List<ArpEntry> arpEntries;
Sangho Shineb083032014-09-22 16:11:34 -0700104 private ArpHandler arpHandler;
105 private GenericIpHandler ipHandler;
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700106 private IcmpHandler icmpHandler;
Sangho Shin43cee112014-09-25 16:43:34 -0700107 private IThreadPoolService threadPool;
108 private SingletonTask discoveryTask;
Sangho Shin23f898d2014-10-13 16:54:00 -0700109 private SingletonTask linkAddTask;
Sangho Shin15273b62014-10-16 22:22:05 -0700110 private SingletonTask testTask;
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700111 private IFloodlightProviderService floodlightProvider;
Sangho Shin2f263692014-09-15 14:09:41 -0700112
Sangho Shinfbc572c2014-10-02 16:37:05 -0700113 private HashMap<Switch, ECMPShortestPathGraph> graphs;
Sangho Shin23f898d2014-10-13 16:54:00 -0700114 private HashMap<String, LinkData> linksDown;
115 private HashMap<String, LinkData> linksToAdd;
Sangho Shin5be3e532014-10-03 17:20:58 -0700116 private ConcurrentLinkedQueue<TopologyEvents> topologyEventQueue;
Sangho Shine020cc32014-10-20 13:28:02 -0700117 private HashMap<String, PolicyInfo> policyTable;
Sangho Shin81655442014-10-20 14:22:46 -0700118 private HashMap<String, TunnelInfo> tunnelTable;
Sangho Shin6471d202014-10-23 10:59:36 -0700119 private HashMap<Integer, HashMap<Integer, List<Integer>>> adjacencySidTable;
Sangho Shin5b8f5452014-10-20 11:46:01 -0700120
Sangho Shine842cad2014-10-24 16:07:35 -0700121 // Flag whether transit router supports ECMP or not
Srikanth Vavilapalli8a661e72014-10-27 15:40:22 -0700122 // private boolean supportTransitECMP = true;
Sangho Shin5b8f5452014-10-20 11:46:01 -0700123
Sangho Shine842cad2014-10-24 16:07:35 -0700124 private int testMode = 0;
Sangho Shinbce900e2014-10-07 17:13:23 -0700125
126 private int numOfEvents = 0;
127 private int numOfEventProcess = 0;
128 private int numOfPopulation = 0;
Sangho Shin99918bd2014-10-08 15:52:35 -0700129 private long matchActionId = 0L;
Sangho Shin58182672014-10-21 13:23:38 -0700130
Sangho Shin23f898d2014-10-13 16:54:00 -0700131 private final int DELAY_TO_ADD_LINK = 10;
Sangho Shin15273b62014-10-16 22:22:05 -0700132 private final int MAX_NUM_LABELS = 3;
Sangho Shinfbc572c2014-10-02 16:37:05 -0700133
Sangho Shin5b8f5452014-10-20 11:46:01 -0700134 private final int POLICY_ADD1 = 1;
135 private final int POLICY_ADD2 = 2;
136 private final int POLICY_REMOVE1 = 3;
137 private final int POLICY_REMOVE2 = 4;
Sangho Shin4b46bcd2014-10-20 15:48:47 -0700138 private final int TUNNEL_REMOVE1 = 5;
139 private final int TUNNEL_REMOVE2 = 6;
Sangho Shin5b8f5452014-10-20 11:46:01 -0700140
141
Sangho Shin7330c032014-10-20 10:34:51 -0700142 // ************************************
143 // IFloodlightModule implementation
144 // ************************************
145
Sangho Shin2f263692014-09-15 14:09:41 -0700146 @Override
147 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Srikanth Vavilapalli8c49db72014-10-20 13:35:08 -0700148 Collection<Class<? extends IFloodlightService>> l = new ArrayList<>();
149 l.add(ISegmentRoutingService.class);
150 return l;
Sangho Shin2f263692014-09-15 14:09:41 -0700151 }
152
153 @Override
154 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Srikanth Vavilapalli8c49db72014-10-20 13:35:08 -0700155 Map<Class<? extends IFloodlightService>, IFloodlightService> m = new HashMap<>();
156 m.put(ISegmentRoutingService.class, this);
157 return m;
Sangho Shin2f263692014-09-15 14:09:41 -0700158 }
159
160 @Override
161 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
162 Collection<Class<? extends IFloodlightService>> l = new ArrayList<Class<? extends IFloodlightService>>();
163
164 l.add(IFloodlightProviderService.class);
165 l.add(IConfigInfoService.class);
166 l.add(ITopologyService.class);
167 l.add(IPacketService.class);
168 l.add(IFlowPusherService.class);
169 l.add(ITopologyService.class);
Fahad Naeem Khan4444b952014-10-18 22:30:50 -0700170 l.add(IRestApiService.class);
Sangho Shin2f263692014-09-15 14:09:41 -0700171
172 return l;
173
174 }
175
176 @Override
177 public void init(FloodlightModuleContext context) throws FloodlightModuleException {
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700178 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Sangho Shineb083032014-09-22 16:11:34 -0700179 arpHandler = new ArpHandler(context, this);
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700180 icmpHandler = new IcmpHandler(context, this);
Sangho Shineb083032014-09-22 16:11:34 -0700181 ipHandler = new GenericIpHandler(context, this);
Sangho Shin2f263692014-09-15 14:09:41 -0700182 arpEntries = new ArrayList<ArpEntry>();
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700183 topologyService = context.getServiceImpl(ITopologyService.class);
Sangho Shin43cee112014-09-25 16:43:34 -0700184 threadPool = context.getServiceImpl(IThreadPoolService.class);
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700185 mutableTopology = topologyService.getTopology();
Sangho Shin61535402014-10-01 11:37:14 -0700186 ipPacketQueue = new ConcurrentLinkedQueue<IPv4>();
Sangho Shinfbc572c2014-10-02 16:37:05 -0700187 graphs = new HashMap<Switch, ECMPShortestPathGraph>();
Sangho Shin23f898d2014-10-13 16:54:00 -0700188 linksDown = new HashMap<String, LinkData>();
189 linksToAdd = new HashMap<String, LinkData>();
Sangho Shin5be3e532014-10-03 17:20:58 -0700190 topologyEventQueue = new ConcurrentLinkedQueue<TopologyEvents>();
Sangho Shin15273b62014-10-16 22:22:05 -0700191 packetService = context.getServiceImpl(IPacketService.class);
Fahad Naeem Khan4444b952014-10-18 22:30:50 -0700192 restApi = context.getServiceImpl(IRestApiService.class);
Sangho Shine020cc32014-10-20 13:28:02 -0700193 policyTable = new HashMap<String, PolicyInfo>();
Sangho Shin81655442014-10-20 14:22:46 -0700194 tunnelTable = new HashMap<String, TunnelInfo>();
Sangho Shin6471d202014-10-23 10:59:36 -0700195 adjacencySidTable = new HashMap<Integer,HashMap<Integer, List<Integer>>>();
Sangho Shin2f263692014-09-15 14:09:41 -0700196
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700197 packetService.registerPacketListener(this);
Sangho Shin15273b62014-10-16 22:22:05 -0700198 topologyService.addListener(this, false);
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700199
Sangho Shin99918bd2014-10-08 15:52:35 -0700200
Sangho Shin2f263692014-09-15 14:09:41 -0700201 }
202
203 @Override
204 public void startUp(FloodlightModuleContext context) throws FloodlightModuleException {
Sangho Shinc8d2f592014-09-30 16:53:57 -0700205 ScheduledExecutorService ses = threadPool.getScheduledExecutor();
Fahad Naeem Khan4444b952014-10-18 22:30:50 -0700206 restApi.addRestletRoutable(new SegmentRoutingWebRoutable());
Sangho Shin2f263692014-09-15 14:09:41 -0700207
Sangho Shinc8d2f592014-09-30 16:53:57 -0700208 discoveryTask = new SingletonTask(ses, new Runnable() {
209 @Override
210 public void run() {
Sangho Shin5be3e532014-10-03 17:20:58 -0700211 handleTopologyChangeEvents();
Sangho Shinc8d2f592014-09-30 16:53:57 -0700212 }
213 });
Sangho Shin23f898d2014-10-13 16:54:00 -0700214
215 linkAddTask = new SingletonTask(ses, new Runnable() {
216 @Override
217 public void run() {
218 delayedAddLink();
219 }
220 });
221
Sangho Shin15273b62014-10-16 22:22:05 -0700222 testTask = new SingletonTask(ses, new Runnable() {
223 @Override
224 public void run() {
225 runTest();
226 }
227 });
228
Sangho Shin5b8f5452014-10-20 11:46:01 -0700229 testMode = POLICY_ADD1;
Sangho Shin69229fb2014-10-27 16:17:04 -0700230 //testTask.reschedule(20, TimeUnit.SECONDS);
Sangho Shin2f263692014-09-15 14:09:41 -0700231 }
232
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700233 @Override
234 public void receive(Switch sw, Port inPort, Ethernet payload) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700235 if (payload.getEtherType() == Ethernet.TYPE_ARP)
236 arpHandler.processPacketIn(sw, inPort, payload);
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700237 if (payload.getEtherType() == Ethernet.TYPE_IPV4) {
Sangho Shin7330c032014-10-20 10:34:51 -0700238 addPacketToPacketBuffer((IPv4) payload.getPayload());
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700239 if (((IPv4) payload.getPayload()).getProtocol() == IPv4.PROTOCOL_ICMP)
240 icmpHandler.processPacketIn(sw, inPort, payload);
241 else
242 ipHandler.processPacketIn(sw, inPort, payload);
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700243 }
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700244 else {
245 log.debug("{}", payload.toString());
246 }
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700247 }
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700248
Sangho Shin2f263692014-09-15 14:09:41 -0700249
Sangho Shin7330c032014-10-20 10:34:51 -0700250 // ************************************
251 // Topology event handlers
252 // ************************************
Sangho Shineb083032014-09-22 16:11:34 -0700253
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700254 /**
255 * Topology events that have been generated.
Sangho Shinfbc572c2014-10-02 16:37:05 -0700256 *
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700257 * @param topologyEvents the generated Topology Events
258 * @see TopologyEvents
259 */
260 public void topologyEvents(TopologyEvents topologyEvents)
261 {
Sangho Shin5be3e532014-10-03 17:20:58 -0700262 topologyEventQueue.add(topologyEvents);
Sangho Shinbce900e2014-10-07 17:13:23 -0700263 discoveryTask.reschedule(100, TimeUnit.MILLISECONDS);
Sangho Shin5be3e532014-10-03 17:20:58 -0700264 }
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700265
Sangho Shin23f898d2014-10-13 16:54:00 -0700266 /**
267 * Process the multiple topology events with some delay (100MS at most for now)
268 *
269 */
Sangho Shin5be3e532014-10-03 17:20:58 -0700270 private void handleTopologyChangeEvents() {
Sangho Shinbce900e2014-10-07 17:13:23 -0700271 numOfEventProcess ++;
272
Sangho Shin51625342014-10-17 09:30:48 -0700273 Collection<LinkData> linkEntriesAddedAll = new ArrayList<LinkData>();
274 Collection<PortData> portEntriesAddedAll = new ArrayList<PortData>();
275 Collection<PortData> portEntriesRemovedAll = new ArrayList<PortData>();
276 Collection<LinkData> linkEntriesRemovedAll = new ArrayList<LinkData>();
277 Collection<SwitchData> switchAddedAll = new ArrayList<SwitchData>();
278 Collection<SwitchData> switchRemovedAll = new ArrayList<SwitchData>();
279 Collection<MastershipData> mastershipRemovedAll = new ArrayList<MastershipData>();
Sangho Shinbce900e2014-10-07 17:13:23 -0700280
Sangho Shin5be3e532014-10-03 17:20:58 -0700281 while (!topologyEventQueue.isEmpty()) {
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700282 // We should handle the events in the order of when they happen
283 // TODO: We need to simulate the final results of multiple events
284 // and shoot only the final state.
285 // Ex: link s1-s2 down, link s1-s2 up --> Do nothing
286 // Ex: ink s1-s2 up, s1-p1,p2 down --> link s1-s2 down
Sangho Shin51625342014-10-17 09:30:48 -0700287
Sangho Shin5be3e532014-10-03 17:20:58 -0700288 TopologyEvents topologyEvents = topologyEventQueue.poll();
Sangho Shin51625342014-10-17 09:30:48 -0700289
290 Collection<LinkData> linkEntriesAdded = topologyEvents.getAddedLinkDataEntries();
291 Collection<PortData> portEntriesAdded = topologyEvents.getAddedPortDataEntries();
292 Collection<PortData> portEntriesRemoved = topologyEvents.getRemovedPortDataEntries();
293 Collection<LinkData> linkEntriesRemoved = topologyEvents.getRemovedLinkDataEntries();
294 Collection<SwitchData> switchAdded = topologyEvents.getAddedSwitchDataEntries();
295 Collection<SwitchData> switchRemoved = topologyEvents.getRemovedSwitchDataEntries();
296 Collection<MastershipData> mastershipRemoved = topologyEvents.getRemovedMastershipDataEntries();
297
298 linkEntriesAddedAll.addAll(linkEntriesAdded);
299 portEntriesAddedAll.addAll(portEntriesAdded);
300 portEntriesRemovedAll.addAll(portEntriesRemoved);
301 linkEntriesRemovedAll.addAll(linkEntriesRemoved);
302 switchAddedAll.addAll(switchAdded);
303 switchRemovedAll.addAll(switchRemoved);
304 mastershipRemovedAll.addAll(mastershipRemoved);
Sangho Shinbce900e2014-10-07 17:13:23 -0700305 numOfEvents++;
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700306
307 if (!portEntriesRemoved.isEmpty()) {
308 processPortRemoval(portEntriesRemoved);
309 }
310
311 if (!linkEntriesRemoved.isEmpty()) {
312 processLinkRemoval(linkEntriesRemoved);
313 }
314
315 if (!switchRemoved.isEmpty()) {
316 processSwitchRemoved(switchRemoved);
317 }
318
319 if (!mastershipRemoved.isEmpty()) {
Sangho Shin23f898d2014-10-13 16:54:00 -0700320 log.debug("Mastership is removed. Check if ports are down also.");
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700321 }
322
323 if (!linkEntriesAdded.isEmpty()) {
Sangho Shin23f898d2014-10-13 16:54:00 -0700324 processLinkAdd(linkEntriesAdded, false);
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700325 }
326
327 if (!portEntriesAdded.isEmpty()) {
328 processPortAdd(portEntriesAdded);
329 }
330
331 if (!switchAdded.isEmpty()) {
332 processSwitchAdd(switchAdded);
333 }
Sangho Shin51625342014-10-17 09:30:48 -0700334
Sangho Shinbce900e2014-10-07 17:13:23 -0700335 }
336
Sangho Shin23f898d2014-10-13 16:54:00 -0700337 // TODO: 100ms is enough to check both mastership removed events
338 // and the port removed events? What if the PORT_STATUS packets comes late?
Sangho Shin51625342014-10-17 09:30:48 -0700339 if (!mastershipRemovedAll.isEmpty()) {
340 if (portEntriesRemovedAll.isEmpty()) {
Saurav Das82e62972014-10-16 14:53:57 -0700341 log.debug("Just mastership is removed. Do not do anthing.");
Sangho Shin23f898d2014-10-13 16:54:00 -0700342 }
343 else {
344 HashMap<String, MastershipData> mastershipToRemove =
345 new HashMap<String, MastershipData>();
Sangho Shin51625342014-10-17 09:30:48 -0700346 for (MastershipData ms: mastershipRemovedAll) {
347 for (PortData port: portEntriesRemovedAll) {
Sangho Shin23f898d2014-10-13 16:54:00 -0700348 // TODO: check ALL ports of the switch are dead ..
349 if (port.getDpid().equals(ms.getDpid())) {
350 mastershipToRemove.put(ms.getDpid().toString(), ms);
351 }
352 }
353 log.debug("Swtich {} is really down.", ms.getDpid());
354 }
355 processMastershipRemoved(mastershipToRemove.values());
356 }
357 }
358
Sangho Shinbce900e2014-10-07 17:13:23 -0700359 log.debug("num events {}, num of process {}, "
360 + "num of Population {}", numOfEvents, numOfEventProcess,
361 numOfPopulation);
362 }
363
364 /**
Sangho Shin99918bd2014-10-08 15:52:35 -0700365 * Process the SwitchAdded events from topologyMananger.
366 * It does nothing. When a switch is added, then link will be added too.
367 * LinkAdded event will handle process all re-computation.
368 *
369 * @param switchAdded
370 */
371 private void processSwitchAdd(Collection<SwitchData> switchAdded) {
372
373 }
374
375 /**
Sangho Shinbce900e2014-10-07 17:13:23 -0700376 * Remove all ports connected to the switch removed
377 *
378 * @param mastershipRemoved master switch info removed
379 */
380 private void processMastershipRemoved(Collection<MastershipData>
381 mastershipRemoved) {
382 for (MastershipData mastership: mastershipRemoved) {
383 Switch sw = mutableTopology.getSwitch(mastership.getDpid());
384 for (Link link: sw.getOutgoingLinks()) {
385 Port dstPort = link.getDstPort();
386 IOF13Switch dstSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
387 getSwId(dstPort.getDpid().toString()));
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700388 if (dstSw != null) {
389 dstSw.removePortFromGroups(dstPort.getNumber());
390 log.debug("MasterSwitch {} is gone: remove port {}", sw.getDpid(), dstPort);
391 }
Sangho Shinbce900e2014-10-07 17:13:23 -0700392 }
Sangho Shin61535402014-10-01 11:37:14 -0700393 }
Sangho Shin23f898d2014-10-13 16:54:00 -0700394
395 linksToAdd.clear();
396 linksDown.clear();
Sangho Shin61535402014-10-01 11:37:14 -0700397 }
Sangho Shinc8d2f592014-09-30 16:53:57 -0700398
Sangho Shinbce900e2014-10-07 17:13:23 -0700399 /**
400 * Remove all ports connected to the switch removed
401 *
402 * @param switchRemoved Switch removed
403 */
Sangho Shin5be3e532014-10-03 17:20:58 -0700404 private void processSwitchRemoved(Collection<SwitchData> switchRemoved) {
Sangho Shin23f898d2014-10-13 16:54:00 -0700405 log.debug("SwitchRemoved event occurred !!!");
Sangho Shin5be3e532014-10-03 17:20:58 -0700406 }
407
Sangho Shin61535402014-10-01 11:37:14 -0700408 /**
Sangho Shin99918bd2014-10-08 15:52:35 -0700409 * Report ports added to driver
Sangho Shinfbc572c2014-10-02 16:37:05 -0700410 *
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700411 * @param portEntries
412 */
413 private void processPortAdd(Collection<PortData> portEntries) {
Sangho Shin99918bd2014-10-08 15:52:35 -0700414 // TODO: do we need to add ports with delay?
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700415 for (PortData port : portEntries) {
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700416 Dpid dpid = port.getDpid();
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700417
Sangho Shinfbc572c2014-10-02 16:37:05 -0700418 IOF13Switch sw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700419 getSwId(port.getDpid().toString()));
Sangho Shin815af0c2014-10-10 13:05:45 -0700420 if (sw != null) {
Sangho Shin721ca042014-10-09 13:03:40 -0700421 sw.addPortToGroups(port.getPortNumber());
Sangho Shin15273b62014-10-16 22:22:05 -0700422 //log.debug("Add port {} to switch {}", port, dpid);
Sangho Shin815af0c2014-10-10 13:05:45 -0700423 }
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700424 }
425 }
426
427 /**
428 * Reports ports of new links to driver and recalculate ECMP SPG
Sangho Shin23f898d2014-10-13 16:54:00 -0700429 * If the link to add was removed before, then we just schedule the add link
430 * event and do not recompute the path now.
Sangho Shinfbc572c2014-10-02 16:37:05 -0700431 *
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700432 * @param linkEntries
433 */
Sangho Shin23f898d2014-10-13 16:54:00 -0700434 private void processLinkAdd(Collection<LinkData> linkEntries, boolean delayed) {
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700435
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700436 for (LinkData link : linkEntries) {
Sangho Shin5be3e532014-10-03 17:20:58 -0700437
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700438 SwitchPort srcPort = link.getSrc();
439 SwitchPort dstPort = link.getDst();
440
Sangho Shin23f898d2014-10-13 16:54:00 -0700441 String key = srcPort.getDpid().toString() +
442 dstPort.getDpid().toString();
443 if (!delayed) {
444 if (linksDown.containsKey(key)) {
445 linksToAdd.put(key, link);
446 linksDown.remove(key);
447 linkAddTask.reschedule(DELAY_TO_ADD_LINK, TimeUnit.SECONDS);
448 log.debug("Add link {} with 5 sec delay", link);
449 // TODO: What if we have multiple events of add link:
450 // one is new link add, the other one is link up for
451 // broken link? ECMPSPG function cannot deal with it for now
452 return;
453 }
454 }
455 else {
456 if (linksDown.containsKey(key)) {
457 linksToAdd.remove(key);
458 log.debug("Do not add the link {}: it is down again!", link);
459 return;
460 }
461 }
462
Sangho Shinfbc572c2014-10-02 16:37:05 -0700463 IOF13Switch srcSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700464 getSwId(srcPort.getDpid().toString()));
Sangho Shinfbc572c2014-10-02 16:37:05 -0700465 IOF13Switch dstSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700466 getSwId(dstPort.getDpid().toString()));
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700467
Sangho Shin815af0c2014-10-10 13:05:45 -0700468 if ((srcSw == null) || (dstSw == null))
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700469 continue;
470
471 srcSw.addPortToGroups(srcPort.getPortNumber());
472 dstSw.addPortToGroups(dstPort.getPortNumber());
Sangho Shin5be3e532014-10-03 17:20:58 -0700473
Sangho Shin15273b62014-10-16 22:22:05 -0700474 //log.debug("Add a link port {} to switch {} to add link {}", srcPort, srcSw,
475 // link);
476 //log.debug("Add a link port {} to switch {} to add link {}", dstPort, dstSw,
477 // link);
Sangho Shin815af0c2014-10-10 13:05:45 -0700478
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700479 }
Sangho Shinbce900e2014-10-07 17:13:23 -0700480 populateEcmpRoutingRules(false);
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700481 }
482
483 /**
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700484 * Check if all links are gone b/w the two switches. If all links are gone,
485 * then we need to recalculate the path. Otherwise, just report link failure
Sangho Shin370e17b2014-10-27 11:39:08 -0700486 * to the driver. IF the switches do not support ECMP in transit routers and
487 * the link removed is between transit routers, then just recompute the path
488 * regardless of ECMP.
Sangho Shinfbc572c2014-10-02 16:37:05 -0700489 *
Sangho Shin61535402014-10-01 11:37:14 -0700490 * @param linkEntries
491 */
492 private void processLinkRemoval(Collection<LinkData> linkEntries) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700493 for (LinkData link : linkEntries) {
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700494 SwitchPort srcPort = link.getSrc();
495 SwitchPort dstPort = link.getDst();
Sangho Shinc8d2f592014-09-30 16:53:57 -0700496
Sangho Shinfbc572c2014-10-02 16:37:05 -0700497 IOF13Switch srcSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700498 getSwId(srcPort.getDpid().toString()));
Sangho Shinfbc572c2014-10-02 16:37:05 -0700499 IOF13Switch dstSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700500 getSwId(dstPort.getDpid().toString()));
Sangho Shin815af0c2014-10-10 13:05:45 -0700501 if ((srcSw == null) || (dstSw == null))
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700502 /* If this link is not between two switches, ignore it */
503 continue;
Sangho Shin23f898d2014-10-13 16:54:00 -0700504
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700505 srcSw.removePortFromGroups(srcPort.getPortNumber());
506 dstSw.removePortFromGroups(dstPort.getPortNumber());
Sangho Shin815af0c2014-10-10 13:05:45 -0700507 log.debug("Remove port {} from switch {}", srcPort, srcSw);
508 log.debug("Remove port {} from switch {}", dstPort, dstSw);
509
Sangho Shinf66aa262014-10-27 16:03:42 -0700510 if ((srcSw instanceof OFSwitchImplDellOSR &&
511 dstSw instanceof OFSwitchImplDellOSR) &&
Sangho Shin370e17b2014-10-27 11:39:08 -0700512 isTransitRouter(mutableTopology.getSwitch(srcPort.getDpid())) &&
513 isTransitRouter(mutableTopology.getSwitch(dstPort.getDpid()))) {
514 populateEcmpRoutingRules(false);
515 }
516 else {
517 Switch srcSwitch = mutableTopology.getSwitch(srcPort.getDpid());
518 if (srcSwitch.getLinkToNeighbor(dstPort.getDpid()) == null) {
519 log.debug("All links are gone b/w {} and {}", srcPort.getDpid(),
520 dstPort.getDpid());
521 log.debug("All paths will recomputed regardless of the rest "
522 + "of the event");
523 populateEcmpRoutingRules(false);
524 }
Sangho Shinc8d2f592014-09-30 16:53:57 -0700525 }
Sangho Shin23f898d2014-10-13 16:54:00 -0700526
527 String key = link.getSrc().getDpid().toString()+
528 link.getDst().getDpid().toString();
529 if (!linksDown.containsKey(key)) {
530 linksDown.put(key, link);
531 }
Sangho Shinc8d2f592014-09-30 16:53:57 -0700532 }
Sangho Shinbce900e2014-10-07 17:13:23 -0700533
Sangho Shin61535402014-10-01 11:37:14 -0700534 }
Sangho Shinc8d2f592014-09-30 16:53:57 -0700535
Sangho Shin61535402014-10-01 11:37:14 -0700536 /**
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700537 * report ports removed to the driver immediately
Sangho Shinfbc572c2014-10-02 16:37:05 -0700538 *
Sangho Shin61535402014-10-01 11:37:14 -0700539 * @param portEntries
540 */
541 private void processPortRemoval(Collection<PortData> portEntries) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700542 for (PortData port : portEntries) {
Sangho Shin61535402014-10-01 11:37:14 -0700543 Dpid dpid = port.getDpid();
Sangho Shin61535402014-10-01 11:37:14 -0700544
Sangho Shinfbc572c2014-10-02 16:37:05 -0700545 IOF13Switch sw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin61535402014-10-01 11:37:14 -0700546 getSwId(port.getDpid().toString()));
Sangho Shin815af0c2014-10-10 13:05:45 -0700547 if (sw != null) {
Sangho Shinfbc572c2014-10-02 16:37:05 -0700548 sw.removePortFromGroups(port.getPortNumber());
Sangho Shin815af0c2014-10-10 13:05:45 -0700549 log.debug("Remove port {} from switch {}", port, dpid);
550 }
Sangho Shin61535402014-10-01 11:37:14 -0700551 }
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700552 }
Sangho Shin1aa93542014-09-22 09:49:44 -0700553
554 /**
Sangho Shin7330c032014-10-20 10:34:51 -0700555 * Add the link immediately
556 * The function is scheduled when link add event happens and called
557 * DELAY_TO_ADD_LINK seconds after the event to avoid link flip-flop.
558 */
559 private void delayedAddLink() {
560
561 processLinkAdd(linksToAdd.values(), true);
562
563 }
564
565
566 // ************************************
567 // ECMP shorted path routing functions
568 // ************************************
569
570 /**
Sangho Shin43cee112014-09-25 16:43:34 -0700571 * Populate routing rules walking through the ECMP shortest paths
Sangho Shinfbc572c2014-10-02 16:37:05 -0700572 *
Sangho Shin99918bd2014-10-08 15:52:35 -0700573 * @param modified if true, it "modifies" the rules
Sangho Shin1aa93542014-09-22 09:49:44 -0700574 */
Sangho Shin5be3e532014-10-03 17:20:58 -0700575 private void populateEcmpRoutingRules(boolean modified) {
576 graphs.clear();
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700577 Iterable<Switch> switches = mutableTopology.getSwitches();
Sangho Shin43cee112014-09-25 16:43:34 -0700578 for (Switch sw : switches) {
579 ECMPShortestPathGraph ecmpSPG = new ECMPShortestPathGraph(sw);
Sangho Shinfbc572c2014-10-02 16:37:05 -0700580 graphs.put(sw, ecmpSPG);
581 //log.debug("ECMPShortestPathGraph is computed for switch {}",
582 // HexString.toHexString(sw.getDpid().value()));
Sangho Shin5be3e532014-10-03 17:20:58 -0700583 populateEcmpRoutingRulesForPath(sw, ecmpSPG, modified);
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700584
585 // Set adjacency routing rule for all switches
586 try {
587 populateAdjacencyncyRule(sw);
588 } catch (JSONException e) {
589 // TODO Auto-generated catch block
590 e.printStackTrace();
591 }
Sangho Shinfbc572c2014-10-02 16:37:05 -0700592 }
Sangho Shinbce900e2014-10-07 17:13:23 -0700593 numOfPopulation++;
Sangho Shinfbc572c2014-10-02 16:37:05 -0700594 }
Sangho Shin1aa93542014-09-22 09:49:44 -0700595
Sangho Shin204b9972014-10-22 11:08:10 -0700596 /**
597 * populate the MPLS rules to handle Adjacency IDs
598 *
599 * @param sw Switch
600 * @throws JSONException
601 */
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700602 private void populateAdjacencyncyRule(Switch sw) throws JSONException {
603 String adjInfo = sw.getStringAttribute("adjacencySids");
Sangho Shin204b9972014-10-22 11:08:10 -0700604 String nodeSidStr = sw.getStringAttribute("nodeSid");
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700605 String srcMac = sw.getStringAttribute("routerMac");
Sangho Shin204b9972014-10-22 11:08:10 -0700606 String autoAdjInfo = sw.getStringAttribute("autogenAdjSids");
607
Sangho Shinced05b62014-10-22 11:23:14 -0700608 if (autoAdjInfo == null || srcMac == null || nodeSidStr == null)
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700609 return;
610
Sangho Shinced05b62014-10-22 11:23:14 -0700611 // parse adjacency Id
Sangho Shincfef3922014-10-22 12:04:16 -0700612 HashMap<Integer, List<Integer>> adjacencyInfo = null;
Sangho Shinced05b62014-10-22 11:23:14 -0700613 if (adjInfo != null) {
Sangho Shincfef3922014-10-22 12:04:16 -0700614 adjacencyInfo = parseAdjacencySidInfo(adjInfo);
Sangho Shinced05b62014-10-22 11:23:14 -0700615 }
Sangho Shincfef3922014-10-22 12:04:16 -0700616 // parse auto generated adjacency Id
617 adjacencyInfo.putAll(parseAdjacencySidInfo(autoAdjInfo));
Sangho Shinced05b62014-10-22 11:23:14 -0700618
Sangho Shin6471d202014-10-23 10:59:36 -0700619 adjacencySidTable.put(Integer.parseInt(nodeSidStr), adjacencyInfo);
Sangho Shin204b9972014-10-22 11:08:10 -0700620
Sangho Shin6471d202014-10-23 10:59:36 -0700621 for (Integer adjId: adjacencyInfo.keySet()) {
622 List<Integer> ports = adjacencyInfo.get(adjId);
623 if (ports.size() == 1) {
624 setAdjacencyRuleOfOutput(sw, adjId, srcMac, ports.get(0));
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700625 }
626 else {
Sangho Shin6471d202014-10-23 10:59:36 -0700627 setAdjacencyRuleOfGroup(sw, adjId, ports);
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700628 }
Sangho Shin6471d202014-10-23 10:59:36 -0700629 }
630 }
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700631
Sangho Shin6471d202014-10-23 10:59:36 -0700632 /**
633 * Set Adjacency Rule to MPLS table for adjacency Ids attached to multiple
634 * ports
635 *
636 * @param sw Switch
637 * @param adjId Adjacency ID
638 * @param ports List of ports assigned to the Adjacency ID
639 */
640 private void setAdjacencyRuleOfGroup(Switch sw, Integer adjId, List<Integer> ports) {
641
642 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
643 getSwId(sw.getDpid().toString()));
644
645 int groupId = -1;
646 if (sw13 != null) {
647 List<PortNumber> portList = new ArrayList<PortNumber>();
648 for (Integer port: ports)
649 portList.add(PortNumber.uint32(port));
650 groupId = sw13.createGroup(new ArrayList<Integer>(), portList);
651 }
652
653 if (groupId < 0) {
654 log.debug("Failed to create a group at driver for adj ID {}", adjId);
655 }
656
657 pushAdjRule(sw, adjId, null, null, groupId, true);
658 pushAdjRule(sw, adjId, null, null, groupId, false);
659 }
660
661 /**
662 * Set Adjacency Rule to MPLS table for adjacency Ids attached to single port
663 *
664 * @param sw Switch
665 * @param adjId Adjacency ID
666 * @param ports List of ports assigned to the Adjacency ID
667 */
668 private void setAdjacencyRuleOfOutput(Switch sw, Integer adjId, String srcMac, Integer portNo) {
669
670 Dpid dstDpid = null;
671 for (Link link: sw.getOutgoingLinks()) {
672 if (link.getSrcPort().getPortNumber().value() == portNo) {
673 dstDpid = link.getDstPort().getDpid();
674 break;
675 }
676 }
677 if (dstDpid == null) {
678 log.debug("Cannot find the destination switch for the adjacency ID {}", adjId);
679 return;
680 }
681 Switch dstSw = mutableTopology.getSwitch(dstDpid);
682 String dstMac = null;
683 if (dstSw == null) {
684 log.debug("Cannot find SW {}", dstDpid.toString());
685 return;
686 }
687 else {
688 dstMac = dstSw.getStringAttribute("routerMac");
689 }
690
691 pushAdjRule(sw, adjId, srcMac, dstMac, portNo, true); // BoS = 1
692 pushAdjRule(sw, adjId, srcMac, dstMac, portNo, false); // BoS = 0
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700693
694 }
695
Sangho Shin204b9972014-10-22 11:08:10 -0700696 /**
697 * Push the MPLS rule for Adjacency ID
698 *
699 * @param sw Switch to push the rule
700 * @param id Adjacency ID
701 * @param srcMac source MAC address
702 * @param dstMac destination MAC address
703 * @param portNo port number assigned to the ID
704 * @param bos BoS option
705 */
Sangho Shin6471d202014-10-23 10:59:36 -0700706 private void pushAdjRule(Switch sw, int id, String srcMac, String dstMac,
707 int num, boolean bos) {
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700708
709 MplsMatch mplsMatch = new MplsMatch(id, bos);
710 List<Action> actions = new ArrayList<Action>();
711
712 if (bos) {
713 PopMplsAction popAction = new PopMplsAction(EthType.IPv4);
714 CopyTtlInAction copyTtlInAction = new CopyTtlInAction();
715 DecNwTtlAction decNwTtlAction = new DecNwTtlAction(1);
716 actions.add(copyTtlInAction);
717 actions.add(popAction);
718 actions.add(decNwTtlAction);
719 }
720 else {
721 PopMplsAction popAction = new PopMplsAction(EthType.MPLS_UNICAST);
722 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
723 actions.add(popAction);
724 actions.add(decMplsTtlAction);
725 }
726
Sangho Shin6471d202014-10-23 10:59:36 -0700727 // Output action
728 if (srcMac != null && dstMac != null) {
Sangho Shind6d8a7e2014-10-28 14:51:03 -0700729 ModifyDstMacAction setDstAction = new ModifyDstMacAction(MACAddress.valueOf(dstMac));
730 ModifySrcMacAction setSrcAction = new ModifySrcMacAction(MACAddress.valueOf(srcMac));
Sangho Shin6471d202014-10-23 10:59:36 -0700731 OutputAction outportAction = new OutputAction(PortNumber.uint32(num));
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700732
Sangho Shin6471d202014-10-23 10:59:36 -0700733 actions.add(setDstAction);
734 actions.add(setSrcAction);
735 actions.add(outportAction);
736 }
737 // Group Action
738 else {
739 GroupAction groupAction = new GroupAction();
740 groupAction.setGroupId(num);
741 actions.add(groupAction);
742 }
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700743
744 MatchAction matchAction = new MatchAction(new MatchActionId(matchActionId++),
745 new SwitchPort((long) 0, (short) 0), mplsMatch, actions);
746 Operator operator = Operator.ADD;
747 MatchActionOperationEntry maEntry =
748 new MatchActionOperationEntry(operator, matchAction);
749
750 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
751 getSwId(sw.getDpid().toString()));
752
753 if (sw13 != null) {
754 try {
755 //printMatchActionOperationEntry(sw, maEntry);
756 sw13.pushFlow(maEntry);
757 } catch (IOException e) {
758 e.printStackTrace();
759 }
760 }
761 }
762
Sangho Shin99918bd2014-10-08 15:52:35 -0700763 /**
764 * populate routing rules to forward packets from the switch given to
765 * all other switches.
766 *
767 * @param sw source switch
768 * @param ecmpSPG shortest path from the the source switch to all others
769 * @param modified modification flag
770 */
Sangho Shinfbc572c2014-10-02 16:37:05 -0700771 private void populateEcmpRoutingRulesForPath(Switch sw,
Sangho Shin5be3e532014-10-03 17:20:58 -0700772 ECMPShortestPathGraph ecmpSPG, boolean modified) {
Sangho Shin43cee112014-09-25 16:43:34 -0700773
Sangho Shinfbc572c2014-10-02 16:37:05 -0700774 HashMap<Integer, HashMap<Switch, ArrayList<ArrayList<Dpid>>>> switchVia =
775 ecmpSPG.getAllLearnedSwitchesAndVia();
776 for (Integer itrIdx : switchVia.keySet()) {
777 //log.debug("ECMPShortestPathGraph:Switches learned in "
778 // + "Iteration{} from switch {}:",
779 // itrIdx,
780 // HexString.toHexString(sw.getDpid().value()));
781 HashMap<Switch, ArrayList<ArrayList<Dpid>>> swViaMap =
782 switchVia.get(itrIdx);
783 for (Switch targetSw : swViaMap.keySet()) {
Sangho Shin5be3e532014-10-03 17:20:58 -0700784 //log.debug("ECMPShortestPathGraph:****switch {} via:",
785 // HexString.toHexString(targetSw.getDpid().value()));
Sangho Shinfbc572c2014-10-02 16:37:05 -0700786 String destSw = sw.getDpid().toString();
787 List<String> fwdToSw = new ArrayList<String>();
788
Sangho Shinfbc572c2014-10-02 16:37:05 -0700789 for (ArrayList<Dpid> via : swViaMap.get(targetSw)) {
Sangho Shin5be3e532014-10-03 17:20:58 -0700790 //log.debug("ECMPShortestPathGraph:******{}) {}", ++i, via);
Sangho Shinfbc572c2014-10-02 16:37:05 -0700791 if (via.isEmpty()) {
792 fwdToSw.add(destSw);
Sangho Shin43cee112014-09-25 16:43:34 -0700793 }
Sangho Shinfbc572c2014-10-02 16:37:05 -0700794 else {
795 fwdToSw.add(via.get(0).toString());
796 }
Sangho Shin43cee112014-09-25 16:43:34 -0700797 }
Sangho Shin5be3e532014-10-03 17:20:58 -0700798 setRoutingRule(targetSw, destSw, fwdToSw, modified);
Sangho Shineb083032014-09-22 16:11:34 -0700799 }
Sangho Shinfbc572c2014-10-02 16:37:05 -0700800
801 // Send Barrier Message and make sure all rules are set
802 // before we set the rules to next routers
Saurav Dasa962a692014-10-17 14:52:38 -0700803 // TODO: barriers to all switches in this update stage
Sangho Shinfbc572c2014-10-02 16:37:05 -0700804 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
805 getSwId(sw.getDpid().toString()));
Sangho Shin5be3e532014-10-03 17:20:58 -0700806 if (sw13 != null) {
Saurav Dasa962a692014-10-17 14:52:38 -0700807 OFBarrierReplyFuture replyFuture = null;
Sangho Shin5be3e532014-10-03 17:20:58 -0700808 try {
Saurav Dasa962a692014-10-17 14:52:38 -0700809 replyFuture = sw13.sendBarrier();
Sangho Shin5be3e532014-10-03 17:20:58 -0700810 } catch (IOException e) {
Saurav Dasa962a692014-10-17 14:52:38 -0700811 log.error("Error sending barrier request to switch {}",
812 sw13.getId(), e.getCause());
Sangho Shin5be3e532014-10-03 17:20:58 -0700813 }
Saurav Dasa962a692014-10-17 14:52:38 -0700814 OFBarrierReply br = null;
815 try {
816 br = replyFuture.get(2, TimeUnit.SECONDS);
817 } catch (TimeoutException | InterruptedException | ExecutionException e) {
818 // XXX for some reason these exceptions are not being thrown
819 }
820 if (br == null) {
821 log.warn("Did not receive barrier-reply from {}", sw13.getId());
822 // XXX take corrective action
823 }
824
Sangho Shinfbc572c2014-10-02 16:37:05 -0700825 }
826 }
827
828 }
829
Sangho Shinfbc572c2014-10-02 16:37:05 -0700830 /**
831 *
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700832 * Set routing rules in targetSw {forward packets to fwdToSw switches in
833 * order to send packets to destSw} - If the target switch is an edge router
834 * and final destnation switch is also an edge router, then set IP
835 * forwarding rules to subnets - If only the target switch is an edge
836 * router, then set IP forwarding rule to the transit router loopback IP
837 * address - If the target is a transit router, then just set the MPLS
838 * forwarding rule
Sangho Shinfbc572c2014-10-02 16:37:05 -0700839 *
Sangho Shin43cee112014-09-25 16:43:34 -0700840 * @param targetSw Switch to set the rules
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700841 * @param destSw Final destination switches
Sangho Shin43cee112014-09-25 16:43:34 -0700842 * @param fwdToSw next hop switches
843 */
Sangho Shin99918bd2014-10-08 15:52:35 -0700844 private void setRoutingRule(Switch targetSw, String destSw,
845 List<String> fwdToSw, boolean modified) {
Sangho Shin43cee112014-09-25 16:43:34 -0700846
Sangho Shin43cee112014-09-25 16:43:34 -0700847 if (fwdToSw.isEmpty()) {
848 fwdToSw.add(destSw);
849 }
850
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700851 // if both target SW and dest SW are an edge router, then set IP table
Sangho Shin43cee112014-09-25 16:43:34 -0700852 if (IsEdgeRouter(targetSw.getDpid().toString()) &&
853 IsEdgeRouter(destSw)) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700854 // We assume that there is at least one transit router b/w edge
855 // routers
Sangho Shin43cee112014-09-25 16:43:34 -0700856 Switch destSwitch = mutableTopology.getSwitch(new Dpid(destSw));
857 String subnets = destSwitch.getStringAttribute("subnets");
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700858 setIpTableRouterSubnet(targetSw, subnets, getMplsLabel(destSw)
Sangho Shin5be3e532014-10-03 17:20:58 -0700859 , fwdToSw, modified);
Sangho Shin43cee112014-09-25 16:43:34 -0700860
Sangho Shin43cee112014-09-25 16:43:34 -0700861 String routerIp = destSwitch.getStringAttribute("routerIp");
Sangho Shin5be3e532014-10-03 17:20:58 -0700862 setIpTableRouter(targetSw, routerIp, getMplsLabel(destSw), fwdToSw,
863 null, modified);
Sangho Shin721ca042014-10-09 13:03:40 -0700864 // Edge router can be a transit router
865 setMplsTable(targetSw, getMplsLabel(destSw), fwdToSw, modified);
Sangho Shin43cee112014-09-25 16:43:34 -0700866 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700867 // Only if the target switch is the edge router, then set the IP rules
Sangho Shin43cee112014-09-25 16:43:34 -0700868 else if (IsEdgeRouter(targetSw.getDpid().toString())) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700869 // We assume that there is at least one transit router b/w edge
870 // routers
Sangho Shin43cee112014-09-25 16:43:34 -0700871 Switch destSwitch = mutableTopology.getSwitch(new Dpid(destSw));
872 String routerIp = destSwitch.getStringAttribute("routerIp");
Sangho Shin5be3e532014-10-03 17:20:58 -0700873 setIpTableRouter(targetSw, routerIp, getMplsLabel(destSw), fwdToSw,
874 null, modified);
Sangho Shin721ca042014-10-09 13:03:40 -0700875 // Edge router can be a transit router
876 setMplsTable(targetSw, getMplsLabel(destSw), fwdToSw, modified);
Sangho Shin43cee112014-09-25 16:43:34 -0700877 }
878 // if it is a transit router, then set rules in the MPLS table
879 else {
Sangho Shin5be3e532014-10-03 17:20:58 -0700880 setMplsTable(targetSw, getMplsLabel(destSw), fwdToSw, modified);
Sangho Shin43cee112014-09-25 16:43:34 -0700881 }
882
883 }
884
Sangho Shinfbc572c2014-10-02 16:37:05 -0700885 /**
886 * Set IP forwarding rule to the gateway of each subnet of switches
887 *
888 * @param targetSw Switch to set rules
889 * @param subnets subnet information
890 * @param mplsLabel destination MPLS label
891 * @param fwdToSw router to forward packets to
892 */
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700893 private void setIpTableRouterSubnet(Switch targetSw, String subnets,
Sangho Shin5be3e532014-10-03 17:20:58 -0700894 String mplsLabel, List<String> fwdToSw, boolean modified) {
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700895
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700896 Collection<MatchActionOperationEntry> entries =
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700897 new ArrayList<MatchActionOperationEntry>();
898
899 try {
900 JSONArray arry = new JSONArray(subnets);
901 for (int i = 0; i < arry.length(); i++) {
902 String subnetIp = (String) arry.getJSONObject(i).get("subnetIp");
Sangho Shin5be3e532014-10-03 17:20:58 -0700903 setIpTableRouter(targetSw, subnetIp, mplsLabel, fwdToSw, entries,
904 modified);
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700905 }
906 } catch (JSONException e) {
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700907 e.printStackTrace();
908 }
909
910 if (!entries.isEmpty()) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700911 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700912 getSwId(targetSw.getDpid().toString()));
913
Sangho Shin721ca042014-10-09 13:03:40 -0700914 if (sw13 != null) {
915 try {
916 sw13.pushFlows(entries);
917 } catch (IOException e) {
918 e.printStackTrace();
919 }
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700920 }
921 }
922
923 }
924
Sangho Shin43cee112014-09-25 16:43:34 -0700925 /**
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700926 * Set IP forwarding rule - If the destination is the next hop, then do not
927 * push MPLS, just decrease the NW TTL - Otherwise, push MPLS label and set
928 * the MPLS ID
Sangho Shinfbc572c2014-10-02 16:37:05 -0700929 *
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700930 * @param sw target switch to set rules
Sangho Shin43cee112014-09-25 16:43:34 -0700931 * @param subnetIp Match IP address
932 * @param mplsLabel MPLS label of final destination router
933 * @param fwdToSws next hop routers
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700934 * @param entries
Sangho Shin43cee112014-09-25 16:43:34 -0700935 */
936 private void setIpTableRouter(Switch sw, String subnetIp, String mplsLabel,
Sangho Shin5be3e532014-10-03 17:20:58 -0700937 List<String> fwdToSws, Collection<MatchActionOperationEntry> entries,
938 boolean modified) {
Sangho Shin43cee112014-09-25 16:43:34 -0700939
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700940 Ipv4Match ipMatch = new Ipv4Match(subnetIp);
Sangho Shin43cee112014-09-25 16:43:34 -0700941 List<Action> actions = new ArrayList<>();
Sangho Shin721ca042014-10-09 13:03:40 -0700942 GroupAction groupAction = new GroupAction();
Sangho Shin43cee112014-09-25 16:43:34 -0700943
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700944 // If destination SW is the same as the fwd SW, then do not push MPLS
945 // label
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700946 if (fwdToSws.size() > 1) {
Sangho Shin43cee112014-09-25 16:43:34 -0700947 PushMplsAction pushMplsAction = new PushMplsAction();
948 SetMplsIdAction setIdAction = new SetMplsIdAction(Integer.parseInt(mplsLabel));
949 CopyTtlOutAction copyTtlOutAction = new CopyTtlOutAction();
Sangho Shin463bee52014-09-29 15:14:43 -0700950 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
Sangho Shin43cee112014-09-25 16:43:34 -0700951
Sangho Shin62ce5c12014-10-08 16:24:40 -0700952 //actions.add(pushMplsAction);
953 //actions.add(copyTtlOutAction);
954 //actions.add(decMplsTtlAction);
Saurav Das82e62972014-10-16 14:53:57 -0700955 // actions.add(setIdAction);
Sangho Shin721ca042014-10-09 13:03:40 -0700956 groupAction.setEdgeLabel(Integer.parseInt(mplsLabel));
Sangho Shin43cee112014-09-25 16:43:34 -0700957 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700958 else {
959 String fwdToSw = fwdToSws.get(0);
960 if (getMplsLabel(fwdToSw).equals(mplsLabel)) {
961 DecNwTtlAction decTtlAction = new DecNwTtlAction(1);
962 actions.add(decTtlAction);
963 }
964 else {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700965 SetMplsIdAction setIdAction = new SetMplsIdAction(
966 Integer.parseInt(mplsLabel));
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700967 CopyTtlOutAction copyTtlOutAction = new CopyTtlOutAction();
Sangho Shin463bee52014-09-29 15:14:43 -0700968 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700969
Sangho Shin62ce5c12014-10-08 16:24:40 -0700970 //actions.add(pushMplsAction);
971 //actions.add(copyTtlOutAction);
972 //actions.add(decMplsTtlAction);
Saurav Das82e62972014-10-16 14:53:57 -0700973 // actions.add(setIdAction);
Sangho Shin721ca042014-10-09 13:03:40 -0700974 groupAction.setEdgeLabel(Integer.parseInt(mplsLabel));
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700975 }
976 }
Sangho Shin43cee112014-09-25 16:43:34 -0700977
Sangho Shin43cee112014-09-25 16:43:34 -0700978 for (String fwdSw : fwdToSws) {
979 groupAction.addSwitch(new Dpid(fwdSw));
980 }
981 actions.add(groupAction);
982
Sangho Shin99918bd2014-10-08 15:52:35 -0700983 MatchAction matchAction = new MatchAction(new MatchActionId(matchActionId++),
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700984 new SwitchPort((long) 0, (short) 0), ipMatch, actions);
Sangho Shin43cee112014-09-25 16:43:34 -0700985
Sangho Shin5be3e532014-10-03 17:20:58 -0700986 Operator operator = null;
987 if (modified)
988 operator = Operator.MODIFY;
989 else
990 operator = Operator.ADD;
991
Sangho Shin43cee112014-09-25 16:43:34 -0700992 MatchActionOperationEntry maEntry =
Sangho Shin5be3e532014-10-03 17:20:58 -0700993 new MatchActionOperationEntry(operator, matchAction);
Sangho Shin43cee112014-09-25 16:43:34 -0700994
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700995 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700996 getSwId(sw.getDpid().toString()));
997
Sangho Shin5be3e532014-10-03 17:20:58 -0700998 if (sw13 != null) {
999 try {
Sangho Shinbce900e2014-10-07 17:13:23 -07001000 //printMatchActionOperationEntry(sw, maEntry);
Sangho Shin5be3e532014-10-03 17:20:58 -07001001 if (entries != null)
1002 entries.add(maEntry);
1003 else
1004 sw13.pushFlow(maEntry);
1005 } catch (IOException e) {
1006 e.printStackTrace();
1007 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -07001008 }
1009
Sangho Shin43cee112014-09-25 16:43:34 -07001010 }
1011
Sangho Shinac5ee2b2014-09-28 21:27:20 -07001012 /**
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001013 * Set MPLS forwarding rules to MPLS table
1014 * </p>
1015 * If the destination is the same as the next hop to forward packets then,
1016 * pop the MPLS label according to PHP rule. Here, if BoS is set, then
1017 * copy TTL In and decrement NW TTL. Otherwise, it just decrement the MPLS
1018 * TTL of the another MPLS header.
1019 * If the next hop is not the destination, just forward packets to next
1020 * hops using Group action.
Sangho Shinfbc572c2014-10-02 16:37:05 -07001021 *
Sangho Shin204b9972014-10-22 11:08:10 -07001022 * TODO: refactoring required
1023 *
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001024 * @param sw Switch to set the rules
Sangho Shin43cee112014-09-25 16:43:34 -07001025 * @param mplsLabel destination MPLS label
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001026 * @param fwdSws next hop switches
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001027 * */
Sangho Shin5be3e532014-10-03 17:20:58 -07001028 private void setMplsTable(Switch sw, String mplsLabel, List<String> fwdSws,
1029 boolean modified) {
Sangho Shin463bee52014-09-29 15:14:43 -07001030
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001031 if (fwdSws.isEmpty())
1032 return;
Sangho Shin43cee112014-09-25 16:43:34 -07001033
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001034 Collection<MatchActionOperationEntry> maEntries =
1035 new ArrayList<MatchActionOperationEntry>();
1036 String fwdSw1 = fwdSws.get(0);
Sangho Shin43cee112014-09-25 16:43:34 -07001037
Sangho Shine842cad2014-10-24 16:07:35 -07001038 //If the next hop is the destination router, do PHP
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001039 if (fwdSws.size() == 1 && mplsLabel.equals(getMplsLabel(fwdSw1))) {
Sangho Shine842cad2014-10-24 16:07:35 -07001040 maEntries.add(buildMAEntry(sw, mplsLabel, fwdSws, true, true));
1041 maEntries.add(buildMAEntry(sw, mplsLabel, fwdSws, true, false));
Sangho Shin9c0f4c32014-09-26 16:02:38 -07001042 }
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001043 else {
Sangho Shine842cad2014-10-24 16:07:35 -07001044 maEntries.add(buildMAEntry(sw, mplsLabel, fwdSws, false, true));
1045 maEntries.add(buildMAEntry(sw, mplsLabel, fwdSws, false, false));
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001046 }
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001047 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin9c0f4c32014-09-26 16:02:38 -07001048 getSwId(sw.getDpid().toString()));
1049
Sangho Shin5be3e532014-10-03 17:20:58 -07001050 if (sw13 != null) {
1051 try {
Sangho Shinbce900e2014-10-07 17:13:23 -07001052 //printMatchActionOperationEntry(sw, maEntry);
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001053 sw13.pushFlows(maEntries);
Sangho Shin5be3e532014-10-03 17:20:58 -07001054 } catch (IOException e) {
1055 e.printStackTrace();
1056 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -07001057 }
Sangho Shin43cee112014-09-25 16:43:34 -07001058 }
1059
Sangho Shin7330c032014-10-20 10:34:51 -07001060
1061 // ************************************
1062 // Policy routing classes and functions
1063 // ************************************
1064
Fahad Naeem Khan1e712ad2014-10-27 16:48:07 -07001065 /**
1066 * Enums for policy type
1067 *
1068 */
1069 public enum PolicyType{
1070 TUNNEL_FLOW,
1071 LOADBALANCE,
1072 AVOID,
1073 DENY
1074 }
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001075 public class PolicyInfo {
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001076 private String policyId;
1077 private PacketMatch match;
1078 private int priority;
1079 private String tunnelId;
Fahad Naeem Khan1e712ad2014-10-27 16:48:07 -07001080 private PolicyType type;
Sangho Shin5b8f5452014-10-20 11:46:01 -07001081
Fahad Naeem Khan1e712ad2014-10-27 16:48:07 -07001082 public PolicyInfo(String pid, PolicyType type, PacketMatch match, int priority,
Sangho Shin58182672014-10-21 13:23:38 -07001083 String tid) {
1084 this.policyId = pid;
1085 this.match = match;
1086 this.priority = priority;
1087 this.tunnelId = tid;
1088 this.type = type;
1089 }
Sangho Shin204b9972014-10-22 11:08:10 -07001090
Fahad Naeem Khan95aa4012014-10-21 14:07:00 -07001091 public PolicyInfo(String pid, PacketMatch match, int priority,
1092 String tid) {
1093 this.policyId = pid;
1094 this.match = match;
1095 this.priority = priority;
1096 this.tunnelId = tid;
Fahad Naeem Khan1e712ad2014-10-27 16:48:07 -07001097 this.type = PolicyType.TUNNEL_FLOW;
Fahad Naeem Khan95aa4012014-10-21 14:07:00 -07001098 }
1099 public String getPolicyId(){
1100 return this.policyId;
1101 }
1102 public PacketMatch getMatch(){
1103 return this.match;
1104 }
1105 public int getPriority(){
1106 return this.priority;
1107 }
1108 public String getTunnelId(){
1109 return this.tunnelId;
1110 }
Fahad Naeem Khan1e712ad2014-10-27 16:48:07 -07001111 public PolicyType getType(){
Fahad Naeem Khan95aa4012014-10-21 14:07:00 -07001112 return this.type;
1113 }
Sangho Shin5b8f5452014-10-20 11:46:01 -07001114 }
1115
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001116 public class TunnelInfo {
1117 private String tunnelId;
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001118 private List<Integer> labelIds;
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001119 private List<TunnelRouteInfo> routes;
Sangho Shin81655442014-10-20 14:22:46 -07001120
Sangho Shin6471d202014-10-23 10:59:36 -07001121 public TunnelInfo(String tid, List<Integer> labelIds,
1122 List<TunnelRouteInfo> routes) {
Sangho Shin81655442014-10-20 14:22:46 -07001123 this.tunnelId = tid;
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001124 this.labelIds = labelIds;
Sangho Shin81655442014-10-20 14:22:46 -07001125 this.routes = routes;
1126 }
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001127 public String getTunnelId(){
1128 return this.tunnelId;
1129 }
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001130
1131 public List<Integer> getLabelids() {
1132 return this.labelIds;
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001133 }
1134 public List<TunnelRouteInfo> getRoutes(){
1135 return this.routes;
1136 }
Sangho Shin81655442014-10-20 14:22:46 -07001137 }
1138
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001139 public class TunnelRouteInfo {
Sangho Shin7330c032014-10-20 10:34:51 -07001140
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001141 private String srcSwDpid;
1142 private List<Dpid> fwdSwDpids;
1143 private List<String> route;
Sangho Shin6471d202014-10-23 10:59:36 -07001144 private int gropuId;
Sangho Shin7330c032014-10-20 10:34:51 -07001145
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001146 public TunnelRouteInfo() {
Sangho Shin7330c032014-10-20 10:34:51 -07001147 fwdSwDpids = new ArrayList<Dpid>();
1148 route = new ArrayList<String>();
1149 }
1150
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001151 private void setSrcDpid(String dpid) {
Sangho Shin7330c032014-10-20 10:34:51 -07001152 this.srcSwDpid = dpid;
1153 }
1154
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001155 private void setFwdSwDpid(List<Dpid> dpid) {
Sangho Shin7330c032014-10-20 10:34:51 -07001156 this.fwdSwDpids = dpid;
1157 }
1158
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001159 private void addRoute(String id) {
Sangho Shin7330c032014-10-20 10:34:51 -07001160 route.add(id);
1161 }
1162
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001163 private void setRoute(List<String> r) {
Sangho Shin7330c032014-10-20 10:34:51 -07001164 this.route = r;
1165 }
1166
Sangho Shin6471d202014-10-23 10:59:36 -07001167 private void setGroupId(int groupId) {
1168 this.gropuId = groupId;
1169 }
1170
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001171 public String getSrcSwDpid() {
Sangho Shin7330c032014-10-20 10:34:51 -07001172 return this.srcSwDpid;
1173 }
1174
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001175 public List<Dpid> getFwdSwDpid() {
Sangho Shin7330c032014-10-20 10:34:51 -07001176 return this.fwdSwDpids;
1177 }
1178
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001179 public List<String> getRoute() {
Sangho Shin7330c032014-10-20 10:34:51 -07001180 return this.route;
1181 }
Sangho Shin6471d202014-10-23 10:59:36 -07001182
1183 public int getGroupId() {
1184 return this.gropuId;
1185 }
Sangho Shin7330c032014-10-20 10:34:51 -07001186 }
1187
Sangho Shin15273b62014-10-16 22:22:05 -07001188 /**
Sangho Shin81655442014-10-20 14:22:46 -07001189 * Return the Tunnel table
1190 *
1191 * @return collection of TunnelInfo
1192 */
1193 public Collection<TunnelInfo> getTunnelTable() {
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001194 return this.tunnelTable.values();
Sangho Shin81655442014-10-20 14:22:46 -07001195 }
Sangho Shin204b9972014-10-22 11:08:10 -07001196
Fahad Naeem Khan12fa63a2014-10-21 17:01:27 -07001197 public Collection<PolicyInfo> getPoclicyTable() {
1198 return this.policyTable.values();
1199 }
Sangho Shin81655442014-10-20 14:22:46 -07001200
1201 /**
Sangho Shin5671cbb2014-10-20 22:35:41 -07001202 * Return router DPIDs for the tunnel
1203 *
1204 * @param tid tunnel ID
1205 * @return List of DPID
1206 */
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001207 public List<Integer> getTunnelInfo(String tid) {
Sangho Shin5671cbb2014-10-20 22:35:41 -07001208 TunnelInfo tunnelInfo = tunnelTable.get(tid);
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001209 return tunnelInfo.labelIds;
Sangho Shin5671cbb2014-10-20 22:35:41 -07001210
1211 }
1212
1213 /**
1214 * Get the first group ID for the tunnel for specific source router
1215 * If Segment Stitching was required to create the tunnel, there are
1216 * mutiple source routers.
1217 *
1218 * @param tunnelId ID for the tunnel
1219 * @param dpid source router DPID
1220 * @return the first group ID of the tunnel
1221 */
1222 public int getTunnelGroupId(String tunnelId, String dpid) {
Sangho Shin6471d202014-10-23 10:59:36 -07001223 TunnelInfo tunnelInfo = tunnelTable.get(tunnelId);
1224 for (TunnelRouteInfo routeInfo: tunnelInfo.getRoutes()) {
1225 String tunnelSrcDpid = routeInfo.getSrcSwDpid();
1226 if (tunnelSrcDpid.equals(dpid))
1227 return routeInfo.getGroupId();
1228 }
Sangho Shin5671cbb2014-10-20 22:35:41 -07001229
Sangho Shin6471d202014-10-23 10:59:36 -07001230 return -1;
Sangho Shin5671cbb2014-10-20 22:35:41 -07001231 }
1232
1233 /**
Sangho Shin15273b62014-10-16 22:22:05 -07001234 * Create a tunnel for policy routing
1235 * It delivers the node IDs of tunnels to driver.
1236 * Split the node IDs if number of IDs exceeds the limit for stitching.
1237 *
1238 * @param tunnelId Node IDs for the tunnel
1239 * @param Ids tunnel ID
1240 */
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001241 public boolean createTunnel(String tunnelId, List<Integer> labelIds) {
Sangho Shin15273b62014-10-16 22:22:05 -07001242
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001243 if (labelIds.isEmpty() || labelIds.size() < 2) {
Sangho Shin15273b62014-10-16 22:22:05 -07001244 log.debug("Wrong tunnel information");
1245 return false;
1246 }
1247
Sangho Shin55d00e12014-10-20 12:13:07 -07001248 List<String> Ids = new ArrayList<String>();
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001249 for (Integer label : labelIds) {
1250 Ids.add(label.toString());
Sangho Shin55d00e12014-10-20 12:13:07 -07001251 }
1252
Sangho Shin81655442014-10-20 14:22:46 -07001253 List<TunnelRouteInfo> stitchingRule = getStitchingRule(Ids);
Sangho Shin15273b62014-10-16 22:22:05 -07001254 if (stitchingRule == null) {
Sangho Shin6471d202014-10-23 10:59:36 -07001255 log.debug("Failed to get a tunnel rule.");
Sangho Shin15273b62014-10-16 22:22:05 -07001256 return false;
1257 }
Sangho Shin55908712014-10-27 15:16:48 -07001258
Sangho Shin81655442014-10-20 14:22:46 -07001259 for (TunnelRouteInfo route: stitchingRule) {
Sangho Shin15273b62014-10-16 22:22:05 -07001260 NeighborSet ns = new NeighborSet();
1261 for (Dpid dpid: route.getFwdSwDpid())
1262 ns.addDpid(dpid);
1263
Sangho Shin6471d202014-10-23 10:59:36 -07001264 printTunnelInfo(route.srcSwDpid, tunnelId, route.getRoute(), ns);
1265 int groupId = -1;
1266 if ((groupId =createGroupsForTunnel(tunnelId, route, ns)) < 0) {
1267 log.debug("Failed to create a tunnel at driver.");
1268 return false;
1269 }
1270 route.setGroupId(groupId);
Sangho Shin15273b62014-10-16 22:22:05 -07001271 }
1272
Sangho Shin6471d202014-10-23 10:59:36 -07001273 TunnelInfo tunnelInfo = new TunnelInfo(tunnelId, labelIds,
1274 stitchingRule);
Sangho Shin81655442014-10-20 14:22:46 -07001275 tunnelTable.put(tunnelId, tunnelInfo);
Sangho Shin15273b62014-10-16 22:22:05 -07001276
1277 return true;
1278 }
1279
Sangho Shin1a692c02014-10-23 17:05:41 -07001280 /**
1281 * Create groups for the tunnel
1282 *
1283 * @param tunnelId tunnel ID
1284 * @param routeInfo label stacks for the tunnel
1285 * @param ns NeighborSet to forward packets
1286 * @return group ID, return -1 if it fails
1287 */
Sangho Shin6471d202014-10-23 10:59:36 -07001288 private int createGroupsForTunnel(String tunnelId, TunnelRouteInfo routeInfo,
1289 NeighborSet ns) {
1290
1291 IOF13Switch targetSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
1292 getSwId(routeInfo.srcSwDpid));
1293
1294 if (targetSw == null) {
1295 log.debug("Switch {} is gone.", routeInfo.srcSwDpid);
1296 return -1;
1297 }
1298
1299 List<Integer> Ids = new ArrayList<Integer>();
1300 for (String IdStr: routeInfo.route)
1301 Ids.add(Integer.parseInt(IdStr));
1302
1303 List<PortNumber> ports = getPortsFromNeighborSet(routeInfo.srcSwDpid, ns);
1304 int groupId = targetSw.createGroup(Ids, ports);
1305
1306 return groupId;
1307 }
1308
Sangho Shin15273b62014-10-16 22:22:05 -07001309 /**
1310 * Set policy table for policy routing
1311 *
1312 * @param sw
1313 * @param mplsLabel
Sangho Shin306633a2014-10-20 14:26:55 -07001314 * @return
Sangho Shin15273b62014-10-16 22:22:05 -07001315 */
Sangho Shin306633a2014-10-20 14:26:55 -07001316 public boolean createPolicy(String pid, MACAddress srcMac, MACAddress dstMac,
Sangho Shin15273b62014-10-16 22:22:05 -07001317 Short etherType, IPv4Net srcIp, IPv4Net dstIp, Byte ipProto,
Sangho Shine020cc32014-10-20 13:28:02 -07001318 Short srcTcpPort, Short dstTcpPort, int priority, String tid) {
Sangho Shin15273b62014-10-16 22:22:05 -07001319
Sangho Shin5b8f5452014-10-20 11:46:01 -07001320 PacketMatchBuilder packetBuilder = new PacketMatchBuilder();
1321
1322 if (srcMac != null)
1323 packetBuilder.setSrcMac(srcMac);
1324 if (dstMac != null)
1325 packetBuilder.setDstMac(dstMac);
Sangho Shin58182672014-10-21 13:23:38 -07001326 if (etherType == null) // Cqpd requires the type of IPV4
1327 packetBuilder.setEtherType(Ethernet.TYPE_IPV4);
1328 else
Sangho Shin5b8f5452014-10-20 11:46:01 -07001329 packetBuilder.setEtherType(etherType);
1330 if (srcIp != null)
1331 packetBuilder.setSrcIp(srcIp.address(), srcIp.prefixLen());
1332 if (dstIp != null)
1333 packetBuilder.setDstIp(dstIp.address(), dstIp.prefixLen());
1334 if (ipProto != null)
1335 packetBuilder.setIpProto(ipProto);
1336 if (srcTcpPort > 0)
1337 packetBuilder.setSrcTcpPort(srcTcpPort);
1338 if (dstTcpPort > 0)
1339 packetBuilder.setDstTcpPort(dstTcpPort);
1340 PacketMatch policyMatch = packetBuilder.build();
Sangho Shin81655442014-10-20 14:22:46 -07001341 TunnelInfo tunnelInfo = tunnelTable.get(tid);
Sangho Shin6471d202014-10-23 10:59:36 -07001342 if (tunnelInfo == null) {
1343 log.debug("Tunnel {} is not defined", tid);
1344 return false;
1345 }
Sangho Shin81655442014-10-20 14:22:46 -07001346 List<TunnelRouteInfo> routes = tunnelInfo.routes;
Sangho Shin5b8f5452014-10-20 11:46:01 -07001347
Sangho Shin81655442014-10-20 14:22:46 -07001348 for (TunnelRouteInfo route : routes) {
Sangho Shin15273b62014-10-16 22:22:05 -07001349 List<Action> actions = new ArrayList<>();
1350 GroupAction groupAction = new GroupAction();
Sangho Shin6471d202014-10-23 10:59:36 -07001351 groupAction.setGroupId(route.getGroupId());
Sangho Shin15273b62014-10-16 22:22:05 -07001352 actions.add(groupAction);
1353
1354 MatchAction matchAction = new MatchAction(new MatchActionId(
1355 matchActionId++),
Sangho Shin5b8f5452014-10-20 11:46:01 -07001356 new SwitchPort((long) 0, (short) 0), policyMatch, priority,
1357 actions);
Sangho Shin15273b62014-10-16 22:22:05 -07001358 MatchActionOperationEntry maEntry =
1359 new MatchActionOperationEntry(Operator.ADD, matchAction);
1360
1361 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin81655442014-10-20 14:22:46 -07001362 getSwId(route.srcSwDpid));
Sangho Shin15273b62014-10-16 22:22:05 -07001363
1364 if (sw13 != null) {
1365 printMatchActionOperationEntry(sw13, maEntry);
1366 try {
1367 sw13.pushFlow(maEntry);
1368 } catch (IOException e) {
1369 e.printStackTrace();
Sangho Shin306633a2014-10-20 14:26:55 -07001370 return false;
Sangho Shin15273b62014-10-16 22:22:05 -07001371 }
1372 }
1373 }
Sangho Shin5b8f5452014-10-20 11:46:01 -07001374
1375 PolicyInfo policyInfo = new PolicyInfo(pid, policyMatch, priority, tid);
Sangho Shine020cc32014-10-20 13:28:02 -07001376 policyTable.put(pid, policyInfo);
Sangho Shin306633a2014-10-20 14:26:55 -07001377
1378 return true;
Sangho Shin15273b62014-10-16 22:22:05 -07001379 }
1380
1381 /**
Sangho Shin1ad7be02014-10-20 16:56:49 -07001382 * Split the nodes IDs into multiple tunnel if Segment Stitching is required.
1383 * We assume that the first node ID is the one of source router, and the last
1384 * node ID is that of the destination router.
Sangho Shin15273b62014-10-16 22:22:05 -07001385 *
Sangho Shin1ad7be02014-10-20 16:56:49 -07001386 * @param route list of node IDs
1387 * @return List of the TunnelRoutInfo
Sangho Shin15273b62014-10-16 22:22:05 -07001388 */
Sangho Shin81655442014-10-20 14:22:46 -07001389 private List<TunnelRouteInfo> getStitchingRule(List<String> route) {
Sangho Shin15273b62014-10-16 22:22:05 -07001390
Sangho Shin1a692c02014-10-23 17:05:41 -07001391 if (route.isEmpty() || route.size() < 3)
Sangho Shin15273b62014-10-16 22:22:05 -07001392 return null;
1393
Sangho Shin81655442014-10-20 14:22:46 -07001394 List<TunnelRouteInfo> rules = new ArrayList<TunnelRouteInfo>();
Sangho Shin15273b62014-10-16 22:22:05 -07001395
1396 Switch srcSw = this.getSwitchFromNodeId(route.get(0));
Sangho Shin6471d202014-10-23 10:59:36 -07001397 if (srcSw == null) {
1398 log.warn("Switch is not found for Node SID {}", route.get(0));
1399 return null;
1400 }
Sangho Shin15273b62014-10-16 22:22:05 -07001401 String srcDpid = srcSw.getDpid().toString();
1402
Sangho Shin15273b62014-10-16 22:22:05 -07001403 int i = 0;
Sangho Shine020cc32014-10-20 13:28:02 -07001404 TunnelRouteInfo routeInfo = new TunnelRouteInfo();
Sangho Shin1a692c02014-10-23 17:05:41 -07001405 boolean checkNeighbor = false;
Sangho Shin6471d202014-10-23 10:59:36 -07001406 String prevAdjacencySid = null;
1407 String prevNodeId = null;
Sangho Shin15273b62014-10-16 22:22:05 -07001408
1409 for (String nodeId: route) {
Sangho Shin6471d202014-10-23 10:59:36 -07001410 // The first node ID is always the source router.
1411 // We assume that the first ID cannot be an Adjacency SID.
Sangho Shin15273b62014-10-16 22:22:05 -07001412 if (i == 0) {
Sangho Shin15273b62014-10-16 22:22:05 -07001413 srcSw = getSwitchFromNodeId(nodeId);
Sangho Shin1a692c02014-10-23 17:05:41 -07001414 if (srcDpid == null)
1415 srcDpid = srcSw.getDpid().toString();
1416 routeInfo.setSrcDpid(srcDpid);
1417 checkNeighbor = true;
Sangho Shin15273b62014-10-16 22:22:05 -07001418 i++;
1419 }
Sangho Shin1a692c02014-10-23 17:05:41 -07001420 // if this is the first node ID to put the label stack..
Sangho Shin6471d202014-10-23 10:59:36 -07001421 else if (i == 1) {
Sangho Shin1a692c02014-10-23 17:05:41 -07001422 if (checkNeighbor) {
1423 List<Dpid> fwdSws = getDpidIfNeighborOf(nodeId, srcSw);
1424 // if nodeId is NOT the neighbor of srcSw..
1425 if (fwdSws.isEmpty()) {
1426 fwdSws = getForwardingSwitchForNodeId(srcSw,nodeId);
1427 if (fwdSws == null || fwdSws.isEmpty()) {
1428 log.warn("There is no route from node {} to node {}",
1429 srcSw.getDpid(), nodeId);
1430 return null;
Sangho Shin6471d202014-10-23 10:59:36 -07001431 }
Sangho Shin6471d202014-10-23 10:59:36 -07001432 routeInfo.addRoute(nodeId);
Sangho Shin6471d202014-10-23 10:59:36 -07001433 i++;
1434 }
Sangho Shin1a692c02014-10-23 17:05:41 -07001435 routeInfo.setFwdSwDpid(fwdSws);
Sangho Shin6471d202014-10-23 10:59:36 -07001436 // we check only the next node ID of the source router
1437 checkNeighbor = false;
Sangho Shin1a692c02014-10-23 17:05:41 -07001438 }
1439 // if neighbor check is already done, then just add it
1440 else {
Sangho Shin6471d202014-10-23 10:59:36 -07001441 routeInfo.addRoute(nodeId);
Sangho Shin15273b62014-10-16 22:22:05 -07001442 i++;
1443 }
1444 }
Sangho Shin6471d202014-10-23 10:59:36 -07001445 // if i > 1
Sangho Shin15273b62014-10-16 22:22:05 -07001446 else {
Sangho Shin6471d202014-10-23 10:59:36 -07001447 // If the adjacency SID is pushed and the next SID is the destination
1448 // of the adjacency SID, then do not add the SID.
1449 if (prevAdjacencySid != null) {
1450 if (isAdjacencySidNeighborOf(prevNodeId, prevAdjacencySid, nodeId)) {
1451 prevAdjacencySid = null;
Sangho Shind6d8a7e2014-10-28 14:51:03 -07001452 prevNodeId = nodeId;
Sangho Shin6471d202014-10-23 10:59:36 -07001453 continue;
1454 }
1455 prevAdjacencySid = null;
1456 }
Sangho Shin15273b62014-10-16 22:22:05 -07001457 routeInfo.addRoute(nodeId);
1458 i++;
1459 }
1460
Sangho Shin1a692c02014-10-23 17:05:41 -07001461 // If the adjacency ID is added the label stack,
1462 // then we need to check if the next node is the destination of the adjacency SID
1463 if (isAdjacencySid(nodeId))
1464 prevAdjacencySid = nodeId;
1465
Sangho Shin1ad7be02014-10-20 16:56:49 -07001466 // If the number of labels reaches the limit, start over the procedure
Sangho Shin15273b62014-10-16 22:22:05 -07001467 if (i == MAX_NUM_LABELS+1) {
Sangho Shin1a692c02014-10-23 17:05:41 -07001468
Sangho Shin81655442014-10-20 14:22:46 -07001469 rules.add(routeInfo);
Sangho Shine020cc32014-10-20 13:28:02 -07001470 routeInfo = new TunnelRouteInfo();
Sangho Shin1a692c02014-10-23 17:05:41 -07001471
Sangho Shin62325582014-10-24 10:36:09 -07001472 if (isAdjacencySid(nodeId)) {
1473 // If the previous sub tunnel finishes with adjacency SID,
1474 // then we need to start the procedure from the adjacency
1475 // destination ID.
1476 List<Switch> destNodeList =
1477 getAdjacencyDestinationNode(prevNodeId, nodeId);
1478 if (destNodeList == null || destNodeList.isEmpty()) {
1479 log.warn("Cannot find destination node for adjacencySID {}",
1480 nodeId);
1481 return null;
1482 }
1483 // If the previous sub tunnel finishes with adjacency SID with
1484 // multiple ports, then we need to remove the adjacency Sid
1485 // from the previous sub tunnel and start the new sub tunnel
1486 // with the adjacency Sid. Technically, the new subtunnel
1487 // forward packets to the port assigned to the adjacency Sid
1488 // and the label stack starts with the next ID.
1489 // This is to avoid to install new policy rule to multiple nodes for stitching when the
1490 // adjacency Sid that has more than one port.
1491 if (destNodeList.size() > 1) {
1492 rules.get(rules.size()-1).route.remove(nodeId);
1493 srcSw = getSwitchFromNodeId(prevNodeId);
1494 List<Dpid> fwdSws = getDpidIfNeighborOf(nodeId, srcSw);
1495 routeInfo.setFwdSwDpid(fwdSws);
1496 routeInfo.setSrcDpid(srcSw.getDpid().toString());
1497 i = 1;
1498 checkNeighbor = false;
1499 continue;
1500 }
1501 else {
Sangho Shin1a692c02014-10-23 17:05:41 -07001502 srcSw = destNodeList.get(0);
Sangho Shin62325582014-10-24 10:36:09 -07001503 }
1504 }
1505 else {
1506 srcSw = getSwitchFromNodeId(nodeId);
Sangho Shin1a692c02014-10-23 17:05:41 -07001507 }
1508 srcDpid = srcSw.getDpid().toString();
Sangho Shin15273b62014-10-16 22:22:05 -07001509 routeInfo.setSrcDpid(srcDpid);
1510 i = 1;
1511 checkNeighbor = true;
1512 }
Sangho Shin6471d202014-10-23 10:59:36 -07001513
1514 if (prevAdjacencySid == null)
1515 prevNodeId = nodeId;
Sangho Shin15273b62014-10-16 22:22:05 -07001516 }
1517
Sangho Shin1a692c02014-10-23 17:05:41 -07001518
Sangho Shineb148ea2014-10-24 12:44:15 -07001519 if (i < MAX_NUM_LABELS+1 && (routeInfo.getFwdSwDpid() != null &&
1520 !routeInfo.getFwdSwDpid().isEmpty())) {
Sangho Shin81655442014-10-20 14:22:46 -07001521 rules.add(routeInfo);
Sangho Shineb148ea2014-10-24 12:44:15 -07001522 // NOTE: empty label stack can happen, but forwarding destination should be set
Sangho Shin15273b62014-10-16 22:22:05 -07001523 }
1524
1525 return rules;
1526 }
1527
Sangho Shin5b8f5452014-10-20 11:46:01 -07001528 /**
1529 * Remove all policies applied to specific tunnel.
1530 *
1531 * @param srcMac
1532 * @param dstMac
1533 * @param etherType
1534 * @param srcIp
1535 * @param dstIp
1536 * @param ipProto
1537 * @param srcTcpPort
1538 * @param dstTcpPort
1539 * @param tid
Sangho Shin306633a2014-10-20 14:26:55 -07001540 * @return
Sangho Shin5b8f5452014-10-20 11:46:01 -07001541 */
Sangho Shin306633a2014-10-20 14:26:55 -07001542 public boolean removePolicy(String pid) {
Sangho Shine020cc32014-10-20 13:28:02 -07001543 PolicyInfo policyInfo = policyTable.get(pid);
Sangho Shin5671cbb2014-10-20 22:35:41 -07001544 if (policyInfo == null)
1545 return false;
Sangho Shin5b8f5452014-10-20 11:46:01 -07001546 PacketMatch policyMatch = policyInfo.match;
Sangho Shine020cc32014-10-20 13:28:02 -07001547 String tid = policyInfo.tunnelId;
Sangho Shin5b8f5452014-10-20 11:46:01 -07001548 int priority = policyInfo.priority;
1549
1550 List<Action> actions = new ArrayList<>();
1551 int gropuId = 0; // dummy group ID
1552 GroupAction groupAction = new GroupAction();
1553 groupAction.setGroupId(gropuId);
1554 actions.add(groupAction);
1555
1556 MatchAction matchAction = new MatchAction(new MatchActionId(
1557 matchActionId++),
1558 new SwitchPort((long) 0, (short) 0), policyMatch, priority,
1559 actions);
1560 MatchActionOperationEntry maEntry =
1561 new MatchActionOperationEntry(Operator.REMOVE, matchAction);
1562
Sangho Shin81655442014-10-20 14:22:46 -07001563 TunnelInfo tunnelInfo = tunnelTable.get(tid);
Sangho Shin5671cbb2014-10-20 22:35:41 -07001564 if (tunnelInfo == null)
1565 return false;
Sangho Shin81655442014-10-20 14:22:46 -07001566 List<TunnelRouteInfo> routes = tunnelInfo.routes;
1567
1568 for (TunnelRouteInfo route : routes) {
Sangho Shin5b8f5452014-10-20 11:46:01 -07001569 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin81655442014-10-20 14:22:46 -07001570 getSwId(route.srcSwDpid));
Sangho Shin5b8f5452014-10-20 11:46:01 -07001571
Sangho Shin5671cbb2014-10-20 22:35:41 -07001572 if (sw13 == null) {
1573 return false;
1574 }
1575 else {
Sangho Shin5b8f5452014-10-20 11:46:01 -07001576 printMatchActionOperationEntry(sw13, maEntry);
1577 try {
1578 sw13.pushFlow(maEntry);
1579 } catch (IOException e) {
1580 e.printStackTrace();
1581 log.debug("policy remove failed due to pushFlow() exception");
Sangho Shin306633a2014-10-20 14:26:55 -07001582 return false;
Sangho Shin5b8f5452014-10-20 11:46:01 -07001583 }
1584 }
1585 }
1586
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001587 policyTable.remove(pid);
Sangho Shin5b8f5452014-10-20 11:46:01 -07001588 log.debug("Policy {} is removed.", pid);
Sangho Shin306633a2014-10-20 14:26:55 -07001589 return true;
Sangho Shine020cc32014-10-20 13:28:02 -07001590 }
Sangho Shin5b8f5452014-10-20 11:46:01 -07001591
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001592 /**
1593 * Remove a tunnel
1594 * It removes all groups for the tunnel if the tunnel is not used for any
1595 * policy.
1596 *
1597 * @param tunnelId tunnel ID to remove
1598 */
Sangho Shin306633a2014-10-20 14:26:55 -07001599 public boolean removeTunnel(String tunnelId) {
Sangho Shin55d00e12014-10-20 12:13:07 -07001600
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001601 // Check if the tunnel is used for any policy
1602 for (PolicyInfo policyInfo: policyTable.values()) {
Sangho Shina000c612014-10-21 14:17:59 -07001603 if (policyInfo.tunnelId.equals(tunnelId)) {
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001604 log.debug("Tunnel {} is still used for the policy {}.",
1605 policyInfo.policyId, tunnelId);
1606 return false;
1607 }
1608 }
1609
1610 TunnelInfo tunnelInfo = tunnelTable.get(tunnelId);
Sangho Shin5671cbb2014-10-20 22:35:41 -07001611 if (tunnelInfo == null)
1612 return false;
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001613
1614 List<TunnelRouteInfo> routes = tunnelInfo.routes;
1615 for (TunnelRouteInfo route: routes) {
1616 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
1617 getSwId(route.srcSwDpid));
1618
Sangho Shin5671cbb2014-10-20 22:35:41 -07001619 if (sw13 == null) {
1620 return false;
1621 }
1622 else {
Sangho Shin93f623c2014-10-24 12:59:53 -07001623 if (!sw13.removeGroup(route.getGroupId())) {
Sangho Shine842cad2014-10-24 16:07:35 -07001624 log.warn("Faied to remove the tunnel {} at driver",
1625 tunnelId);
Sangho Shin93f623c2014-10-24 12:59:53 -07001626 return false; }
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001627 }
1628 }
1629
1630 tunnelTable.remove(tunnelId);
Sangho Shine842cad2014-10-24 16:07:35 -07001631 log.debug("Tunnel {} was removed successfully.", tunnelId);
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001632
Sangho Shin306633a2014-10-20 14:26:55 -07001633 return true;
Sangho Shin55d00e12014-10-20 12:13:07 -07001634 }
1635
Sangho Shin7330c032014-10-20 10:34:51 -07001636 // ************************************
1637 // Utility functions
1638 // ************************************
1639
Sangho Shin1a692c02014-10-23 17:05:41 -07001640 /**
1641 * Get the destination Nodes of the adjacency Sid
1642 *
1643 * @param nodeId node ID of the adjacency Sid
1644 * @param adjacencySid adjacency Sid
1645 * @return List of Switch, empty list if not found
1646 */
1647 private List<Switch> getAdjacencyDestinationNode(String nodeId, String adjacencySid) {
1648 List<Switch> dstSwList = new ArrayList<Switch>();
1649
1650 HashMap<Integer, List<Integer>> adjacencySidInfo =
1651 adjacencySidTable.get(Integer.valueOf(nodeId));
1652 List<Integer> ports = adjacencySidInfo.get(Integer.valueOf(adjacencySid));
1653 Switch srcSw = getSwitchFromNodeId(nodeId);
1654 for (Integer port: ports) {
1655 for (Link link: srcSw.getOutgoingLinks()) {
1656 if (link.getSrcPort().getPortNumber().value() == port) {
1657 dstSwList.add(link.getDstSwitch());
1658 }
1659 }
1660 }
1661
1662 return dstSwList;
1663
1664 }
1665
1666 /**
1667 * Get the DPID of the router with node ID IF the node ID is the neighbor of the
1668 * Switch srcSW.
1669 * If the nodeId is the adjacency Sid, then it returns the destination router DPIDs.
1670 *
1671 * @param nodeId Node ID to check
1672 * @param srcSw target Switch
1673 * @return List of DPID of nodeId, empty list if the nodeId is not the neighbor of srcSW
1674 */
1675 private List<Dpid> getDpidIfNeighborOf(String nodeId, Switch srcSw) {
1676 List<Dpid> fwdSws = new ArrayList<Dpid>();
1677 // if the nodeID is the adjacency ID, then we need to regard it as the
1678 // neighbor node ID and need to return the destination router DPID(s)
1679 if (isAdjacencySid(nodeId)) {
1680 String srcNodeId = this.getMplsLabel(srcSw.getDpid().toString());
1681 HashMap<Integer, List<Integer>> adjacencySidInfo =
1682 adjacencySidTable.get(Integer.valueOf(srcNodeId));
1683 List<Integer> ports = adjacencySidInfo.get(Integer.valueOf(nodeId));
1684
1685 for (Integer port: ports) {
1686 for (Link link: srcSw.getOutgoingLinks()) {
1687 if (link.getSrcPort().getPortNumber().value() == port) {
1688 fwdSws.add(link.getDstSwitch().getDpid());
1689 }
1690 }
1691 }
1692 }
1693 else {
1694 List<Dpid> fwdSwDpids = getForwardingSwitchForNodeId(srcSw,nodeId);
1695 if (fwdSwDpids == null || fwdSwDpids.isEmpty()) {
1696 log.warn("There is no route from node {} to node {}",
1697 srcSw.getDpid(), nodeId);
Sangho Shin55908712014-10-27 15:16:48 -07001698 return fwdSws;
Sangho Shin1a692c02014-10-23 17:05:41 -07001699 }
1700
1701 for (Dpid dpid: fwdSwDpids) {
1702 if (getMplsLabel(dpid.toString()).toString().equals(nodeId)) {
1703 fwdSws.add(dpid);
1704 break;
1705 }
1706 }
1707 }
1708
1709 return fwdSws;
1710 }
1711
1712 /**
Sangho Shin55908712014-10-27 15:16:48 -07001713 * Get port numbers of the neighbor set.
1714 * If ECMP in transit router is not supported, then only one port should be returned
1715 * regardless of number of nodes in neighbor set.
Sangho Shin1a692c02014-10-23 17:05:41 -07001716 *
1717 * @param srcSwDpid source switch
1718 * @param ns Neighbor set of the switch
1719 * @return List of PortNumber, null if not found
1720 */
Sangho Shin6471d202014-10-23 10:59:36 -07001721 private List<PortNumber> getPortsFromNeighborSet(String srcSwDpid, NeighborSet ns) {
1722
1723 List<PortNumber> portList = new ArrayList<PortNumber>();
1724 Switch srcSwitch = mutableTopology.getSwitch(new Dpid(srcSwDpid));
1725 if (srcSwitch == null)
1726 return null;
Sangho Shinf66aa262014-10-27 16:03:42 -07001727 IOF13Switch srcSwitch13 = (IOF13Switch)floodlightProvider.getMasterSwitch(
1728 getSwId(srcSwitch.getDpid().toString()));
1729
Sangho Shin6471d202014-10-23 10:59:36 -07001730 for (Dpid neighborDpid: ns.getDpids()) {
Sangho Shinf66aa262014-10-27 16:03:42 -07001731 if (srcSwitch13 instanceof OFSwitchImplDellOSR &&
1732 ns.getDpids().size() == 1) {
Sangho Shin55908712014-10-27 15:16:48 -07001733 Switch dstSwitch = mutableTopology.getSwitch(neighborDpid);
1734 if (isTransitRouter(srcSwitch) && isTransitRouter(dstSwitch)) {
1735 Link link = srcSwitch.getLinkToNeighbor(neighborDpid);
1736 portList.add(link.getSrcPort().getNumber());
1737 break;
1738 }
1739 }
1740 else {
1741 for (Link link: srcSwitch.getOutgoingLinks()) {
1742 if (link.getDstSwitch().getDpid().equals(neighborDpid)) {
1743 portList.add(link.getSrcPort().getNumber());
1744 }
1745 }
1746 }
Sangho Shin6471d202014-10-23 10:59:36 -07001747 }
1748
1749 return portList;
1750 }
1751
Sangho Shine842cad2014-10-24 16:07:35 -07001752 /**
1753 * Check whether the router with preNodeid is connected to the router
1754 * with nodeId via adjacencySid or not
1755 *
1756 * @param prevNodeId the router node ID of the adjacencySid
1757 * @param adjacencySid adjacency SID
1758 * @param nodeId the router node ID to check
1759 * @return
1760 */
1761 private boolean isAdjacencySidNeighborOf(String prevNodeId, String adjacencySid, String nodeId) {
Sangho Shin6471d202014-10-23 10:59:36 -07001762
1763 HashMap<Integer, List<Integer>> adjacencySidInfo = adjacencySidTable.get(Integer.valueOf(prevNodeId));
Sangho Shine842cad2014-10-24 16:07:35 -07001764 List<Integer> ports = adjacencySidInfo.get(Integer.valueOf(adjacencySid));
Sangho Shin6471d202014-10-23 10:59:36 -07001765
1766 for (Integer port: ports) {
1767 Switch sw = getSwitchFromNodeId(prevNodeId);
1768 for (Link link: sw.getOutgoingLinks()) {
1769 if (link.getSrcPort().getPortNumber().value() == port) {
1770 if (getMplsLabel(link.getDstPort().getDpid().toString()).equals(nodeId)) {
1771 return true;
1772 }
1773 }
1774 }
1775 }
1776
1777 return false;
1778 }
1779
Sangho Shine842cad2014-10-24 16:07:35 -07001780 /**
1781 * Check if the node ID is the adjacency ID or not
1782 *
1783 * @param nodeId to check
1784 * @return true if the node ID is the adjacency ID, false otherwise
1785 */
Sangho Shin6471d202014-10-23 10:59:36 -07001786 private boolean isAdjacencySid(String nodeId) {
1787 // XXX The rule might change
1788 if (Integer.parseInt(nodeId) > 10000)
1789 return true;
1790
1791 return false;
1792 }
1793
Sangho Shin15273b62014-10-16 22:22:05 -07001794 /**
Sangho Shinced05b62014-10-22 11:23:14 -07001795 * Returns the Adjacency IDs for the node
1796 *
1797 * @param nodeSid Node SID
Sangho Shincfef3922014-10-22 12:04:16 -07001798 * @return Collection of Adjacency ID
Sangho Shinced05b62014-10-22 11:23:14 -07001799 */
Sangho Shincfef3922014-10-22 12:04:16 -07001800 public Collection<Integer> getAdjacencyIds(int nodeSid) {
1801 HashMap<Integer, List<Integer>> adjecencyInfo =
Sangho Shin6471d202014-10-23 10:59:36 -07001802 adjacencySidTable.get(Integer.valueOf(nodeSid));
Sangho Shincfef3922014-10-22 12:04:16 -07001803
1804 return adjecencyInfo.keySet();
1805 }
1806
1807 /**
1808 * Returns the Adjacency Info for the node
1809 *
1810 * @param nodeSid Node SID
1811 * @return HashMap of <AdjacencyID, list of ports>
1812 */
1813 public HashMap<Integer, List<Integer>> getAdjacencyInfo(int nodeSid) {
Sangho Shin6471d202014-10-23 10:59:36 -07001814 return adjacencySidTable.get(Integer.valueOf(nodeSid));
Sangho Shincfef3922014-10-22 12:04:16 -07001815 }
1816
Sangho Shine842cad2014-10-24 16:07:35 -07001817 /**
1818 * Parse the adjacency jason string and build the adjacency Table
1819 *
1820 * @param adjInfo adjacency info jason string
1821 * @return HashMap<Adjacency ID, List of ports> object
1822 * @throws JSONException
1823 */
1824 private HashMap<Integer, List<Integer>> parseAdjacencySidInfo(String adjInfo)
1825 throws JSONException {
Sangho Shincfef3922014-10-22 12:04:16 -07001826 JSONArray arry = new JSONArray(adjInfo);
1827 HashMap<Integer, List<Integer>> AdjacencyInfo =
1828 new HashMap<Integer, List<Integer>>();
1829
1830 for (int i = 0; i < arry.length(); i++) {
1831 Integer adjId = (Integer) arry.getJSONObject(i).get("adjSid");
1832 JSONArray portNos = (JSONArray) arry.getJSONObject(i).get("ports");
1833 if (adjId == null || portNos == null)
1834 continue;
1835
1836 List<Integer> portNoList = new ArrayList<Integer>();
1837 for (int j = 0; j < portNos.length(); j++) {
Sangho Shin62325582014-10-24 10:36:09 -07001838 portNoList.add(Integer.valueOf(portNos.getInt(j)));
Sangho Shincfef3922014-10-22 12:04:16 -07001839 }
1840 AdjacencyInfo.put(adjId, portNoList);
1841 }
1842 return AdjacencyInfo;
Sangho Shinced05b62014-10-22 11:23:14 -07001843 }
1844
1845 /**
Sangho Shine842cad2014-10-24 16:07:35 -07001846 * Build the MatchActionOperationEntry according to the flag
1847 *
1848 * @param sw node ID to push for MPLS label
1849 * @param mplsLabel List of Switch DPIDs to forwards packets to
1850 * @param fwdSws PHP flag
1851 * @param Bos BoS flag
1852 * @param isTransitRouter
1853 * @return MatchiACtionOperationEntry object
1854 */
1855 private MatchActionOperationEntry buildMAEntry(Switch sw,
1856 String mplsLabel, List<String> fwdSws, boolean php,
1857 boolean Bos) {
1858 MplsMatch mplsMatch = new MplsMatch(Integer.parseInt(mplsLabel), Bos);
1859 List<Action> actions = new ArrayList<Action>();
1860
1861 PopMplsAction popActionBos = new PopMplsAction(EthType.IPv4);
1862 PopMplsAction popAction = new PopMplsAction(EthType.MPLS_UNICAST);
1863 CopyTtlInAction copyTtlInAction = new CopyTtlInAction();
1864 DecNwTtlAction decNwTtlAction = new DecNwTtlAction(1);
1865 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
1866
1867 if (php) {
1868 actions.add(copyTtlInAction);
1869 if (Bos) {
1870 actions.add(popActionBos);
1871 actions.add(decNwTtlAction);
1872 }
1873 else {
1874 actions.add(popAction);
1875 actions.add(decMplsTtlAction);
1876 }
1877 }
1878 else {
1879 actions.add(decMplsTtlAction);
1880 }
1881
Sangho Shin402354e2014-10-27 16:53:05 -07001882 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
1883 getSwId(sw.getDpid().toString()));
1884 if ((sw13 instanceof OFSwitchImplDellOSR) && isTransitRouter(sw) && !php) {
Sangho Shine842cad2014-10-24 16:07:35 -07001885 PortNumber port = pickOnePort(sw, fwdSws);
1886 if (port == null) {
1887 log.warn("Failed to get a port from NeightborSet");
1888 return null;
1889 }
1890 OutputAction outputAction = new OutputAction(port);
1891 Switch destSwitch =
1892 mutableTopology.getSwitch(new Dpid(fwdSws.get(0)));
1893 MacAddress srcMac =
1894 MacAddress.of(sw.getStringAttribute("routerMac"));
1895 MacAddress dstMac =
1896 MacAddress.of(destSwitch.getStringAttribute("routerMac"));
1897 SetSAAction setSAAction = new SetSAAction(srcMac);
1898 SetDAAction setDAAction = new SetDAAction(dstMac);
1899 actions.add(outputAction);
1900 actions.add(setSAAction);
1901 actions.add(setDAAction);
1902 }
1903 else {
1904 GroupAction groupAction = new GroupAction();
1905 for (String dpid: fwdSws)
1906 groupAction.addSwitch(new Dpid(dpid));
1907 actions.add(groupAction);
1908 }
1909
1910 MatchAction matchAction = new MatchAction(new MatchActionId(matchActionId++),
1911 new SwitchPort((long) 0, (short) 0), mplsMatch, actions);
1912 Operator operator = Operator.ADD;
1913 MatchActionOperationEntry maEntry =
1914 new MatchActionOperationEntry(operator, matchAction);
1915
1916 return maEntry;
1917 }
1918
1919 /**
1920 * Pick a router from the neighbor set and return the port
1921 * connected to the router.
1922 *
1923 * @param sw source switch
1924 * @param fwdSwDpids neighbor set of the switch
1925 * @return PortNumber connected to one of the neighbors
1926 */
1927 private PortNumber pickOnePort(Switch sw, List<String> fwdSwDpids) {
1928 for (Link link: sw.getOutgoingLinks()) {
1929 if (link.getDstSwitch().getDpid().toString().equals(fwdSwDpids.get(0)))
1930 return link.getSrcPort().getNumber();
1931 }
1932
1933 return null;
1934 }
1935
1936 /**
1937 * check if the router is the transit router or not
1938 *
1939 * @param sw router switch to check
1940 * @return true if the switch is the transit router, false otherwise
1941 */
1942 private boolean isTransitRouter(Switch sw) {
1943 int i = 0;
1944 for(Switch neighbor: sw.getNeighbors()) {
1945 i++;
1946 }
1947 if (i > 1)
1948 return true;
1949 else
1950 return false;
1951 }
1952
1953 /**
Sangho Shin55908712014-10-27 15:16:48 -07001954 * Get the forwarding Switch DPIDs to send packets to a node.
1955 * If ECMP in transit routers is not supported, only one switch needs to be
1956 * selected as the neighbor set to forward packets to.
Sangho Shin15273b62014-10-16 22:22:05 -07001957 *
Sangho Shin7330c032014-10-20 10:34:51 -07001958 * @param srcSw source switch
1959 * @param nodeId destination node Id
1960 * @return list of switch DPID to forward packets to
Sangho Shin15273b62014-10-16 22:22:05 -07001961 */
Sangho Shin7330c032014-10-20 10:34:51 -07001962 private List<Dpid> getForwardingSwitchForNodeId(Switch srcSw, String nodeId) {
Sangho Shin15273b62014-10-16 22:22:05 -07001963
Sangho Shin7330c032014-10-20 10:34:51 -07001964 List<Dpid> fwdSws = new ArrayList<Dpid>();
1965 Switch destSw = null;
Sangho Shin15273b62014-10-16 22:22:05 -07001966
Sangho Shin7330c032014-10-20 10:34:51 -07001967 destSw = getSwitchFromNodeId(nodeId);
1968
1969 if (destSw == null) {
1970 log.debug("Cannot find the switch with ID {}", nodeId);
1971 return null;
1972 }
1973
1974 ECMPShortestPathGraph ecmpSPG = new ECMPShortestPathGraph(srcSw);
1975
1976 HashMap<Integer, HashMap<Switch, ArrayList<ArrayList<Dpid>>>> switchVia =
1977 ecmpSPG.getAllLearnedSwitchesAndVia();
1978 for (Integer itrIdx : switchVia.keySet()) {
1979 HashMap<Switch, ArrayList<ArrayList<Dpid>>> swViaMap =
1980 switchVia.get(itrIdx);
1981 for (Switch targetSw : swViaMap.keySet()) {
1982 String destSwDpid = destSw.getDpid().toString();
1983 if (targetSw.getDpid().toString().equals(destSwDpid)) {
1984 for (ArrayList<Dpid> via : swViaMap.get(targetSw)) {
1985 if (via.isEmpty()) {
1986 fwdSws.add(destSw.getDpid());
1987 }
1988 else {
Sangho Shina000c612014-10-21 14:17:59 -07001989 Dpid firstVia = via.get(via.size()-1);
1990 fwdSws.add(firstVia);
Sangho Shinf66aa262014-10-27 16:03:42 -07001991 IOF13Switch targetSw13 = (IOF13Switch)floodlightProvider.getMasterSwitch(
1992 getSwId(targetSw.getDpid().toString()));
1993 if (targetSw13 instanceof OFSwitchImplDellOSR &&
Sangho Shin55908712014-10-27 15:16:48 -07001994 isTransitRouter(targetSw) &&
1995 isTransitRouter(mutableTopology.getSwitch(firstVia))) {
1996 return fwdSws;
1997 }
Sangho Shin7330c032014-10-20 10:34:51 -07001998 }
1999 }
2000 }
2001 }
2002 }
2003
2004 return fwdSws;
Sangho Shin15273b62014-10-16 22:22:05 -07002005 }
2006
Sangho Shin7330c032014-10-20 10:34:51 -07002007 /**
2008 * Get switch for the node Id specified
2009 *
2010 * @param nodeId node ID for switch
2011 * @return Switch
2012 */
2013 private Switch getSwitchFromNodeId(String nodeId) {
Fahad Naeem Khan4444b952014-10-18 22:30:50 -07002014
Sangho Shin7330c032014-10-20 10:34:51 -07002015 for (Switch sw : mutableTopology.getSwitches()) {
2016 String id = sw.getStringAttribute("nodeSid");
2017 if (id.equals(nodeId)) {
2018 return sw;
2019 }
2020 }
2021
2022 return null;
2023 }
Fahad Naeem Khan4444b952014-10-18 22:30:50 -07002024
Sangho Shin43cee112014-09-25 16:43:34 -07002025 /**
Sangho Shin7330c032014-10-20 10:34:51 -07002026 * Convert a string DPID to its Switch Id (integer)
Sangho Shinfbc572c2014-10-02 16:37:05 -07002027 *
Sangho Shin7330c032014-10-20 10:34:51 -07002028 * @param dpid
2029 * @return
Sangho Shin43cee112014-09-25 16:43:34 -07002030 */
Sangho Shin7330c032014-10-20 10:34:51 -07002031 private long getSwId(String dpid) {
Sangho Shin43cee112014-09-25 16:43:34 -07002032
Sangho Shin7330c032014-10-20 10:34:51 -07002033 long swId = 0;
Sangho Shin43cee112014-09-25 16:43:34 -07002034
Sangho Shin7330c032014-10-20 10:34:51 -07002035 String swIdHexStr = "0x"+dpid.substring(dpid.lastIndexOf(":") + 1);
2036 if (swIdHexStr != null)
2037 swId = Integer.decode(swIdHexStr);
Sangho Shin43cee112014-09-25 16:43:34 -07002038
Sangho Shin7330c032014-10-20 10:34:51 -07002039 return swId;
2040 }
Sangho Shin43cee112014-09-25 16:43:34 -07002041
Sangho Shin7330c032014-10-20 10:34:51 -07002042 /**
2043 * Check if the switch is the edge router or not.
2044 *
2045 * @param dpid Dpid of the switch to check
2046 * @return true if it is an edge router, otherwise false
2047 */
2048 private boolean IsEdgeRouter(String dpid) {
Sangho Shin0df01982014-09-25 17:11:18 -07002049
Sangho Shin7330c032014-10-20 10:34:51 -07002050 for (Switch sw : mutableTopology.getSwitches()) {
2051 String dpidStr = sw.getDpid().toString();
2052 if (dpid.equals(dpidStr)) {
2053 /*
2054 String subnetInfo = sw.getStringAttribute("subnets");
2055 if (subnetInfo == null || subnetInfo.equals("[]")) {
2056 return false;
2057 }
2058 else
2059 return true;
2060 */
2061 String isEdge = sw.getStringAttribute("isEdgeRouter");
2062 if (isEdge != null) {
2063 if (isEdge.equals("true"))
2064 return true;
2065 else
2066 return false;
2067 }
Sangho Shin43cee112014-09-25 16:43:34 -07002068 }
2069 }
2070
Sangho Shin7330c032014-10-20 10:34:51 -07002071 return false;
Sangho Shineb083032014-09-22 16:11:34 -07002072 }
2073
2074 /**
2075 * Get MPLS label reading the config file
Sangho Shinfbc572c2014-10-02 16:37:05 -07002076 *
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002077 * @param dipid DPID of the switch
Sangho Shineb083032014-09-22 16:11:34 -07002078 * @return MPLS label for the switch
2079 */
Sangho Shin43cee112014-09-25 16:43:34 -07002080 private String getMplsLabel(String dpid) {
Sangho Shineb083032014-09-22 16:11:34 -07002081
2082 String mplsLabel = null;
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002083 for (Switch sw : mutableTopology.getSwitches()) {
Sangho Shin43cee112014-09-25 16:43:34 -07002084 String dpidStr = sw.getDpid().toString();
2085 if (dpid.equals(dpidStr)) {
Sangho Shineb083032014-09-22 16:11:34 -07002086 mplsLabel = sw.getStringAttribute("nodeSid");
2087 break;
Sangho Shin1aa93542014-09-22 09:49:44 -07002088 }
2089 }
2090
Sangho Shineb083032014-09-22 16:11:34 -07002091 return mplsLabel;
Sangho Shin1aa93542014-09-22 09:49:44 -07002092 }
2093
Sangho Shineb083032014-09-22 16:11:34 -07002094 /**
Sangho Shin1aa93542014-09-22 09:49:44 -07002095 * The function checks if given IP matches to the given subnet mask
Sangho Shinfbc572c2014-10-02 16:37:05 -07002096 *
Sangho Shin1aa93542014-09-22 09:49:44 -07002097 * @param addr - subnet address to match
2098 * @param addr1 - IP address to check
2099 * @return true if the IP address matches to the subnet, otherwise false
2100 */
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002101 public boolean netMatch(String addr, String addr1) { // addr is subnet
2102 // address and addr1 is
2103 // ip address. Function
2104 // will return true, if
2105 // addr1 is within
2106 // addr(subnet)
Sangho Shin1aa93542014-09-22 09:49:44 -07002107
2108 String[] parts = addr.split("/");
2109 String ip = parts[0];
2110 int prefix;
2111
2112 if (parts.length < 2) {
2113 prefix = 0;
2114 } else {
2115 prefix = Integer.parseInt(parts[1]);
2116 }
2117
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002118 Inet4Address a = null;
2119 Inet4Address a1 = null;
Sangho Shin1aa93542014-09-22 09:49:44 -07002120 try {
2121 a = (Inet4Address) InetAddress.getByName(ip);
2122 a1 = (Inet4Address) InetAddress.getByName(addr1);
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002123 } catch (UnknownHostException e) {
2124 }
Sangho Shin1aa93542014-09-22 09:49:44 -07002125
2126 byte[] b = a.getAddress();
2127 int ipInt = ((b[0] & 0xFF) << 24) |
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002128 ((b[1] & 0xFF) << 16) |
2129 ((b[2] & 0xFF) << 8) |
2130 ((b[3] & 0xFF) << 0);
Sangho Shin1aa93542014-09-22 09:49:44 -07002131
2132 byte[] b1 = a1.getAddress();
2133 int ipInt1 = ((b1[0] & 0xFF) << 24) |
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002134 ((b1[1] & 0xFF) << 16) |
2135 ((b1[2] & 0xFF) << 8) |
2136 ((b1[3] & 0xFF) << 0);
Sangho Shin1aa93542014-09-22 09:49:44 -07002137
2138 int mask = ~((1 << (32 - prefix)) - 1);
2139
2140 if ((ipInt & mask) == (ipInt1 & mask)) {
2141 return true;
2142 }
2143 else {
2144 return false;
2145 }
2146 }
Sangho Shineb083032014-09-22 16:11:34 -07002147
Sangho Shinac5ee2b2014-09-28 21:27:20 -07002148 /**
2149 * Add a routing rule for the host
Sangho Shinfbc572c2014-10-02 16:37:05 -07002150 *
Sangho Shinac5ee2b2014-09-28 21:27:20 -07002151 * @param sw - Switch to add the rule
2152 * @param hostIpAddress Destination host IP address
2153 * @param hostMacAddress Destination host MAC address
2154 */
Sangho Shineb083032014-09-22 16:11:34 -07002155 public void addRouteToHost(Switch sw, int hostIpAddress, byte[] hostMacAddress) {
2156 ipHandler.addRouteToHost(sw, hostIpAddress, hostMacAddress);
Sangho Shineb083032014-09-22 16:11:34 -07002157 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -07002158
Sangho Shin463bee52014-09-29 15:14:43 -07002159 /**
2160 * Add IP packet to a buffer queue
Sangho Shinfbc572c2014-10-02 16:37:05 -07002161 *
Sangho Shin463bee52014-09-29 15:14:43 -07002162 * @param ipv4
2163 */
Sangho Shin7330c032014-10-20 10:34:51 -07002164 public void addPacketToPacketBuffer(IPv4 ipv4) {
Sangho Shin61535402014-10-01 11:37:14 -07002165 ipPacketQueue.add(ipv4);
Sangho Shin463bee52014-09-29 15:14:43 -07002166 }
2167
2168 /**
2169 * Retrieve all packets whose destination is the given address.
Sangho Shinfbc572c2014-10-02 16:37:05 -07002170 *
Sangho Shin463bee52014-09-29 15:14:43 -07002171 * @param destIp Destination address of packets to retrieve
2172 */
2173 public List<IPv4> getIpPacketFromQueue(byte[] destIp) {
2174
2175 List<IPv4> bufferedPackets = new ArrayList<IPv4>();
2176
Sangho Shin61535402014-10-01 11:37:14 -07002177 if (!ipPacketQueue.isEmpty()) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002178 for (IPv4 ip : ipPacketQueue) {
Sangho Shin61535402014-10-01 11:37:14 -07002179 int dest = ip.getDestinationAddress();
2180 IPv4Address ip1 = IPv4Address.of(dest);
2181 IPv4Address ip2 = IPv4Address.of(destIp);
2182 if (ip1.equals(ip2)) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002183 bufferedPackets.add((IPv4) (ipPacketQueue.poll()).clone());
Sangho Shin463bee52014-09-29 15:14:43 -07002184 }
2185 }
2186 }
2187
2188 return bufferedPackets;
2189 }
2190
Sangho Shin7330c032014-10-20 10:34:51 -07002191 /**
2192 * Get MAC address to known hosts
2193 *
2194 * @param destinationAddress IP address to get MAC address
2195 * @return MAC Address to given IP address
2196 */
2197 public byte[] getMacAddressFromIpAddress(int destinationAddress) {
2198
2199 // Can't we get the host IP address from the TopologyService ??
2200
2201 Iterator<ArpEntry> iterator = arpEntries.iterator();
2202
2203 IPv4Address ipAddress = IPv4Address.of(destinationAddress);
2204 byte[] ipAddressInByte = ipAddress.getBytes();
2205
2206 while (iterator.hasNext()) {
2207 ArpEntry arpEntry = iterator.next();
2208 byte[] address = arpEntry.targetIpAddress;
2209
2210 IPv4Address a = IPv4Address.of(address);
2211 IPv4Address b = IPv4Address.of(ipAddressInByte);
2212
2213 if (a.equals(b)) {
2214 log.debug("Found an arp entry");
2215 return arpEntry.targetMacAddress;
2216 }
2217 }
2218
2219 return null;
2220 }
2221
2222 /**
2223 * Send an ARP request via ArpHandler
2224 *
2225 * @param destinationAddress
2226 * @param sw
2227 * @param inPort
2228 *
2229 */
2230 public void sendArpRequest(Switch sw, int destinationAddress, Port inPort) {
2231 arpHandler.sendArpRequest(sw, destinationAddress, inPort);
2232 }
2233
Sangho Shin7330c032014-10-20 10:34:51 -07002234 // ************************************
2235 // Test functions
2236 // ************************************
2237
Sangho Shin55d00e12014-10-20 12:13:07 -07002238 private void runTest() {
2239
2240 if (testMode == POLICY_ADD1) {
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07002241 Integer[] routeArray = {101, 105, 110};
2242 /*List<Dpid> routeList = new ArrayList<Dpid>();
Sangho Shin55d00e12014-10-20 12:13:07 -07002243 for (int i = 0; i < routeArray.length; i++) {
2244 Dpid dpid = getSwitchFromNodeId(routeArray[i]).getDpid();
2245 routeList.add(dpid);
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07002246 }*/
Sangho Shin55d00e12014-10-20 12:13:07 -07002247
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07002248 if (createTunnel("1", Arrays.asList(routeArray))) {
Sangho Shin55d00e12014-10-20 12:13:07 -07002249 IPv4Net srcIp = new IPv4Net("10.0.1.1/24");
2250 IPv4Net dstIp = new IPv4Net("10.1.2.1/24");
2251
2252 log.debug("Set the policy 1");
Sangho Shine020cc32014-10-20 13:28:02 -07002253 this.createPolicy("1", null, null, Ethernet.TYPE_IPV4, srcIp,
Sangho Shin55d00e12014-10-20 12:13:07 -07002254 dstIp, IPv4.PROTOCOL_ICMP, (short)-1, (short)-1, 10000,
Sangho Shine020cc32014-10-20 13:28:02 -07002255 "1");
Sangho Shin55d00e12014-10-20 12:13:07 -07002256 testMode = POLICY_ADD2;
Sangho Shin4b46bcd2014-10-20 15:48:47 -07002257 testTask.reschedule(5, TimeUnit.SECONDS);
Sangho Shin55d00e12014-10-20 12:13:07 -07002258 }
2259 else {
2260 // retry it
2261 testTask.reschedule(5, TimeUnit.SECONDS);
2262 }
2263 }
2264 else if (testMode == POLICY_ADD2) {
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07002265 Integer[] routeArray = {101, 102, 103, 104, 105, 108, 110};
Sangho Shin55d00e12014-10-20 12:13:07 -07002266
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07002267 if (createTunnel("2", Arrays.asList(routeArray))) {
Sangho Shin55d00e12014-10-20 12:13:07 -07002268 IPv4Net srcIp = new IPv4Net("10.0.1.1/24");
2269 IPv4Net dstIp = new IPv4Net("10.1.2.1/24");
2270
2271 log.debug("Set the policy 2");
Sangho Shine020cc32014-10-20 13:28:02 -07002272 this.createPolicy("2", null, null, Ethernet.TYPE_IPV4, srcIp,
Sangho Shin55d00e12014-10-20 12:13:07 -07002273 dstIp, IPv4.PROTOCOL_ICMP, (short)-1, (short)-1, 20000,
Sangho Shine020cc32014-10-20 13:28:02 -07002274 "2");
Fahad Naeem Khan95aa4012014-10-21 14:07:00 -07002275 //testMode = POLICY_REMOVE2;
2276 //testTask.reschedule(5, TimeUnit.SECONDS);
Sangho Shin55d00e12014-10-20 12:13:07 -07002277 }
2278 else {
2279 log.debug("Retry it");
2280 testTask.reschedule(5, TimeUnit.SECONDS);
2281 }
2282 }
2283 else if (testMode == POLICY_REMOVE2){
2284 log.debug("Remove the policy 2");
Sangho Shine020cc32014-10-20 13:28:02 -07002285 this.removePolicy("2");
Sangho Shin55d00e12014-10-20 12:13:07 -07002286 testMode = POLICY_REMOVE1;
Sangho Shin4b46bcd2014-10-20 15:48:47 -07002287 testTask.reschedule(5, TimeUnit.SECONDS);
Sangho Shin55d00e12014-10-20 12:13:07 -07002288 }
2289 else if (testMode == POLICY_REMOVE1){
2290 log.debug("Remove the policy 1");
Sangho Shine020cc32014-10-20 13:28:02 -07002291 this.removePolicy("1");
Sangho Shin55d00e12014-10-20 12:13:07 -07002292
Sangho Shin4b46bcd2014-10-20 15:48:47 -07002293 testMode = TUNNEL_REMOVE1;
2294 testTask.reschedule(5, TimeUnit.SECONDS);
2295 }
2296 else if (testMode == TUNNEL_REMOVE1) {
2297 log.debug("Remove the tunnel 1");
2298 this.removeTunnel("1");
2299
2300 testMode = TUNNEL_REMOVE2;
2301 testTask.reschedule(5, TimeUnit.SECONDS);
2302 }
2303 else if (testMode == TUNNEL_REMOVE2) {
2304 log.debug("Remove the tunnel 2");
2305 this.removeTunnel("2");
2306 log.debug("The end of test");
2307 }
Sangho Shin55d00e12014-10-20 12:13:07 -07002308 }
Sangho Shin7330c032014-10-20 10:34:51 -07002309
2310 private void runTest1() {
2311
2312 String dpid1 = "00:00:00:00:00:00:00:01";
2313 String dpid2 = "00:00:00:00:00:00:00:0a";
2314 Switch srcSw = mutableTopology.getSwitch(new Dpid(dpid1));
2315 Switch dstSw = mutableTopology.getSwitch(new Dpid(dpid2));
2316
2317 if (srcSw == null || dstSw == null) {
2318 testTask.reschedule(1, TimeUnit.SECONDS);
2319 log.debug("Switch is gone. Reschedule the test");
2320 return;
2321 }
2322
2323 String[] routeArray = {"101", "102", "105", "108", "110"};
2324 List<String> routeList = new ArrayList<String>();
2325 for (int i = 0; i < routeArray.length; i++)
2326 routeList.add(routeArray[i]);
2327
2328 List<String> optimizedRoute = this.getOptimizedPath(srcSw, dstSw, routeList);
2329
2330 log.debug("Test set is {}", routeList.toString());
2331 log.debug("Result set is {}", optimizedRoute.toString());
2332
2333
2334 }
2335
2336 /**
2337 * print tunnel info - used only for debugging.
2338 * @param targetSw
2339 *
2340 * @param fwdSwDpids
2341 * @param ids
2342 * @param tunnelId
2343 */
Sangho Shin6471d202014-10-23 10:59:36 -07002344 private void printTunnelInfo(String targetSw, String tunnelId,
Sangho Shin7330c032014-10-20 10:34:51 -07002345 List<String> ids, NeighborSet ns) {
2346 StringBuilder logStr = new StringBuilder("In switch " +
Sangho Shin6471d202014-10-23 10:59:36 -07002347 targetSw + ", create a tunnel " + tunnelId + " " + " of push ");
Sangho Shin7330c032014-10-20 10:34:51 -07002348 for (String id: ids)
2349 logStr.append(id + "-");
2350 logStr.append(" output to ");
2351 for (Dpid dpid: ns.getDpids())
2352 logStr.append(dpid + " - ");
2353
2354 log.debug(logStr.toString());
2355
2356 }
2357
2358 /**
2359 * Debugging function to print out the Match Action Entry
2360 * @param sw13
2361 *
2362 * @param maEntry
2363 */
2364 private void printMatchActionOperationEntry(
2365 IOF13Switch sw13, MatchActionOperationEntry maEntry) {
2366
2367 StringBuilder logStr = new StringBuilder("In switch " + sw13.getId() + ", ");
2368
2369 MatchAction ma = maEntry.getTarget();
2370 Match m = ma.getMatch();
2371 List<Action> actions = ma.getActions();
2372
2373 if (m instanceof Ipv4Match) {
2374 logStr.append("If the IP matches with ");
2375 IPv4Net ip = ((Ipv4Match) m).getDestination();
2376 logStr.append(ip.toString());
2377 logStr.append(" then ");
2378 }
2379 else if (m instanceof MplsMatch) {
2380 logStr.append("If the MPLS label matches with ");
2381 int mplsLabel = ((MplsMatch) m).getMplsLabel();
2382 logStr.append(mplsLabel);
2383 logStr.append(" then ");
2384 }
2385 else if (m instanceof PacketMatch) {
2386 GroupAction ga = (GroupAction)actions.get(0);
2387 logStr.append("if the policy match is XXX then go to group " +
2388 ga.getGroupId());
2389 log.debug(logStr.toString());
2390 return;
2391 }
2392
2393 logStr.append(" do { ");
2394 for (Action action : actions) {
2395 if (action instanceof CopyTtlInAction) {
2396 logStr.append("copy ttl In, ");
2397 }
2398 else if (action instanceof CopyTtlOutAction) {
2399 logStr.append("copy ttl Out, ");
2400 }
2401 else if (action instanceof DecMplsTtlAction) {
2402 logStr.append("Dec MPLS TTL , ");
2403 }
2404 else if (action instanceof GroupAction) {
2405 logStr.append("Forward packet to < ");
2406 NeighborSet dpids = ((GroupAction) action).getDpids();
2407 logStr.append(dpids.toString() + ",");
2408
2409 }
2410 else if (action instanceof PopMplsAction) {
2411 logStr.append("Pop MPLS label, ");
2412 }
2413 else if (action instanceof PushMplsAction) {
2414 logStr.append("Push MPLS label, ");
2415 }
2416 else if (action instanceof SetMplsIdAction) {
2417 int id = ((SetMplsIdAction) action).getMplsId();
2418 logStr.append("Set MPLS ID as " + id + ", ");
2419 }
2420 }
2421
2422 log.debug(logStr.toString());
2423
2424 }
2425
Sangho Shin7330c032014-10-20 10:34:51 -07002426 // ************************************
2427 // Unused classes and functions
2428 // ************************************
2429
2430 /**
2431 * Temporary class to to keep ARP entry
2432 *
2433 */
2434 private class ArpEntry {
2435
2436 byte[] targetMacAddress;
2437 byte[] targetIpAddress;
2438
2439 private ArpEntry(byte[] macAddress, byte[] ipAddress) {
2440 this.targetMacAddress = macAddress;
2441 this.targetIpAddress = ipAddress;
2442 }
2443 }
2444
2445 /**
2446 * This class is used only for link recovery optimization in
2447 * modifyEcmpRoutingRules() function.
2448 * TODO: please remove if the optimization is not used at all
2449 */
2450 private class SwitchPair {
2451 private Switch src;
2452 private Switch dst;
2453
2454 public SwitchPair(Switch src, Switch dst) {
2455 this.src = src;
2456 this.dst = dst;
2457 }
2458
2459 public Switch getSource() {
2460 return src;
2461 }
2462
2463 public Switch getDestination() {
2464 return dst;
2465 }
2466 }
2467
2468 /**
2469 * Update ARP Cache using ARP packets It is used to set destination MAC
2470 * address to forward packets to known hosts. But, it will be replace with
2471 * Host information of Topology service later.
2472 *
2473 * @param arp APR packets to use for updating ARP entries
2474 */
2475 public void updateArpCache(ARP arp) {
2476
2477 ArpEntry arpEntry = new ArpEntry(arp.getSenderHardwareAddress(),
2478 arp.getSenderProtocolAddress());
2479 // TODO: Need to check the duplication
2480 arpEntries.add(arpEntry);
2481 }
2482
2483 /**
2484 * Modify the routing rules for the lost links
2485 * - Recompute the path if the link failed is included in the path
2486 * (including src and dest).
2487 *
2488 * @param newLink
2489 */
2490 private void modifyEcmpRoutingRules(LinkData linkRemoved) {
2491
2492 //HashMap<Switch, SwitchPair> linksToRecompute = new HashMap<Switch, SwitchPair>();
2493 Set<SwitchPair> linksToRecompute = new HashSet<SwitchPair>();
2494
2495 for (ECMPShortestPathGraph ecmpSPG : graphs.values()) {
2496 Switch rootSw = ecmpSPG.getRootSwitch();
2497 HashMap<Integer, HashMap<Switch, ArrayList<Path>>> paths =
2498 ecmpSPG.getCompleteLearnedSwitchesAndPaths();
2499 for (HashMap<Switch, ArrayList<Path>> p: paths.values()) {
2500 for (Switch destSw: p.keySet()) {
2501 ArrayList<Path> path = p.get(destSw);
2502 if (checkPath(path, linkRemoved)) {
2503 boolean found = false;
2504 for (SwitchPair pair: linksToRecompute) {
2505 if (pair.getSource().getDpid() == rootSw.getDpid() &&
2506 pair.getSource().getDpid() == destSw.getDpid()) {
2507 found = true;
2508 }
2509 }
2510 if (!found) {
2511 linksToRecompute.add(new SwitchPair(rootSw, destSw));
2512 }
2513 }
2514 }
2515 }
2516 }
2517
2518 // Recompute the path for the specific route
2519 for (SwitchPair pair: linksToRecompute) {
2520
2521 log.debug("Recompute path from {} to {}", pair.getSource(), pair.getDestination());
2522 // We need the following function for optimization
2523 //ECMPShortestPathGraph ecmpSPG =
2524 // new ECMPShortestPathGraph(pair.getSource(), pair.getDestination());
2525 ECMPShortestPathGraph ecmpSPG =
2526 new ECMPShortestPathGraph(pair.getSource());
2527 populateEcmpRoutingRulesForPath(pair.getSource(), ecmpSPG, true);
2528 }
2529 }
2530
2531 /**
2532 * Optimize the mpls label
2533 * The feature will be used only for policy of "avoid a specific switch".
2534 * Check route to each router in route backward.
2535 * If there is only one route to the router and the routers are included in
2536 * the route, remove the id from the path.
2537 * A-B-C-D-E => A-B-C-D-E -> A-E
2538 * | | => A-B-H-I -> A-I
Sangho Shin5b8f5452014-10-20 11:46:01 -07002539 * F-G-H-I => A-D-I > A-D-I
Sangho Shin7330c032014-10-20 10:34:51 -07002540 */
2541 private List<String> getOptimizedPath(Switch srcSw, Switch dstSw, List<String> route) {
2542
2543 List<String> optimizedPath = new ArrayList<String>();
2544 optimizedPath.addAll(route);
2545 ECMPShortestPathGraph ecmpSPG = new ECMPShortestPathGraph(srcSw);
2546
2547 HashMap<Integer, HashMap<Switch, ArrayList<Path>>> paths =
2548 ecmpSPG.getCompleteLearnedSwitchesAndPaths();
2549 for (HashMap<Switch, ArrayList<Path>> p: paths.values()) {
2550 for (Switch s: p.keySet()) {
2551 if (s.getDpid().toString().equals(dstSw.getDpid().toString())) {
2552 ArrayList<Path> ecmpPaths = p.get(s);
2553 if (ecmpPaths!= null && ecmpPaths.size() == 1) {
2554 for (Path path: ecmpPaths) {
2555 for (LinkData link: path) {
2556 String srcId = getMplsLabel(link.getSrc().getDpid().toString());
2557 String dstId = getMplsLabel(link.getSrc().getDpid().toString());
2558 if (optimizedPath.contains(srcId)) {
2559 optimizedPath.remove(srcId);
2560 }
2561 if (optimizedPath.contains(dstId)) {
2562 optimizedPath.remove(dstId);
2563 }
2564 }
2565 }
2566 }
2567 }
2568 }
2569 }
2570
2571 return optimizedPath;
2572
2573 }
2574
2575 /**
2576 * Check if the path is affected from the link removed
2577 *
2578 * @param path Path to check
2579 * @param linkRemoved link removed
2580 * @return true if the path contains the link removed
2581 */
2582 private boolean checkPath(ArrayList<Path> path, LinkData linkRemoved) {
2583
2584 for (Path ppp: path) {
2585 // TODO: need to check if this is a bidirectional or
2586 // unidirectional
2587 for (LinkData link: ppp) {
2588 if (link.getDst().getDpid().equals(linkRemoved.getDst().getDpid()) &&
2589 link.getSrc().getDpid().equals(linkRemoved.getSrc().getDpid()))
2590 return true;
2591 }
2592 }
2593
2594 return false;
2595 }
Sangho Shin15273b62014-10-16 22:22:05 -07002596
2597
Sangho Shin2f263692014-09-15 14:09:41 -07002598}