blob: 1b8a45000061258013d32492979ca295caf91f3a [file] [log] [blame]
Sangho Shin2f263692014-09-15 14:09:41 -07001package net.onrc.onos.apps.segmentrouting;
2
Sangho Shin9c0f4c32014-09-26 16:02:38 -07003import java.io.IOException;
Sangho Shin1aa93542014-09-22 09:49:44 -07004import java.net.Inet4Address;
5import java.net.InetAddress;
6import java.net.UnknownHostException;
Sangho Shin2f263692014-09-15 14:09:41 -07007import java.util.ArrayList;
8import java.util.Collection;
Srikanth Vavilapalli363f1dc2014-09-22 14:30:23 -07009import java.util.HashMap;
Sangho Shin5be3e532014-10-03 17:20:58 -070010import java.util.HashSet;
Sangho Shin2f263692014-09-15 14:09:41 -070011import java.util.Iterator;
12import java.util.List;
13import java.util.Map;
Sangho Shin5be3e532014-10-03 17:20:58 -070014import java.util.Set;
Sangho Shin61535402014-10-01 11:37:14 -070015import java.util.concurrent.ConcurrentLinkedQueue;
Sangho Shin11d4e0f2014-09-30 12:00:33 -070016import java.util.concurrent.ExecutionException;
Sangho Shin43cee112014-09-25 16:43:34 -070017import java.util.concurrent.ScheduledExecutorService;
18import java.util.concurrent.TimeUnit;
Sangho Shin11d4e0f2014-09-30 12:00:33 -070019import java.util.concurrent.TimeoutException;
Sangho Shin2f263692014-09-15 14:09:41 -070020
21import net.floodlightcontroller.core.IFloodlightProviderService;
Sangho Shin9c0f4c32014-09-26 16:02:38 -070022import net.floodlightcontroller.core.IOF13Switch;
Sangho Shin0df01982014-09-25 17:11:18 -070023import net.floodlightcontroller.core.IOF13Switch.NeighborSet;
Sangho Shin11d4e0f2014-09-30 12:00:33 -070024import net.floodlightcontroller.core.internal.OFBarrierReplyFuture;
Sangho Shin2f263692014-09-15 14:09:41 -070025import net.floodlightcontroller.core.module.FloodlightModuleContext;
26import net.floodlightcontroller.core.module.FloodlightModuleException;
27import net.floodlightcontroller.core.module.IFloodlightModule;
28import net.floodlightcontroller.core.module.IFloodlightService;
Sangho Shin43cee112014-09-25 16:43:34 -070029import net.floodlightcontroller.core.util.SingletonTask;
Sangho Shin7330c032014-10-20 10:34:51 -070030import net.floodlightcontroller.restserver.IRestApiService;
Sangho Shin43cee112014-09-25 16:43:34 -070031import net.floodlightcontroller.threadpool.IThreadPoolService;
Sangho Shin15273b62014-10-16 22:22:05 -070032import net.floodlightcontroller.util.MACAddress;
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070033import net.onrc.onos.api.packet.IPacketListener;
Sangho Shin2f263692014-09-15 14:09:41 -070034import net.onrc.onos.api.packet.IPacketService;
Fahad Naeem Khan4444b952014-10-18 22:30:50 -070035import net.onrc.onos.apps.segmentrouting.web.SegmentRoutingWebRoutable;
Sangho Shin2f263692014-09-15 14:09:41 -070036import net.onrc.onos.core.flowprogrammer.IFlowPusherService;
Sangho Shinfbc572c2014-10-02 16:37:05 -070037import net.onrc.onos.core.intent.Path;
Sangho Shin2f263692014-09-15 14:09:41 -070038import net.onrc.onos.core.main.config.IConfigInfoService;
Sangho Shin43cee112014-09-25 16:43:34 -070039import net.onrc.onos.core.matchaction.MatchAction;
40import net.onrc.onos.core.matchaction.MatchActionId;
41import net.onrc.onos.core.matchaction.MatchActionOperationEntry;
Sangho Shin5be3e532014-10-03 17:20:58 -070042import net.onrc.onos.core.matchaction.MatchActionOperations.Operator;
Sangho Shin43cee112014-09-25 16:43:34 -070043import net.onrc.onos.core.matchaction.action.Action;
44import net.onrc.onos.core.matchaction.action.CopyTtlInAction;
45import net.onrc.onos.core.matchaction.action.CopyTtlOutAction;
46import net.onrc.onos.core.matchaction.action.DecMplsTtlAction;
47import net.onrc.onos.core.matchaction.action.DecNwTtlAction;
48import net.onrc.onos.core.matchaction.action.GroupAction;
49import net.onrc.onos.core.matchaction.action.PopMplsAction;
50import net.onrc.onos.core.matchaction.action.PushMplsAction;
51import net.onrc.onos.core.matchaction.action.SetMplsIdAction;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -070052import net.onrc.onos.core.matchaction.match.Ipv4Match;
Sangho Shin43cee112014-09-25 16:43:34 -070053import net.onrc.onos.core.matchaction.match.Match;
54import net.onrc.onos.core.matchaction.match.MplsMatch;
Sangho Shin15273b62014-10-16 22:22:05 -070055import net.onrc.onos.core.matchaction.match.PacketMatch;
56import net.onrc.onos.core.matchaction.match.PacketMatchBuilder;
Sangho Shin2f263692014-09-15 14:09:41 -070057import net.onrc.onos.core.packet.ARP;
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070058import net.onrc.onos.core.packet.Ethernet;
59import net.onrc.onos.core.packet.IPv4;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070060import net.onrc.onos.core.topology.ITopologyListener;
Sangho Shin1aa93542014-09-22 09:49:44 -070061import net.onrc.onos.core.topology.ITopologyService;
Sangho Shinbce900e2014-10-07 17:13:23 -070062import net.onrc.onos.core.topology.Link;
Sangho Shinc8d2f592014-09-30 16:53:57 -070063import net.onrc.onos.core.topology.LinkData;
Sangho Shinbce900e2014-10-07 17:13:23 -070064import net.onrc.onos.core.topology.MastershipData;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070065import net.onrc.onos.core.topology.MutableTopology;
Sangho Shineb083032014-09-22 16:11:34 -070066import net.onrc.onos.core.topology.Port;
Sangho Shinc8d2f592014-09-30 16:53:57 -070067import net.onrc.onos.core.topology.PortData;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070068import net.onrc.onos.core.topology.Switch;
Sangho Shin5be3e532014-10-03 17:20:58 -070069import net.onrc.onos.core.topology.SwitchData;
Sangho Shin1aa93542014-09-22 09:49:44 -070070import net.onrc.onos.core.topology.TopologyEvents;
Srikanth Vavilapalli363f1dc2014-09-22 14:30:23 -070071import net.onrc.onos.core.util.Dpid;
Sangho Shin43cee112014-09-25 16:43:34 -070072import net.onrc.onos.core.util.IPv4Net;
73import net.onrc.onos.core.util.SwitchPort;
Sangho Shin2f263692014-09-15 14:09:41 -070074
Sangho Shin43cee112014-09-25 16:43:34 -070075import org.json.JSONArray;
76import org.json.JSONException;
Saurav Dasa962a692014-10-17 14:52:38 -070077import org.projectfloodlight.openflow.protocol.OFBarrierReply;
Saurav Dasbc594a42014-09-25 20:13:50 -070078import org.projectfloodlight.openflow.types.EthType;
Sangho Shin2f263692014-09-15 14:09:41 -070079import org.projectfloodlight.openflow.types.IPv4Address;
80import org.slf4j.Logger;
81import org.slf4j.LoggerFactory;
82
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070083public class SegmentRoutingManager implements IFloodlightModule,
Srikanth Vavilapalli8c49db72014-10-20 13:35:08 -070084 ITopologyListener, IPacketListener, ISegmentRoutingService {
Sangho Shin2f263692014-09-15 14:09:41 -070085
86 private static final Logger log = LoggerFactory
87 .getLogger(SegmentRoutingManager.class);
Sangho Shin23f898d2014-10-13 16:54:00 -070088
Fahad Naeem Khan5b558f22014-10-16 10:35:20 -070089 private ITopologyService topologyService;
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070090 private IPacketService packetService;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070091 private MutableTopology mutableTopology;
Sangho Shin61535402014-10-01 11:37:14 -070092 private ConcurrentLinkedQueue<IPv4> ipPacketQueue;
Fahad Naeem Khan4444b952014-10-18 22:30:50 -070093 private IRestApiService restApi;
Sangho Shin2f263692014-09-15 14:09:41 -070094 private List<ArpEntry> arpEntries;
Sangho Shineb083032014-09-22 16:11:34 -070095 private ArpHandler arpHandler;
96 private GenericIpHandler ipHandler;
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070097 private IcmpHandler icmpHandler;
Sangho Shin43cee112014-09-25 16:43:34 -070098 private IThreadPoolService threadPool;
99 private SingletonTask discoveryTask;
Sangho Shin23f898d2014-10-13 16:54:00 -0700100 private SingletonTask linkAddTask;
Sangho Shin15273b62014-10-16 22:22:05 -0700101 private SingletonTask testTask;
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700102 private IFloodlightProviderService floodlightProvider;
Sangho Shin2f263692014-09-15 14:09:41 -0700103
Sangho Shinfbc572c2014-10-02 16:37:05 -0700104 private HashMap<Switch, ECMPShortestPathGraph> graphs;
Sangho Shin23f898d2014-10-13 16:54:00 -0700105 private HashMap<String, LinkData> linksDown;
106 private HashMap<String, LinkData> linksToAdd;
Sangho Shin5be3e532014-10-03 17:20:58 -0700107 private ConcurrentLinkedQueue<TopologyEvents> topologyEventQueue;
Sangho Shine020cc32014-10-20 13:28:02 -0700108 private HashMap<String, PolicyInfo> policyTable;
Sangho Shin81655442014-10-20 14:22:46 -0700109 private HashMap<String, TunnelInfo> tunnelTable;
Sangho Shin5b8f5452014-10-20 11:46:01 -0700110
111 private int testMode = 0;
112
Sangho Shinbce900e2014-10-07 17:13:23 -0700113
114 private int numOfEvents = 0;
115 private int numOfEventProcess = 0;
116 private int numOfPopulation = 0;
Sangho Shin99918bd2014-10-08 15:52:35 -0700117 private long matchActionId = 0L;
Sangho Shin23f898d2014-10-13 16:54:00 -0700118 private final int DELAY_TO_ADD_LINK = 10;
Sangho Shin15273b62014-10-16 22:22:05 -0700119 private final int MAX_NUM_LABELS = 3;
Sangho Shinfbc572c2014-10-02 16:37:05 -0700120
Sangho Shin5b8f5452014-10-20 11:46:01 -0700121
122 private final int POLICY_ADD1 = 1;
123 private final int POLICY_ADD2 = 2;
124 private final int POLICY_REMOVE1 = 3;
125 private final int POLICY_REMOVE2 = 4;
Sangho Shin4b46bcd2014-10-20 15:48:47 -0700126 private final int TUNNEL_REMOVE1 = 5;
127 private final int TUNNEL_REMOVE2 = 6;
Sangho Shin5b8f5452014-10-20 11:46:01 -0700128
129
Sangho Shin7330c032014-10-20 10:34:51 -0700130 // ************************************
131 // IFloodlightModule implementation
132 // ************************************
133
Sangho Shin2f263692014-09-15 14:09:41 -0700134 @Override
135 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Srikanth Vavilapalli8c49db72014-10-20 13:35:08 -0700136 Collection<Class<? extends IFloodlightService>> l = new ArrayList<>();
137 l.add(ISegmentRoutingService.class);
138 return l;
Sangho Shin2f263692014-09-15 14:09:41 -0700139 }
140
141 @Override
142 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Srikanth Vavilapalli8c49db72014-10-20 13:35:08 -0700143 Map<Class<? extends IFloodlightService>, IFloodlightService> m = new HashMap<>();
144 m.put(ISegmentRoutingService.class, this);
145 return m;
Sangho Shin2f263692014-09-15 14:09:41 -0700146 }
147
148 @Override
149 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
150 Collection<Class<? extends IFloodlightService>> l = new ArrayList<Class<? extends IFloodlightService>>();
151
152 l.add(IFloodlightProviderService.class);
153 l.add(IConfigInfoService.class);
154 l.add(ITopologyService.class);
155 l.add(IPacketService.class);
156 l.add(IFlowPusherService.class);
157 l.add(ITopologyService.class);
Fahad Naeem Khan4444b952014-10-18 22:30:50 -0700158 l.add(IRestApiService.class);
Sangho Shin2f263692014-09-15 14:09:41 -0700159
160 return l;
161
162 }
163
164 @Override
165 public void init(FloodlightModuleContext context) throws FloodlightModuleException {
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700166 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Sangho Shineb083032014-09-22 16:11:34 -0700167 arpHandler = new ArpHandler(context, this);
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700168 icmpHandler = new IcmpHandler(context, this);
Sangho Shineb083032014-09-22 16:11:34 -0700169 ipHandler = new GenericIpHandler(context, this);
Sangho Shin2f263692014-09-15 14:09:41 -0700170 arpEntries = new ArrayList<ArpEntry>();
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700171 topologyService = context.getServiceImpl(ITopologyService.class);
Sangho Shin43cee112014-09-25 16:43:34 -0700172 threadPool = context.getServiceImpl(IThreadPoolService.class);
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700173 mutableTopology = topologyService.getTopology();
Sangho Shin61535402014-10-01 11:37:14 -0700174 ipPacketQueue = new ConcurrentLinkedQueue<IPv4>();
Sangho Shinfbc572c2014-10-02 16:37:05 -0700175 graphs = new HashMap<Switch, ECMPShortestPathGraph>();
Sangho Shin23f898d2014-10-13 16:54:00 -0700176 linksDown = new HashMap<String, LinkData>();
177 linksToAdd = new HashMap<String, LinkData>();
Sangho Shin5be3e532014-10-03 17:20:58 -0700178 topologyEventQueue = new ConcurrentLinkedQueue<TopologyEvents>();
Sangho Shin15273b62014-10-16 22:22:05 -0700179 packetService = context.getServiceImpl(IPacketService.class);
Fahad Naeem Khan4444b952014-10-18 22:30:50 -0700180 restApi = context.getServiceImpl(IRestApiService.class);
Sangho Shine020cc32014-10-20 13:28:02 -0700181 policyTable = new HashMap<String, PolicyInfo>();
Sangho Shin81655442014-10-20 14:22:46 -0700182 tunnelTable = new HashMap<String, TunnelInfo>();
Sangho Shin2f263692014-09-15 14:09:41 -0700183
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700184 packetService.registerPacketListener(this);
Sangho Shin15273b62014-10-16 22:22:05 -0700185 topologyService.addListener(this, false);
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700186
Sangho Shin99918bd2014-10-08 15:52:35 -0700187
Sangho Shin2f263692014-09-15 14:09:41 -0700188 }
189
190 @Override
191 public void startUp(FloodlightModuleContext context) throws FloodlightModuleException {
Sangho Shinc8d2f592014-09-30 16:53:57 -0700192 ScheduledExecutorService ses = threadPool.getScheduledExecutor();
Fahad Naeem Khan4444b952014-10-18 22:30:50 -0700193 restApi.addRestletRoutable(new SegmentRoutingWebRoutable());
Sangho Shin2f263692014-09-15 14:09:41 -0700194
Sangho Shinc8d2f592014-09-30 16:53:57 -0700195 discoveryTask = new SingletonTask(ses, new Runnable() {
196 @Override
197 public void run() {
Sangho Shin5be3e532014-10-03 17:20:58 -0700198 handleTopologyChangeEvents();
Sangho Shinc8d2f592014-09-30 16:53:57 -0700199 }
200 });
Sangho Shin23f898d2014-10-13 16:54:00 -0700201
202 linkAddTask = new SingletonTask(ses, new Runnable() {
203 @Override
204 public void run() {
205 delayedAddLink();
206 }
207 });
208
Sangho Shin15273b62014-10-16 22:22:05 -0700209 testTask = new SingletonTask(ses, new Runnable() {
210 @Override
211 public void run() {
212 runTest();
213 }
214 });
215
Sangho Shin5b8f5452014-10-20 11:46:01 -0700216 testMode = POLICY_ADD1;
Sangho Shin00bd9462014-10-20 17:00:54 -0700217 //testTask.reschedule(20, TimeUnit.SECONDS);
Sangho Shin2f263692014-09-15 14:09:41 -0700218 }
219
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700220 @Override
221 public void receive(Switch sw, Port inPort, Ethernet payload) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700222 if (payload.getEtherType() == Ethernet.TYPE_ARP)
223 arpHandler.processPacketIn(sw, inPort, payload);
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700224 if (payload.getEtherType() == Ethernet.TYPE_IPV4) {
Sangho Shin7330c032014-10-20 10:34:51 -0700225 addPacketToPacketBuffer((IPv4) payload.getPayload());
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700226 if (((IPv4) payload.getPayload()).getProtocol() == IPv4.PROTOCOL_ICMP)
227 icmpHandler.processPacketIn(sw, inPort, payload);
228 else
229 ipHandler.processPacketIn(sw, inPort, payload);
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700230 }
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700231 else {
232 log.debug("{}", payload.toString());
233 }
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700234 }
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700235
Sangho Shin2f263692014-09-15 14:09:41 -0700236
Sangho Shin7330c032014-10-20 10:34:51 -0700237 // ************************************
238 // Topology event handlers
239 // ************************************
Sangho Shineb083032014-09-22 16:11:34 -0700240
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700241 /**
242 * Topology events that have been generated.
Sangho Shinfbc572c2014-10-02 16:37:05 -0700243 *
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700244 * @param topologyEvents the generated Topology Events
245 * @see TopologyEvents
246 */
247 public void topologyEvents(TopologyEvents topologyEvents)
248 {
Sangho Shin5be3e532014-10-03 17:20:58 -0700249 topologyEventQueue.add(topologyEvents);
Sangho Shinbce900e2014-10-07 17:13:23 -0700250 discoveryTask.reschedule(100, TimeUnit.MILLISECONDS);
Sangho Shin5be3e532014-10-03 17:20:58 -0700251 }
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700252
Sangho Shin23f898d2014-10-13 16:54:00 -0700253 /**
254 * Process the multiple topology events with some delay (100MS at most for now)
255 *
256 */
Sangho Shin5be3e532014-10-03 17:20:58 -0700257 private void handleTopologyChangeEvents() {
Sangho Shinbce900e2014-10-07 17:13:23 -0700258 numOfEventProcess ++;
259
Sangho Shin51625342014-10-17 09:30:48 -0700260 Collection<LinkData> linkEntriesAddedAll = new ArrayList<LinkData>();
261 Collection<PortData> portEntriesAddedAll = new ArrayList<PortData>();
262 Collection<PortData> portEntriesRemovedAll = new ArrayList<PortData>();
263 Collection<LinkData> linkEntriesRemovedAll = new ArrayList<LinkData>();
264 Collection<SwitchData> switchAddedAll = new ArrayList<SwitchData>();
265 Collection<SwitchData> switchRemovedAll = new ArrayList<SwitchData>();
266 Collection<MastershipData> mastershipRemovedAll = new ArrayList<MastershipData>();
Sangho Shinbce900e2014-10-07 17:13:23 -0700267
Sangho Shin5be3e532014-10-03 17:20:58 -0700268 while (!topologyEventQueue.isEmpty()) {
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700269 // We should handle the events in the order of when they happen
270 // TODO: We need to simulate the final results of multiple events
271 // and shoot only the final state.
272 // Ex: link s1-s2 down, link s1-s2 up --> Do nothing
273 // Ex: ink s1-s2 up, s1-p1,p2 down --> link s1-s2 down
Sangho Shin51625342014-10-17 09:30:48 -0700274
Sangho Shin5be3e532014-10-03 17:20:58 -0700275 TopologyEvents topologyEvents = topologyEventQueue.poll();
Sangho Shin51625342014-10-17 09:30:48 -0700276
277 Collection<LinkData> linkEntriesAdded = topologyEvents.getAddedLinkDataEntries();
278 Collection<PortData> portEntriesAdded = topologyEvents.getAddedPortDataEntries();
279 Collection<PortData> portEntriesRemoved = topologyEvents.getRemovedPortDataEntries();
280 Collection<LinkData> linkEntriesRemoved = topologyEvents.getRemovedLinkDataEntries();
281 Collection<SwitchData> switchAdded = topologyEvents.getAddedSwitchDataEntries();
282 Collection<SwitchData> switchRemoved = topologyEvents.getRemovedSwitchDataEntries();
283 Collection<MastershipData> mastershipRemoved = topologyEvents.getRemovedMastershipDataEntries();
284
285 linkEntriesAddedAll.addAll(linkEntriesAdded);
286 portEntriesAddedAll.addAll(portEntriesAdded);
287 portEntriesRemovedAll.addAll(portEntriesRemoved);
288 linkEntriesRemovedAll.addAll(linkEntriesRemoved);
289 switchAddedAll.addAll(switchAdded);
290 switchRemovedAll.addAll(switchRemoved);
291 mastershipRemovedAll.addAll(mastershipRemoved);
Sangho Shinbce900e2014-10-07 17:13:23 -0700292 numOfEvents++;
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700293
294 if (!portEntriesRemoved.isEmpty()) {
295 processPortRemoval(portEntriesRemoved);
296 }
297
298 if (!linkEntriesRemoved.isEmpty()) {
299 processLinkRemoval(linkEntriesRemoved);
300 }
301
302 if (!switchRemoved.isEmpty()) {
303 processSwitchRemoved(switchRemoved);
304 }
305
306 if (!mastershipRemoved.isEmpty()) {
Sangho Shin23f898d2014-10-13 16:54:00 -0700307 log.debug("Mastership is removed. Check if ports are down also.");
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700308 }
309
310 if (!linkEntriesAdded.isEmpty()) {
Sangho Shin23f898d2014-10-13 16:54:00 -0700311 processLinkAdd(linkEntriesAdded, false);
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700312 }
313
314 if (!portEntriesAdded.isEmpty()) {
315 processPortAdd(portEntriesAdded);
316 }
317
318 if (!switchAdded.isEmpty()) {
319 processSwitchAdd(switchAdded);
320 }
Sangho Shin51625342014-10-17 09:30:48 -0700321
Sangho Shinbce900e2014-10-07 17:13:23 -0700322 }
323
Sangho Shin23f898d2014-10-13 16:54:00 -0700324 // TODO: 100ms is enough to check both mastership removed events
325 // and the port removed events? What if the PORT_STATUS packets comes late?
Sangho Shin51625342014-10-17 09:30:48 -0700326 if (!mastershipRemovedAll.isEmpty()) {
327 if (portEntriesRemovedAll.isEmpty()) {
Saurav Das82e62972014-10-16 14:53:57 -0700328 log.debug("Just mastership is removed. Do not do anthing.");
Sangho Shin23f898d2014-10-13 16:54:00 -0700329 }
330 else {
331 HashMap<String, MastershipData> mastershipToRemove =
332 new HashMap<String, MastershipData>();
Sangho Shin51625342014-10-17 09:30:48 -0700333 for (MastershipData ms: mastershipRemovedAll) {
334 for (PortData port: portEntriesRemovedAll) {
Sangho Shin23f898d2014-10-13 16:54:00 -0700335 // TODO: check ALL ports of the switch are dead ..
336 if (port.getDpid().equals(ms.getDpid())) {
337 mastershipToRemove.put(ms.getDpid().toString(), ms);
338 }
339 }
340 log.debug("Swtich {} is really down.", ms.getDpid());
341 }
342 processMastershipRemoved(mastershipToRemove.values());
343 }
344 }
345
Sangho Shinbce900e2014-10-07 17:13:23 -0700346 log.debug("num events {}, num of process {}, "
347 + "num of Population {}", numOfEvents, numOfEventProcess,
348 numOfPopulation);
349 }
350
351 /**
Sangho Shin99918bd2014-10-08 15:52:35 -0700352 * Process the SwitchAdded events from topologyMananger.
353 * It does nothing. When a switch is added, then link will be added too.
354 * LinkAdded event will handle process all re-computation.
355 *
356 * @param switchAdded
357 */
358 private void processSwitchAdd(Collection<SwitchData> switchAdded) {
359
360 }
361
362 /**
Sangho Shinbce900e2014-10-07 17:13:23 -0700363 * Remove all ports connected to the switch removed
364 *
365 * @param mastershipRemoved master switch info removed
366 */
367 private void processMastershipRemoved(Collection<MastershipData>
368 mastershipRemoved) {
369 for (MastershipData mastership: mastershipRemoved) {
370 Switch sw = mutableTopology.getSwitch(mastership.getDpid());
371 for (Link link: sw.getOutgoingLinks()) {
372 Port dstPort = link.getDstPort();
373 IOF13Switch dstSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
374 getSwId(dstPort.getDpid().toString()));
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700375 if (dstSw != null) {
376 dstSw.removePortFromGroups(dstPort.getNumber());
377 log.debug("MasterSwitch {} is gone: remove port {}", sw.getDpid(), dstPort);
378 }
Sangho Shinbce900e2014-10-07 17:13:23 -0700379 }
Sangho Shin61535402014-10-01 11:37:14 -0700380 }
Sangho Shin23f898d2014-10-13 16:54:00 -0700381
382 linksToAdd.clear();
383 linksDown.clear();
Sangho Shin61535402014-10-01 11:37:14 -0700384 }
Sangho Shinc8d2f592014-09-30 16:53:57 -0700385
Sangho Shinbce900e2014-10-07 17:13:23 -0700386 /**
387 * Remove all ports connected to the switch removed
388 *
389 * @param switchRemoved Switch removed
390 */
Sangho Shin5be3e532014-10-03 17:20:58 -0700391 private void processSwitchRemoved(Collection<SwitchData> switchRemoved) {
Sangho Shin23f898d2014-10-13 16:54:00 -0700392 log.debug("SwitchRemoved event occurred !!!");
Sangho Shin5be3e532014-10-03 17:20:58 -0700393 }
394
Sangho Shin61535402014-10-01 11:37:14 -0700395 /**
Sangho Shin99918bd2014-10-08 15:52:35 -0700396 * Report ports added to driver
Sangho Shinfbc572c2014-10-02 16:37:05 -0700397 *
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700398 * @param portEntries
399 */
400 private void processPortAdd(Collection<PortData> portEntries) {
Sangho Shin99918bd2014-10-08 15:52:35 -0700401 // TODO: do we need to add ports with delay?
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700402 for (PortData port : portEntries) {
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700403 Dpid dpid = port.getDpid();
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700404
Sangho Shinfbc572c2014-10-02 16:37:05 -0700405 IOF13Switch sw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700406 getSwId(port.getDpid().toString()));
Sangho Shin815af0c2014-10-10 13:05:45 -0700407 if (sw != null) {
Sangho Shin721ca042014-10-09 13:03:40 -0700408 sw.addPortToGroups(port.getPortNumber());
Sangho Shin15273b62014-10-16 22:22:05 -0700409 //log.debug("Add port {} to switch {}", port, dpid);
Sangho Shin815af0c2014-10-10 13:05:45 -0700410 }
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700411 }
412 }
413
414 /**
415 * Reports ports of new links to driver and recalculate ECMP SPG
Sangho Shin23f898d2014-10-13 16:54:00 -0700416 * If the link to add was removed before, then we just schedule the add link
417 * event and do not recompute the path now.
Sangho Shinfbc572c2014-10-02 16:37:05 -0700418 *
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700419 * @param linkEntries
420 */
Sangho Shin23f898d2014-10-13 16:54:00 -0700421 private void processLinkAdd(Collection<LinkData> linkEntries, boolean delayed) {
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700422
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700423 for (LinkData link : linkEntries) {
Sangho Shin5be3e532014-10-03 17:20:58 -0700424
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700425 SwitchPort srcPort = link.getSrc();
426 SwitchPort dstPort = link.getDst();
427
Sangho Shin23f898d2014-10-13 16:54:00 -0700428 String key = srcPort.getDpid().toString() +
429 dstPort.getDpid().toString();
430 if (!delayed) {
431 if (linksDown.containsKey(key)) {
432 linksToAdd.put(key, link);
433 linksDown.remove(key);
434 linkAddTask.reschedule(DELAY_TO_ADD_LINK, TimeUnit.SECONDS);
435 log.debug("Add link {} with 5 sec delay", link);
436 // TODO: What if we have multiple events of add link:
437 // one is new link add, the other one is link up for
438 // broken link? ECMPSPG function cannot deal with it for now
439 return;
440 }
441 }
442 else {
443 if (linksDown.containsKey(key)) {
444 linksToAdd.remove(key);
445 log.debug("Do not add the link {}: it is down again!", link);
446 return;
447 }
448 }
449
Sangho Shinfbc572c2014-10-02 16:37:05 -0700450 IOF13Switch srcSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700451 getSwId(srcPort.getDpid().toString()));
Sangho Shinfbc572c2014-10-02 16:37:05 -0700452 IOF13Switch dstSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700453 getSwId(dstPort.getDpid().toString()));
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700454
Sangho Shin815af0c2014-10-10 13:05:45 -0700455 if ((srcSw == null) || (dstSw == null))
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700456 continue;
457
458 srcSw.addPortToGroups(srcPort.getPortNumber());
459 dstSw.addPortToGroups(dstPort.getPortNumber());
Sangho Shin5be3e532014-10-03 17:20:58 -0700460
Sangho Shin15273b62014-10-16 22:22:05 -0700461 //log.debug("Add a link port {} to switch {} to add link {}", srcPort, srcSw,
462 // link);
463 //log.debug("Add a link port {} to switch {} to add link {}", dstPort, dstSw,
464 // link);
Sangho Shin815af0c2014-10-10 13:05:45 -0700465
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700466 }
Sangho Shinbce900e2014-10-07 17:13:23 -0700467 populateEcmpRoutingRules(false);
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700468 }
469
470 /**
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700471 * Check if all links are gone b/w the two switches. If all links are gone,
472 * then we need to recalculate the path. Otherwise, just report link failure
473 * to the driver.
Sangho Shinfbc572c2014-10-02 16:37:05 -0700474 *
Sangho Shin61535402014-10-01 11:37:14 -0700475 * @param linkEntries
476 */
477 private void processLinkRemoval(Collection<LinkData> linkEntries) {
Sangho Shinbce900e2014-10-07 17:13:23 -0700478 boolean recomputationRequired = false;
479
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700480 for (LinkData link : linkEntries) {
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700481 SwitchPort srcPort = link.getSrc();
482 SwitchPort dstPort = link.getDst();
Sangho Shinc8d2f592014-09-30 16:53:57 -0700483
Sangho Shinfbc572c2014-10-02 16:37:05 -0700484 IOF13Switch srcSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700485 getSwId(srcPort.getDpid().toString()));
Sangho Shinfbc572c2014-10-02 16:37:05 -0700486 IOF13Switch dstSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700487 getSwId(dstPort.getDpid().toString()));
Sangho Shin815af0c2014-10-10 13:05:45 -0700488 if ((srcSw == null) || (dstSw == null))
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700489 /* If this link is not between two switches, ignore it */
490 continue;
Sangho Shin23f898d2014-10-13 16:54:00 -0700491
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700492 srcSw.removePortFromGroups(srcPort.getPortNumber());
493 dstSw.removePortFromGroups(dstPort.getPortNumber());
Sangho Shin815af0c2014-10-10 13:05:45 -0700494 log.debug("Remove port {} from switch {}", srcPort, srcSw);
495 log.debug("Remove port {} from switch {}", dstPort, dstSw);
496
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700497 Switch srcSwitch = mutableTopology.getSwitch(srcPort.getDpid());
498 if (srcSwitch.getLinkToNeighbor(dstPort.getDpid()) == null) {
Sangho Shinbce900e2014-10-07 17:13:23 -0700499 // TODO: it is only for debugging purpose.
Sangho Shin99918bd2014-10-08 15:52:35 -0700500 // We just need to call populateEcmpRoutingRules() and return;
Sangho Shinbce900e2014-10-07 17:13:23 -0700501 recomputationRequired = true;
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700502 log.debug("All links are gone b/w {} and {}", srcPort.getDpid(),
Sangho Shin5be3e532014-10-03 17:20:58 -0700503 dstPort.getDpid());
Sangho Shinc8d2f592014-09-30 16:53:57 -0700504 }
Sangho Shin23f898d2014-10-13 16:54:00 -0700505
506 String key = link.getSrc().getDpid().toString()+
507 link.getDst().getDpid().toString();
508 if (!linksDown.containsKey(key)) {
509 linksDown.put(key, link);
510 }
Sangho Shinc8d2f592014-09-30 16:53:57 -0700511 }
Sangho Shinbce900e2014-10-07 17:13:23 -0700512
513 if (recomputationRequired)
514 populateEcmpRoutingRules(false);
Sangho Shin61535402014-10-01 11:37:14 -0700515 }
Sangho Shinc8d2f592014-09-30 16:53:57 -0700516
Sangho Shin61535402014-10-01 11:37:14 -0700517 /**
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700518 * report ports removed to the driver immediately
Sangho Shinfbc572c2014-10-02 16:37:05 -0700519 *
Sangho Shin61535402014-10-01 11:37:14 -0700520 * @param portEntries
521 */
522 private void processPortRemoval(Collection<PortData> portEntries) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700523 for (PortData port : portEntries) {
Sangho Shin61535402014-10-01 11:37:14 -0700524 Dpid dpid = port.getDpid();
Sangho Shin61535402014-10-01 11:37:14 -0700525
Sangho Shinfbc572c2014-10-02 16:37:05 -0700526 IOF13Switch sw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin61535402014-10-01 11:37:14 -0700527 getSwId(port.getDpid().toString()));
Sangho Shin815af0c2014-10-10 13:05:45 -0700528 if (sw != null) {
Sangho Shinfbc572c2014-10-02 16:37:05 -0700529 sw.removePortFromGroups(port.getPortNumber());
Sangho Shin815af0c2014-10-10 13:05:45 -0700530 log.debug("Remove port {} from switch {}", port, dpid);
531 }
Sangho Shin61535402014-10-01 11:37:14 -0700532 }
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700533 }
Sangho Shin1aa93542014-09-22 09:49:44 -0700534
535 /**
Sangho Shin7330c032014-10-20 10:34:51 -0700536 * Add the link immediately
537 * The function is scheduled when link add event happens and called
538 * DELAY_TO_ADD_LINK seconds after the event to avoid link flip-flop.
539 */
540 private void delayedAddLink() {
541
542 processLinkAdd(linksToAdd.values(), true);
543
544 }
545
546
547 // ************************************
548 // ECMP shorted path routing functions
549 // ************************************
550
551 /**
Sangho Shin43cee112014-09-25 16:43:34 -0700552 * Populate routing rules walking through the ECMP shortest paths
Sangho Shinfbc572c2014-10-02 16:37:05 -0700553 *
Sangho Shin99918bd2014-10-08 15:52:35 -0700554 * @param modified if true, it "modifies" the rules
Sangho Shin1aa93542014-09-22 09:49:44 -0700555 */
Sangho Shin5be3e532014-10-03 17:20:58 -0700556 private void populateEcmpRoutingRules(boolean modified) {
557 graphs.clear();
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700558 Iterable<Switch> switches = mutableTopology.getSwitches();
Sangho Shin43cee112014-09-25 16:43:34 -0700559 for (Switch sw : switches) {
560 ECMPShortestPathGraph ecmpSPG = new ECMPShortestPathGraph(sw);
Sangho Shinfbc572c2014-10-02 16:37:05 -0700561 graphs.put(sw, ecmpSPG);
562 //log.debug("ECMPShortestPathGraph is computed for switch {}",
563 // HexString.toHexString(sw.getDpid().value()));
Sangho Shin5be3e532014-10-03 17:20:58 -0700564 populateEcmpRoutingRulesForPath(sw, ecmpSPG, modified);
Sangho Shinfbc572c2014-10-02 16:37:05 -0700565 }
Sangho Shinbce900e2014-10-07 17:13:23 -0700566 numOfPopulation++;
Sangho Shinfbc572c2014-10-02 16:37:05 -0700567 }
Sangho Shin1aa93542014-09-22 09:49:44 -0700568
Sangho Shin99918bd2014-10-08 15:52:35 -0700569 /**
570 * populate routing rules to forward packets from the switch given to
571 * all other switches.
572 *
573 * @param sw source switch
574 * @param ecmpSPG shortest path from the the source switch to all others
575 * @param modified modification flag
576 */
Sangho Shinfbc572c2014-10-02 16:37:05 -0700577 private void populateEcmpRoutingRulesForPath(Switch sw,
Sangho Shin5be3e532014-10-03 17:20:58 -0700578 ECMPShortestPathGraph ecmpSPG, boolean modified) {
Sangho Shin43cee112014-09-25 16:43:34 -0700579
Sangho Shinfbc572c2014-10-02 16:37:05 -0700580 HashMap<Integer, HashMap<Switch, ArrayList<ArrayList<Dpid>>>> switchVia =
581 ecmpSPG.getAllLearnedSwitchesAndVia();
582 for (Integer itrIdx : switchVia.keySet()) {
583 //log.debug("ECMPShortestPathGraph:Switches learned in "
584 // + "Iteration{} from switch {}:",
585 // itrIdx,
586 // HexString.toHexString(sw.getDpid().value()));
587 HashMap<Switch, ArrayList<ArrayList<Dpid>>> swViaMap =
588 switchVia.get(itrIdx);
589 for (Switch targetSw : swViaMap.keySet()) {
Sangho Shin5be3e532014-10-03 17:20:58 -0700590 //log.debug("ECMPShortestPathGraph:****switch {} via:",
591 // HexString.toHexString(targetSw.getDpid().value()));
Sangho Shinfbc572c2014-10-02 16:37:05 -0700592 String destSw = sw.getDpid().toString();
593 List<String> fwdToSw = new ArrayList<String>();
594
Sangho Shinfbc572c2014-10-02 16:37:05 -0700595 for (ArrayList<Dpid> via : swViaMap.get(targetSw)) {
Sangho Shin5be3e532014-10-03 17:20:58 -0700596 //log.debug("ECMPShortestPathGraph:******{}) {}", ++i, via);
Sangho Shinfbc572c2014-10-02 16:37:05 -0700597 if (via.isEmpty()) {
598 fwdToSw.add(destSw);
Sangho Shin43cee112014-09-25 16:43:34 -0700599 }
Sangho Shinfbc572c2014-10-02 16:37:05 -0700600 else {
601 fwdToSw.add(via.get(0).toString());
602 }
Sangho Shin43cee112014-09-25 16:43:34 -0700603 }
Sangho Shin5be3e532014-10-03 17:20:58 -0700604 setRoutingRule(targetSw, destSw, fwdToSw, modified);
Sangho Shineb083032014-09-22 16:11:34 -0700605 }
Sangho Shinfbc572c2014-10-02 16:37:05 -0700606
607 // Send Barrier Message and make sure all rules are set
608 // before we set the rules to next routers
Saurav Dasa962a692014-10-17 14:52:38 -0700609 // TODO: barriers to all switches in this update stage
Sangho Shinfbc572c2014-10-02 16:37:05 -0700610 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
611 getSwId(sw.getDpid().toString()));
Sangho Shin5be3e532014-10-03 17:20:58 -0700612 if (sw13 != null) {
Saurav Dasa962a692014-10-17 14:52:38 -0700613 OFBarrierReplyFuture replyFuture = null;
Sangho Shin5be3e532014-10-03 17:20:58 -0700614 try {
Saurav Dasa962a692014-10-17 14:52:38 -0700615 replyFuture = sw13.sendBarrier();
Sangho Shin5be3e532014-10-03 17:20:58 -0700616 } catch (IOException e) {
Saurav Dasa962a692014-10-17 14:52:38 -0700617 log.error("Error sending barrier request to switch {}",
618 sw13.getId(), e.getCause());
Sangho Shin5be3e532014-10-03 17:20:58 -0700619 }
Saurav Dasa962a692014-10-17 14:52:38 -0700620 OFBarrierReply br = null;
621 try {
622 br = replyFuture.get(2, TimeUnit.SECONDS);
623 } catch (TimeoutException | InterruptedException | ExecutionException e) {
624 // XXX for some reason these exceptions are not being thrown
625 }
626 if (br == null) {
627 log.warn("Did not receive barrier-reply from {}", sw13.getId());
628 // XXX take corrective action
629 }
630
Sangho Shinfbc572c2014-10-02 16:37:05 -0700631 }
632 }
633
634 }
635
Sangho Shinfbc572c2014-10-02 16:37:05 -0700636 /**
637 *
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700638 * Set routing rules in targetSw {forward packets to fwdToSw switches in
639 * order to send packets to destSw} - If the target switch is an edge router
640 * and final destnation switch is also an edge router, then set IP
641 * forwarding rules to subnets - If only the target switch is an edge
642 * router, then set IP forwarding rule to the transit router loopback IP
643 * address - If the target is a transit router, then just set the MPLS
644 * forwarding rule
Sangho Shinfbc572c2014-10-02 16:37:05 -0700645 *
Sangho Shin43cee112014-09-25 16:43:34 -0700646 * @param targetSw Switch to set the rules
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700647 * @param destSw Final destination switches
Sangho Shin43cee112014-09-25 16:43:34 -0700648 * @param fwdToSw next hop switches
649 */
Sangho Shin99918bd2014-10-08 15:52:35 -0700650 private void setRoutingRule(Switch targetSw, String destSw,
651 List<String> fwdToSw, boolean modified) {
Sangho Shin43cee112014-09-25 16:43:34 -0700652
Sangho Shin43cee112014-09-25 16:43:34 -0700653 if (fwdToSw.isEmpty()) {
654 fwdToSw.add(destSw);
655 }
656
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700657 // if both target SW and dest SW are an edge router, then set IP table
Sangho Shin43cee112014-09-25 16:43:34 -0700658 if (IsEdgeRouter(targetSw.getDpid().toString()) &&
659 IsEdgeRouter(destSw)) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700660 // We assume that there is at least one transit router b/w edge
661 // routers
Sangho Shin43cee112014-09-25 16:43:34 -0700662 Switch destSwitch = mutableTopology.getSwitch(new Dpid(destSw));
663 String subnets = destSwitch.getStringAttribute("subnets");
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700664 setIpTableRouterSubnet(targetSw, subnets, getMplsLabel(destSw)
Sangho Shin5be3e532014-10-03 17:20:58 -0700665 , fwdToSw, modified);
Sangho Shin43cee112014-09-25 16:43:34 -0700666
Sangho Shin43cee112014-09-25 16:43:34 -0700667 String routerIp = destSwitch.getStringAttribute("routerIp");
Sangho Shin5be3e532014-10-03 17:20:58 -0700668 setIpTableRouter(targetSw, routerIp, getMplsLabel(destSw), fwdToSw,
669 null, modified);
Sangho Shin721ca042014-10-09 13:03:40 -0700670 // Edge router can be a transit router
671 setMplsTable(targetSw, getMplsLabel(destSw), fwdToSw, modified);
Sangho Shin43cee112014-09-25 16:43:34 -0700672 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700673 // Only if the target switch is the edge router, then set the IP rules
Sangho Shin43cee112014-09-25 16:43:34 -0700674 else if (IsEdgeRouter(targetSw.getDpid().toString())) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700675 // We assume that there is at least one transit router b/w edge
676 // routers
Sangho Shin43cee112014-09-25 16:43:34 -0700677 Switch destSwitch = mutableTopology.getSwitch(new Dpid(destSw));
678 String routerIp = destSwitch.getStringAttribute("routerIp");
Sangho Shin5be3e532014-10-03 17:20:58 -0700679 setIpTableRouter(targetSw, routerIp, getMplsLabel(destSw), fwdToSw,
680 null, modified);
Sangho Shin721ca042014-10-09 13:03:40 -0700681 // Edge router can be a transit router
682 setMplsTable(targetSw, getMplsLabel(destSw), fwdToSw, modified);
Sangho Shin43cee112014-09-25 16:43:34 -0700683 }
684 // if it is a transit router, then set rules in the MPLS table
685 else {
Sangho Shin5be3e532014-10-03 17:20:58 -0700686 setMplsTable(targetSw, getMplsLabel(destSw), fwdToSw, modified);
Sangho Shin43cee112014-09-25 16:43:34 -0700687 }
688
689 }
690
Sangho Shinfbc572c2014-10-02 16:37:05 -0700691 /**
692 * Set IP forwarding rule to the gateway of each subnet of switches
693 *
694 * @param targetSw Switch to set rules
695 * @param subnets subnet information
696 * @param mplsLabel destination MPLS label
697 * @param fwdToSw router to forward packets to
698 */
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700699 private void setIpTableRouterSubnet(Switch targetSw, String subnets,
Sangho Shin5be3e532014-10-03 17:20:58 -0700700 String mplsLabel, List<String> fwdToSw, boolean modified) {
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700701
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700702 Collection<MatchActionOperationEntry> entries =
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700703 new ArrayList<MatchActionOperationEntry>();
704
705 try {
706 JSONArray arry = new JSONArray(subnets);
707 for (int i = 0; i < arry.length(); i++) {
708 String subnetIp = (String) arry.getJSONObject(i).get("subnetIp");
Sangho Shin5be3e532014-10-03 17:20:58 -0700709 setIpTableRouter(targetSw, subnetIp, mplsLabel, fwdToSw, entries,
710 modified);
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700711 }
712 } catch (JSONException e) {
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700713 e.printStackTrace();
714 }
715
716 if (!entries.isEmpty()) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700717 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700718 getSwId(targetSw.getDpid().toString()));
719
Sangho Shin721ca042014-10-09 13:03:40 -0700720 if (sw13 != null) {
721 try {
722 sw13.pushFlows(entries);
723 } catch (IOException e) {
724 e.printStackTrace();
725 }
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700726 }
727 }
728
729 }
730
Sangho Shin43cee112014-09-25 16:43:34 -0700731 /**
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700732 * Set IP forwarding rule - If the destination is the next hop, then do not
733 * push MPLS, just decrease the NW TTL - Otherwise, push MPLS label and set
734 * the MPLS ID
Sangho Shinfbc572c2014-10-02 16:37:05 -0700735 *
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700736 * @param sw target switch to set rules
Sangho Shin43cee112014-09-25 16:43:34 -0700737 * @param subnetIp Match IP address
738 * @param mplsLabel MPLS label of final destination router
739 * @param fwdToSws next hop routers
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700740 * @param entries
Sangho Shin43cee112014-09-25 16:43:34 -0700741 */
742 private void setIpTableRouter(Switch sw, String subnetIp, String mplsLabel,
Sangho Shin5be3e532014-10-03 17:20:58 -0700743 List<String> fwdToSws, Collection<MatchActionOperationEntry> entries,
744 boolean modified) {
Sangho Shin43cee112014-09-25 16:43:34 -0700745
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700746 Ipv4Match ipMatch = new Ipv4Match(subnetIp);
Sangho Shin43cee112014-09-25 16:43:34 -0700747 List<Action> actions = new ArrayList<>();
Sangho Shin721ca042014-10-09 13:03:40 -0700748 GroupAction groupAction = new GroupAction();
Sangho Shin43cee112014-09-25 16:43:34 -0700749
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700750 // If destination SW is the same as the fwd SW, then do not push MPLS
751 // label
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700752 if (fwdToSws.size() > 1) {
Sangho Shin43cee112014-09-25 16:43:34 -0700753 PushMplsAction pushMplsAction = new PushMplsAction();
754 SetMplsIdAction setIdAction = new SetMplsIdAction(Integer.parseInt(mplsLabel));
755 CopyTtlOutAction copyTtlOutAction = new CopyTtlOutAction();
Sangho Shin463bee52014-09-29 15:14:43 -0700756 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
Sangho Shin43cee112014-09-25 16:43:34 -0700757
Sangho Shin62ce5c12014-10-08 16:24:40 -0700758 //actions.add(pushMplsAction);
759 //actions.add(copyTtlOutAction);
760 //actions.add(decMplsTtlAction);
Saurav Das82e62972014-10-16 14:53:57 -0700761 // actions.add(setIdAction);
Sangho Shin721ca042014-10-09 13:03:40 -0700762 groupAction.setEdgeLabel(Integer.parseInt(mplsLabel));
Sangho Shin43cee112014-09-25 16:43:34 -0700763 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700764 else {
765 String fwdToSw = fwdToSws.get(0);
766 if (getMplsLabel(fwdToSw).equals(mplsLabel)) {
767 DecNwTtlAction decTtlAction = new DecNwTtlAction(1);
768 actions.add(decTtlAction);
769 }
770 else {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700771 SetMplsIdAction setIdAction = new SetMplsIdAction(
772 Integer.parseInt(mplsLabel));
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700773 CopyTtlOutAction copyTtlOutAction = new CopyTtlOutAction();
Sangho Shin463bee52014-09-29 15:14:43 -0700774 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700775
Sangho Shin62ce5c12014-10-08 16:24:40 -0700776 //actions.add(pushMplsAction);
777 //actions.add(copyTtlOutAction);
778 //actions.add(decMplsTtlAction);
Saurav Das82e62972014-10-16 14:53:57 -0700779 // actions.add(setIdAction);
Sangho Shin721ca042014-10-09 13:03:40 -0700780 groupAction.setEdgeLabel(Integer.parseInt(mplsLabel));
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700781 }
782 }
Sangho Shin43cee112014-09-25 16:43:34 -0700783
Sangho Shin43cee112014-09-25 16:43:34 -0700784 for (String fwdSw : fwdToSws) {
785 groupAction.addSwitch(new Dpid(fwdSw));
786 }
787 actions.add(groupAction);
788
Sangho Shin99918bd2014-10-08 15:52:35 -0700789 MatchAction matchAction = new MatchAction(new MatchActionId(matchActionId++),
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700790 new SwitchPort((long) 0, (short) 0), ipMatch, actions);
Sangho Shin43cee112014-09-25 16:43:34 -0700791
Sangho Shin5be3e532014-10-03 17:20:58 -0700792 Operator operator = null;
793 if (modified)
794 operator = Operator.MODIFY;
795 else
796 operator = Operator.ADD;
797
Sangho Shin43cee112014-09-25 16:43:34 -0700798 MatchActionOperationEntry maEntry =
Sangho Shin5be3e532014-10-03 17:20:58 -0700799 new MatchActionOperationEntry(operator, matchAction);
Sangho Shin43cee112014-09-25 16:43:34 -0700800
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700801 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700802 getSwId(sw.getDpid().toString()));
803
Sangho Shin5be3e532014-10-03 17:20:58 -0700804 if (sw13 != null) {
805 try {
Sangho Shinbce900e2014-10-07 17:13:23 -0700806 //printMatchActionOperationEntry(sw, maEntry);
Sangho Shin5be3e532014-10-03 17:20:58 -0700807 if (entries != null)
808 entries.add(maEntry);
809 else
810 sw13.pushFlow(maEntry);
811 } catch (IOException e) {
812 e.printStackTrace();
813 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700814 }
815
Sangho Shin43cee112014-09-25 16:43:34 -0700816 }
817
Sangho Shinac5ee2b2014-09-28 21:27:20 -0700818 /**
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700819 * Set MPLS forwarding rules to MPLS table
820 * </p>
821 * If the destination is the same as the next hop to forward packets then,
822 * pop the MPLS label according to PHP rule. Here, if BoS is set, then
823 * copy TTL In and decrement NW TTL. Otherwise, it just decrement the MPLS
824 * TTL of the another MPLS header.
825 * If the next hop is not the destination, just forward packets to next
826 * hops using Group action.
Sangho Shinfbc572c2014-10-02 16:37:05 -0700827 *
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700828 * @param sw Switch to set the rules
Sangho Shin43cee112014-09-25 16:43:34 -0700829 * @param mplsLabel destination MPLS label
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700830 * @param fwdSws next hop switches
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700831 * */
Sangho Shin5be3e532014-10-03 17:20:58 -0700832 private void setMplsTable(Switch sw, String mplsLabel, List<String> fwdSws,
833 boolean modified) {
Sangho Shin463bee52014-09-29 15:14:43 -0700834
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700835 if (fwdSws.isEmpty())
836 return;
Sangho Shin43cee112014-09-25 16:43:34 -0700837
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700838 Collection<MatchActionOperationEntry> maEntries =
839 new ArrayList<MatchActionOperationEntry>();
840 String fwdSw1 = fwdSws.get(0);
Sangho Shin43cee112014-09-25 16:43:34 -0700841
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700842 if (fwdSws.size() == 1 && mplsLabel.equals(getMplsLabel(fwdSw1))) {
843 // One rule for Bos = 1
844 MplsMatch mplsMatch = new MplsMatch(Integer.parseInt(mplsLabel), true);
845 List<Action> actions = new ArrayList<Action>();
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700846
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700847 PopMplsAction popAction = new PopMplsAction(EthType.IPv4);
848 CopyTtlInAction copyTtlInAction = new CopyTtlInAction();
849 DecNwTtlAction decNwTtlAction = new DecNwTtlAction(1);
850
851 actions.add(copyTtlInAction);
852 actions.add(popAction);
853 actions.add(decNwTtlAction);
854
855 GroupAction groupAction = new GroupAction();
856 groupAction.addSwitch(new Dpid(fwdSw1));
857 actions.add(groupAction);
858
859 MatchAction matchAction = new MatchAction(new MatchActionId(matchActionId++),
860 new SwitchPort((long) 0, (short) 0), mplsMatch, actions);
861 Operator operator = Operator.ADD;
862 MatchActionOperationEntry maEntry =
863 new MatchActionOperationEntry(operator, matchAction);
864 maEntries.add(maEntry);
865
866 // One rule for Bos = 0
Sangho Shin23f898d2014-10-13 16:54:00 -0700867 MplsMatch mplsMatchBos = new MplsMatch(Integer.parseInt(mplsLabel), false);
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700868 List<Action> actionsBos = new ArrayList<Action>();
Sangho Shin15273b62014-10-16 22:22:05 -0700869 PopMplsAction popActionBos = new PopMplsAction(EthType.MPLS_UNICAST);
870 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
871
872 actionsBos.add(copyTtlInAction);
873 actionsBos.add(popActionBos);
874 actionsBos.add(decMplsTtlAction);
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700875 actionsBos.add(groupAction);
876
877 MatchAction matchActionBos = new MatchAction(new MatchActionId(matchActionId++),
878 new SwitchPort((long) 0, (short) 0), mplsMatchBos, actionsBos);
879 MatchActionOperationEntry maEntryBos =
880 new MatchActionOperationEntry(operator, matchActionBos);
881 maEntries.add(maEntryBos);
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700882 }
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700883 else {
884 MplsMatch mplsMatch = new MplsMatch(Integer.parseInt(mplsLabel), false);
885 List<Action> actions = new ArrayList<Action>();
Sangho Shin43cee112014-09-25 16:43:34 -0700886
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700887 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
888 actions.add(decMplsTtlAction);
Sangho Shin43cee112014-09-25 16:43:34 -0700889
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700890 GroupAction groupAction = new GroupAction();
891 for (String fwdSw : fwdSws)
892 groupAction.addSwitch(new Dpid(fwdSw));
893 actions.add(groupAction);
Sangho Shin5be3e532014-10-03 17:20:58 -0700894
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700895 MatchAction matchAction = new MatchAction(new MatchActionId(
896 matchActionId++),
897 new SwitchPort((long) 0, (short) 0), mplsMatch, actions);
898 Operator operator = Operator.ADD;
899 MatchActionOperationEntry maEntry =
900 new MatchActionOperationEntry(operator, matchAction);
901 maEntries.add(maEntry);
Sangho Shine2e9bcd2014-10-13 15:14:18 -0700902
903 // BoS = 1
904 MplsMatch mplsMatchBoS = new MplsMatch(Integer.parseInt(mplsLabel), true);
905 List<Action> actionsBoS = new ArrayList<Action>();
906
907 DecMplsTtlAction decMplsTtlActionBoS = new DecMplsTtlAction(1);
908 actionsBoS.add(decMplsTtlActionBoS);
909
910 GroupAction groupActionBoS = new GroupAction();
911 for (String fwdSw : fwdSws)
912 groupActionBoS.addSwitch(new Dpid(fwdSw));
913 actionsBoS.add(groupActionBoS);
914
915 MatchAction matchActionBos = new MatchAction(new MatchActionId(
916 matchActionId++),
917 new SwitchPort((long) 0, (short) 0), mplsMatchBoS, actionsBoS);
918 MatchActionOperationEntry maEntryBoS =
919 new MatchActionOperationEntry(operator, matchActionBos);
920 maEntries.add(maEntryBoS);
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700921 }
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700922 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700923 getSwId(sw.getDpid().toString()));
924
Sangho Shin5be3e532014-10-03 17:20:58 -0700925 if (sw13 != null) {
926 try {
Sangho Shinbce900e2014-10-07 17:13:23 -0700927 //printMatchActionOperationEntry(sw, maEntry);
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700928 sw13.pushFlows(maEntries);
Sangho Shin5be3e532014-10-03 17:20:58 -0700929 } catch (IOException e) {
930 e.printStackTrace();
931 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700932 }
Sangho Shin43cee112014-09-25 16:43:34 -0700933 }
934
Sangho Shin7330c032014-10-20 10:34:51 -0700935
936 // ************************************
937 // Policy routing classes and functions
938 // ************************************
939
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -0700940 public class PolicyInfo {
Sangho Shin5b8f5452014-10-20 11:46:01 -0700941
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -0700942 private String policyId;
943 private PacketMatch match;
944 private int priority;
945 private String tunnelId;
Sangho Shin5b8f5452014-10-20 11:46:01 -0700946
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -0700947 public PolicyInfo(String pid, PacketMatch match, int priority, String tid) {
Sangho Shin5b8f5452014-10-20 11:46:01 -0700948 this.policyId = pid;
949 this.match = match;
950 this.priority = priority;
951 this.tunnelId = tid;
952 }
953 }
954
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -0700955 public class TunnelInfo {
956 private String tunnelId;
957 private List<Dpid> dpids;
958 private List<TunnelRouteInfo> routes;
Sangho Shin81655442014-10-20 14:22:46 -0700959
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -0700960 public TunnelInfo(String tid, List<Dpid> dpids, List<TunnelRouteInfo> routes) {
Sangho Shin81655442014-10-20 14:22:46 -0700961 this.tunnelId = tid;
962 this.dpids = dpids;
963 this.routes = routes;
964 }
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -0700965 public String getTunnelId(){
966 return this.tunnelId;
967 }
968 public List<Dpid> getDpids(){
969 return this.dpids;
970 }
971 public List<TunnelRouteInfo> getRoutes(){
972 return this.routes;
973 }
Sangho Shin81655442014-10-20 14:22:46 -0700974 }
975
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -0700976 public class TunnelRouteInfo {
Sangho Shin7330c032014-10-20 10:34:51 -0700977
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -0700978 private String srcSwDpid;
979 private List<Dpid> fwdSwDpids;
980 private List<String> route;
Sangho Shin7330c032014-10-20 10:34:51 -0700981
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -0700982 public TunnelRouteInfo() {
Sangho Shin7330c032014-10-20 10:34:51 -0700983 fwdSwDpids = new ArrayList<Dpid>();
984 route = new ArrayList<String>();
985 }
986
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -0700987 private void setSrcDpid(String dpid) {
Sangho Shin7330c032014-10-20 10:34:51 -0700988 this.srcSwDpid = dpid;
989 }
990
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -0700991 private void setFwdSwDpid(List<Dpid> dpid) {
Sangho Shin7330c032014-10-20 10:34:51 -0700992 this.fwdSwDpids = dpid;
993 }
994
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -0700995 private void addRoute(String id) {
Sangho Shin7330c032014-10-20 10:34:51 -0700996 route.add(id);
997 }
998
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -0700999 private void setRoute(List<String> r) {
Sangho Shin7330c032014-10-20 10:34:51 -07001000 this.route = r;
1001 }
1002
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001003 public String getSrcSwDpid() {
Sangho Shin7330c032014-10-20 10:34:51 -07001004 return this.srcSwDpid;
1005 }
1006
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001007 public List<Dpid> getFwdSwDpid() {
Sangho Shin7330c032014-10-20 10:34:51 -07001008 return this.fwdSwDpids;
1009 }
1010
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001011 public List<String> getRoute() {
Sangho Shin7330c032014-10-20 10:34:51 -07001012 return this.route;
1013 }
1014 }
1015
Sangho Shin15273b62014-10-16 22:22:05 -07001016 /**
Sangho Shin81655442014-10-20 14:22:46 -07001017 * Return the Tunnel table
1018 *
1019 * @return collection of TunnelInfo
1020 */
1021 public Collection<TunnelInfo> getTunnelTable() {
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001022 return this.tunnelTable.values();
Sangho Shin81655442014-10-20 14:22:46 -07001023 }
1024
1025 /**
Sangho Shin15273b62014-10-16 22:22:05 -07001026 * Create a tunnel for policy routing
1027 * It delivers the node IDs of tunnels to driver.
1028 * Split the node IDs if number of IDs exceeds the limit for stitching.
1029 *
1030 * @param tunnelId Node IDs for the tunnel
1031 * @param Ids tunnel ID
1032 */
Sangho Shine020cc32014-10-20 13:28:02 -07001033 public boolean createTunnel(String tunnelId, List<Dpid> dpids) {
Sangho Shin15273b62014-10-16 22:22:05 -07001034
Sangho Shin55d00e12014-10-20 12:13:07 -07001035 if (dpids.isEmpty() || dpids.size() < 2) {
Sangho Shin15273b62014-10-16 22:22:05 -07001036 log.debug("Wrong tunnel information");
1037 return false;
1038 }
1039
Sangho Shin55d00e12014-10-20 12:13:07 -07001040 List<String> Ids = new ArrayList<String>();
1041 for (Dpid dpid: dpids) {
1042 Ids.add(getMplsLabel(dpid.toString()));
1043 }
1044
Sangho Shin81655442014-10-20 14:22:46 -07001045 List<TunnelRouteInfo> stitchingRule = getStitchingRule(Ids);
Sangho Shin15273b62014-10-16 22:22:05 -07001046 if (stitchingRule == null) {
1047 log.debug("Failed to get the policy rule.");
1048 return false;
1049 }
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001050 //HashMap<String, Integer> switchGroupPair = new HashMap<String, Integer>();
Sangho Shin81655442014-10-20 14:22:46 -07001051 for (TunnelRouteInfo route: stitchingRule) {
Sangho Shin15273b62014-10-16 22:22:05 -07001052
1053 IOF13Switch targetSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin81655442014-10-20 14:22:46 -07001054 getSwId(route.srcSwDpid));
Sangho Shin15273b62014-10-16 22:22:05 -07001055
1056 if (targetSw == null) {
Sangho Shin81655442014-10-20 14:22:46 -07001057 log.debug("Switch {} is gone.", route.srcSwDpid);
Sangho Shin15273b62014-10-16 22:22:05 -07001058 return false;
1059 }
1060
1061 NeighborSet ns = new NeighborSet();
1062 for (Dpid dpid: route.getFwdSwDpid())
1063 ns.addDpid(dpid);
1064
1065 printTunnelInfo(targetSw, tunnelId, route.getRoute(), ns);
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001066 targetSw.createTunnel(tunnelId, route.getRoute(), ns);
1067 //switchGroupPair.put(route.srcSwDpid.toString(), groupId);
Sangho Shin15273b62014-10-16 22:22:05 -07001068
1069 }
1070
Sangho Shin81655442014-10-20 14:22:46 -07001071 //tunnelGroupMap.put(tunnelId, switchGroupPair);
1072 TunnelInfo tunnelInfo = new TunnelInfo(tunnelId, dpids, stitchingRule);
1073 tunnelTable.put(tunnelId, tunnelInfo);
Sangho Shin15273b62014-10-16 22:22:05 -07001074
1075 return true;
1076 }
1077
1078 /**
Sangho Shine020cc32014-10-20 13:28:02 -07001079 * Return router DPIDs for the tunnel
1080 *
1081 * @param tid tunnel ID
1082 * @return List of DPID
1083 */
1084 public List<Dpid> getTunnelInfo(String tid) {
Sangho Shin81655442014-10-20 14:22:46 -07001085 TunnelInfo tunnelInfo = tunnelTable.get(tid);
1086 return tunnelInfo.dpids;
1087
Sangho Shine020cc32014-10-20 13:28:02 -07001088 }
1089
1090 /**
Sangho Shin15273b62014-10-16 22:22:05 -07001091 * Set policy table for policy routing
1092 *
1093 * @param sw
1094 * @param mplsLabel
Sangho Shin306633a2014-10-20 14:26:55 -07001095 * @return
Sangho Shin15273b62014-10-16 22:22:05 -07001096 */
Sangho Shin306633a2014-10-20 14:26:55 -07001097 public boolean createPolicy(String pid, MACAddress srcMac, MACAddress dstMac,
Sangho Shin15273b62014-10-16 22:22:05 -07001098 Short etherType, IPv4Net srcIp, IPv4Net dstIp, Byte ipProto,
Sangho Shine020cc32014-10-20 13:28:02 -07001099 Short srcTcpPort, Short dstTcpPort, int priority, String tid) {
Sangho Shin15273b62014-10-16 22:22:05 -07001100
Sangho Shin81655442014-10-20 14:22:46 -07001101 //HashMap<String, TunnelRouteInfo> routeInfo = stitchInfo.get(tid);
1102 //HashMap<String, Integer> switchGroupPair = tunnelGroupMap.get(tid);
Sangho Shin5b8f5452014-10-20 11:46:01 -07001103
1104 PacketMatchBuilder packetBuilder = new PacketMatchBuilder();
1105
1106 if (srcMac != null)
1107 packetBuilder.setSrcMac(srcMac);
1108 if (dstMac != null)
1109 packetBuilder.setDstMac(dstMac);
1110 if (etherType != null)
1111 packetBuilder.setEtherType(etherType);
1112 if (srcIp != null)
1113 packetBuilder.setSrcIp(srcIp.address(), srcIp.prefixLen());
1114 if (dstIp != null)
1115 packetBuilder.setDstIp(dstIp.address(), dstIp.prefixLen());
1116 if (ipProto != null)
1117 packetBuilder.setIpProto(ipProto);
1118 if (srcTcpPort > 0)
1119 packetBuilder.setSrcTcpPort(srcTcpPort);
1120 if (dstTcpPort > 0)
1121 packetBuilder.setDstTcpPort(dstTcpPort);
1122 PacketMatch policyMatch = packetBuilder.build();
Sangho Shin81655442014-10-20 14:22:46 -07001123 TunnelInfo tunnelInfo = tunnelTable.get(tid);
1124 List<TunnelRouteInfo> routes = tunnelInfo.routes;
Sangho Shin5b8f5452014-10-20 11:46:01 -07001125
Sangho Shin81655442014-10-20 14:22:46 -07001126 for (TunnelRouteInfo route : routes) {
Sangho Shin15273b62014-10-16 22:22:05 -07001127 List<Action> actions = new ArrayList<>();
1128 GroupAction groupAction = new GroupAction();
Sangho Shin81655442014-10-20 14:22:46 -07001129 groupAction.setTunnelId(tid);
Sangho Shin15273b62014-10-16 22:22:05 -07001130 actions.add(groupAction);
1131
1132 MatchAction matchAction = new MatchAction(new MatchActionId(
1133 matchActionId++),
Sangho Shin5b8f5452014-10-20 11:46:01 -07001134 new SwitchPort((long) 0, (short) 0), policyMatch, priority,
1135 actions);
Sangho Shin15273b62014-10-16 22:22:05 -07001136 MatchActionOperationEntry maEntry =
1137 new MatchActionOperationEntry(Operator.ADD, matchAction);
1138
1139 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin81655442014-10-20 14:22:46 -07001140 getSwId(route.srcSwDpid));
Sangho Shin15273b62014-10-16 22:22:05 -07001141
1142 if (sw13 != null) {
1143 printMatchActionOperationEntry(sw13, maEntry);
1144 try {
1145 sw13.pushFlow(maEntry);
1146 } catch (IOException e) {
1147 e.printStackTrace();
Sangho Shin306633a2014-10-20 14:26:55 -07001148 return false;
Sangho Shin15273b62014-10-16 22:22:05 -07001149 }
1150 }
1151 }
Sangho Shin5b8f5452014-10-20 11:46:01 -07001152
1153 PolicyInfo policyInfo = new PolicyInfo(pid, policyMatch, priority, tid);
Sangho Shine020cc32014-10-20 13:28:02 -07001154 policyTable.put(pid, policyInfo);
Sangho Shin306633a2014-10-20 14:26:55 -07001155
1156 return true;
Sangho Shin15273b62014-10-16 22:22:05 -07001157 }
1158
1159 /**
Sangho Shin1ad7be02014-10-20 16:56:49 -07001160 * Split the nodes IDs into multiple tunnel if Segment Stitching is required.
1161 * We assume that the first node ID is the one of source router, and the last
1162 * node ID is that of the destination router.
Sangho Shin15273b62014-10-16 22:22:05 -07001163 *
Sangho Shin1ad7be02014-10-20 16:56:49 -07001164 * @param route list of node IDs
1165 * @return List of the TunnelRoutInfo
Sangho Shin15273b62014-10-16 22:22:05 -07001166 */
Sangho Shin81655442014-10-20 14:22:46 -07001167 private List<TunnelRouteInfo> getStitchingRule(List<String> route) {
Sangho Shin15273b62014-10-16 22:22:05 -07001168
1169 if (route.isEmpty() || route.size() < 2)
1170 return null;
1171
Sangho Shin81655442014-10-20 14:22:46 -07001172 List<TunnelRouteInfo> rules = new ArrayList<TunnelRouteInfo>();
Sangho Shin15273b62014-10-16 22:22:05 -07001173
1174 Switch srcSw = this.getSwitchFromNodeId(route.get(0));
1175 String srcDpid = srcSw.getDpid().toString();
1176
1177 if (route.size() <= MAX_NUM_LABELS+1) {
Sangho Shine020cc32014-10-20 13:28:02 -07001178 TunnelRouteInfo info = new TunnelRouteInfo();
Sangho Shin15273b62014-10-16 22:22:05 -07001179 info.setSrcDpid(srcSw.getDpid().toString());
1180 List<Dpid> fwdSwDpids = getForwardingSwitchForNodeId(srcSw, route.get(1));
1181 info.setFwdSwDpid(fwdSwDpids);
1182 route.remove(0);
1183 info.setRoute(route);
Sangho Shin81655442014-10-20 14:22:46 -07001184 rules.add(info);
Sangho Shin15273b62014-10-16 22:22:05 -07001185 return rules;
1186 }
1187
1188 int i = 0;
Sangho Shine020cc32014-10-20 13:28:02 -07001189 TunnelRouteInfo routeInfo = new TunnelRouteInfo();
Sangho Shin15273b62014-10-16 22:22:05 -07001190 boolean checkNeighbor = true;
1191
1192 for (String nodeId: route) {
Sangho Shin1ad7be02014-10-20 16:56:49 -07001193 // First node ID is always the source router
Sangho Shin15273b62014-10-16 22:22:05 -07001194 if (i == 0) {
1195 routeInfo.setSrcDpid(srcDpid);
1196 srcSw = getSwitchFromNodeId(nodeId);
1197 i++;
1198 }
1199 else if (i == 1) {
1200 if (checkNeighbor) {
1201 // Check if next node is the neighbor SW of the source SW
1202 List<Dpid> fwdSwDpids = getForwardingSwitchForNodeId(srcSw, nodeId);
1203 if (fwdSwDpids == null || fwdSwDpids.isEmpty()) {
1204 log.debug("There is no route from node {} to node {}", srcSw.getDpid(), nodeId);
1205 return null;
1206 }
1207 // If first Id is one of the neighbors, do not include it to route, but set it as a fwd SW.
1208 boolean match = false;
1209 for (Dpid dpid: fwdSwDpids) {
1210 if (getMplsLabel(dpid.toString()).toString().equals(nodeId)) {
1211 List<Dpid> fwdSws = new ArrayList<Dpid>();
1212 fwdSws.add(dpid);
1213 routeInfo.setFwdSwDpid(fwdSws);
1214 match = true;
1215 break;
1216 }
1217 }
1218 if (!match) {
1219 routeInfo.addRoute(nodeId);
1220 routeInfo.setFwdSwDpid(fwdSwDpids);
1221 i++;
1222 }
Sangho Shin1ad7be02014-10-20 16:56:49 -07001223 // we check only the next node ID of the source router
Sangho Shin15273b62014-10-16 22:22:05 -07001224 checkNeighbor = false;
1225 }
1226 else {
1227 routeInfo.addRoute(nodeId);
1228 i++;
1229 }
1230 }
1231 else {
1232 routeInfo.addRoute(nodeId);
1233 i++;
1234 }
1235
Sangho Shin1ad7be02014-10-20 16:56:49 -07001236 // If the number of labels reaches the limit, start over the procedure
Sangho Shin15273b62014-10-16 22:22:05 -07001237 if (i == MAX_NUM_LABELS+1) {
Sangho Shin81655442014-10-20 14:22:46 -07001238 rules.add(routeInfo);
Sangho Shine020cc32014-10-20 13:28:02 -07001239 routeInfo = new TunnelRouteInfo();
Sangho Shin15273b62014-10-16 22:22:05 -07001240 srcSw = getSwitchFromNodeId(nodeId);
1241 srcDpid = getSwitchFromNodeId(nodeId).getDpid().toString();
1242 routeInfo.setSrcDpid(srcDpid);
1243 i = 1;
1244 checkNeighbor = true;
1245 }
1246 }
1247
1248 if (i < MAX_NUM_LABELS+1) {
Sangho Shin81655442014-10-20 14:22:46 -07001249 rules.add(routeInfo);
Sangho Shin15273b62014-10-16 22:22:05 -07001250 }
1251
1252 return rules;
1253 }
1254
Sangho Shin5b8f5452014-10-20 11:46:01 -07001255 /**
1256 * Remove all policies applied to specific tunnel.
1257 *
1258 * @param srcMac
1259 * @param dstMac
1260 * @param etherType
1261 * @param srcIp
1262 * @param dstIp
1263 * @param ipProto
1264 * @param srcTcpPort
1265 * @param dstTcpPort
1266 * @param tid
Sangho Shin306633a2014-10-20 14:26:55 -07001267 * @return
Sangho Shin5b8f5452014-10-20 11:46:01 -07001268 */
Sangho Shin306633a2014-10-20 14:26:55 -07001269 public boolean removePolicy(String pid) {
Sangho Shine020cc32014-10-20 13:28:02 -07001270 PolicyInfo policyInfo = policyTable.get(pid);
Sangho Shin5b8f5452014-10-20 11:46:01 -07001271 PacketMatch policyMatch = policyInfo.match;
Sangho Shine020cc32014-10-20 13:28:02 -07001272 String tid = policyInfo.tunnelId;
Sangho Shin5b8f5452014-10-20 11:46:01 -07001273 int priority = policyInfo.priority;
1274
1275 List<Action> actions = new ArrayList<>();
1276 int gropuId = 0; // dummy group ID
1277 GroupAction groupAction = new GroupAction();
1278 groupAction.setGroupId(gropuId);
1279 actions.add(groupAction);
1280
1281 MatchAction matchAction = new MatchAction(new MatchActionId(
1282 matchActionId++),
1283 new SwitchPort((long) 0, (short) 0), policyMatch, priority,
1284 actions);
1285 MatchActionOperationEntry maEntry =
1286 new MatchActionOperationEntry(Operator.REMOVE, matchAction);
1287
Sangho Shin81655442014-10-20 14:22:46 -07001288 TunnelInfo tunnelInfo = tunnelTable.get(tid);
1289 List<TunnelRouteInfo> routes = tunnelInfo.routes;
1290
1291 for (TunnelRouteInfo route : routes) {
Sangho Shin5b8f5452014-10-20 11:46:01 -07001292 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin81655442014-10-20 14:22:46 -07001293 getSwId(route.srcSwDpid));
Sangho Shin5b8f5452014-10-20 11:46:01 -07001294
1295 if (sw13 != null) {
1296 printMatchActionOperationEntry(sw13, maEntry);
1297 try {
1298 sw13.pushFlow(maEntry);
1299 } catch (IOException e) {
1300 e.printStackTrace();
1301 log.debug("policy remove failed due to pushFlow() exception");
Sangho Shin306633a2014-10-20 14:26:55 -07001302 return false;
Sangho Shin5b8f5452014-10-20 11:46:01 -07001303 }
1304 }
1305 }
1306
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001307 policyTable.remove(pid);
Sangho Shin5b8f5452014-10-20 11:46:01 -07001308 log.debug("Policy {} is removed.", pid);
Sangho Shin306633a2014-10-20 14:26:55 -07001309 return true;
Sangho Shine020cc32014-10-20 13:28:02 -07001310 }
Sangho Shin5b8f5452014-10-20 11:46:01 -07001311
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001312 /**
Sangho Shin1ad7be02014-10-20 16:56:49 -07001313 * Get the first group ID for the tunnel for specific source router
1314 * If Segment Stitching was required to create the tunnel, there are
1315 * mutiple source routers.
1316 *
1317 * @param tunnelId ID for the tunnel
1318 * @param dpid source router DPID
1319 * @return the first group ID of the tunnel
1320 */
1321 public int getTunnelGroupId(String tunnelId, String dpid) {
1322 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
1323 getSwId(dpid));
1324
1325 if (sw13 == null) {
1326 return -1;
1327 }
1328 else {
1329 return sw13.getTunnelGroupId(tunnelId);
1330 }
1331 }
1332
1333 /**
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001334 * Remove a tunnel
1335 * It removes all groups for the tunnel if the tunnel is not used for any
1336 * policy.
1337 *
1338 * @param tunnelId tunnel ID to remove
1339 */
Sangho Shin306633a2014-10-20 14:26:55 -07001340 public boolean removeTunnel(String tunnelId) {
Sangho Shin55d00e12014-10-20 12:13:07 -07001341
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001342 // Check if the tunnel is used for any policy
1343 for (PolicyInfo policyInfo: policyTable.values()) {
1344 if (policyInfo.tunnelId == tunnelId) {
1345 log.debug("Tunnel {} is still used for the policy {}.",
1346 policyInfo.policyId, tunnelId);
1347 return false;
1348 }
1349 }
1350
1351 TunnelInfo tunnelInfo = tunnelTable.get(tunnelId);
1352
1353 List<TunnelRouteInfo> routes = tunnelInfo.routes;
1354 for (TunnelRouteInfo route: routes) {
1355 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
1356 getSwId(route.srcSwDpid));
1357
1358 if (sw13 != null) {
1359 sw13.removeTunnel(tunnelId);
1360 }
1361 }
1362
1363 tunnelTable.remove(tunnelId);
1364 log.debug("Tunnel {} was removed ", tunnelId);
1365
Sangho Shin306633a2014-10-20 14:26:55 -07001366 return true;
Sangho Shin55d00e12014-10-20 12:13:07 -07001367 }
1368
Sangho Shin7330c032014-10-20 10:34:51 -07001369 // ************************************
1370 // Utility functions
1371 // ************************************
1372
Sangho Shin15273b62014-10-16 22:22:05 -07001373 /**
Sangho Shin7330c032014-10-20 10:34:51 -07001374 * Get the forwarding Switch DPIDs to send packets to a node
Sangho Shin15273b62014-10-16 22:22:05 -07001375 *
Sangho Shin7330c032014-10-20 10:34:51 -07001376 * @param srcSw source switch
1377 * @param nodeId destination node Id
1378 * @return list of switch DPID to forward packets to
Sangho Shin15273b62014-10-16 22:22:05 -07001379 */
Sangho Shin7330c032014-10-20 10:34:51 -07001380 private List<Dpid> getForwardingSwitchForNodeId(Switch srcSw, String nodeId) {
Sangho Shin15273b62014-10-16 22:22:05 -07001381
Sangho Shin7330c032014-10-20 10:34:51 -07001382 List<Dpid> fwdSws = new ArrayList<Dpid>();
1383 Switch destSw = null;
Sangho Shin15273b62014-10-16 22:22:05 -07001384
Sangho Shin7330c032014-10-20 10:34:51 -07001385 destSw = getSwitchFromNodeId(nodeId);
1386
1387 if (destSw == null) {
1388 log.debug("Cannot find the switch with ID {}", nodeId);
1389 return null;
1390 }
1391
1392 ECMPShortestPathGraph ecmpSPG = new ECMPShortestPathGraph(srcSw);
1393
1394 HashMap<Integer, HashMap<Switch, ArrayList<ArrayList<Dpid>>>> switchVia =
1395 ecmpSPG.getAllLearnedSwitchesAndVia();
1396 for (Integer itrIdx : switchVia.keySet()) {
1397 HashMap<Switch, ArrayList<ArrayList<Dpid>>> swViaMap =
1398 switchVia.get(itrIdx);
1399 for (Switch targetSw : swViaMap.keySet()) {
1400 String destSwDpid = destSw.getDpid().toString();
1401 if (targetSw.getDpid().toString().equals(destSwDpid)) {
1402 for (ArrayList<Dpid> via : swViaMap.get(targetSw)) {
1403 if (via.isEmpty()) {
1404 fwdSws.add(destSw.getDpid());
1405 }
1406 else {
1407 fwdSws.add(via.get(0));
1408 }
1409 }
1410 }
1411 }
1412 }
1413
1414 return fwdSws;
Sangho Shin15273b62014-10-16 22:22:05 -07001415 }
1416
Sangho Shin7330c032014-10-20 10:34:51 -07001417 /**
1418 * Get switch for the node Id specified
1419 *
1420 * @param nodeId node ID for switch
1421 * @return Switch
1422 */
1423 private Switch getSwitchFromNodeId(String nodeId) {
Fahad Naeem Khan4444b952014-10-18 22:30:50 -07001424
Sangho Shin7330c032014-10-20 10:34:51 -07001425 for (Switch sw : mutableTopology.getSwitches()) {
1426 String id = sw.getStringAttribute("nodeSid");
1427 if (id.equals(nodeId)) {
1428 return sw;
1429 }
1430 }
1431
1432 return null;
1433 }
Fahad Naeem Khan4444b952014-10-18 22:30:50 -07001434
Sangho Shin43cee112014-09-25 16:43:34 -07001435 /**
Sangho Shin7330c032014-10-20 10:34:51 -07001436 * Convert a string DPID to its Switch Id (integer)
Sangho Shinfbc572c2014-10-02 16:37:05 -07001437 *
Sangho Shin7330c032014-10-20 10:34:51 -07001438 * @param dpid
1439 * @return
Sangho Shin43cee112014-09-25 16:43:34 -07001440 */
Sangho Shin7330c032014-10-20 10:34:51 -07001441 private long getSwId(String dpid) {
Sangho Shin43cee112014-09-25 16:43:34 -07001442
Sangho Shin7330c032014-10-20 10:34:51 -07001443 long swId = 0;
Sangho Shin43cee112014-09-25 16:43:34 -07001444
Sangho Shin7330c032014-10-20 10:34:51 -07001445 String swIdHexStr = "0x"+dpid.substring(dpid.lastIndexOf(":") + 1);
1446 if (swIdHexStr != null)
1447 swId = Integer.decode(swIdHexStr);
Sangho Shin43cee112014-09-25 16:43:34 -07001448
Sangho Shin7330c032014-10-20 10:34:51 -07001449 return swId;
1450 }
Sangho Shin43cee112014-09-25 16:43:34 -07001451
Sangho Shin7330c032014-10-20 10:34:51 -07001452 /**
1453 * Check if the switch is the edge router or not.
1454 *
1455 * @param dpid Dpid of the switch to check
1456 * @return true if it is an edge router, otherwise false
1457 */
1458 private boolean IsEdgeRouter(String dpid) {
Sangho Shin0df01982014-09-25 17:11:18 -07001459
Sangho Shin7330c032014-10-20 10:34:51 -07001460 for (Switch sw : mutableTopology.getSwitches()) {
1461 String dpidStr = sw.getDpid().toString();
1462 if (dpid.equals(dpidStr)) {
1463 /*
1464 String subnetInfo = sw.getStringAttribute("subnets");
1465 if (subnetInfo == null || subnetInfo.equals("[]")) {
1466 return false;
1467 }
1468 else
1469 return true;
1470 */
1471 String isEdge = sw.getStringAttribute("isEdgeRouter");
1472 if (isEdge != null) {
1473 if (isEdge.equals("true"))
1474 return true;
1475 else
1476 return false;
1477 }
Sangho Shin43cee112014-09-25 16:43:34 -07001478 }
1479 }
1480
Sangho Shin7330c032014-10-20 10:34:51 -07001481 return false;
Sangho Shineb083032014-09-22 16:11:34 -07001482 }
1483
1484 /**
1485 * Get MPLS label reading the config file
Sangho Shinfbc572c2014-10-02 16:37:05 -07001486 *
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001487 * @param dipid DPID of the switch
Sangho Shineb083032014-09-22 16:11:34 -07001488 * @return MPLS label for the switch
1489 */
Sangho Shin43cee112014-09-25 16:43:34 -07001490 private String getMplsLabel(String dpid) {
Sangho Shineb083032014-09-22 16:11:34 -07001491
1492 String mplsLabel = null;
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001493 for (Switch sw : mutableTopology.getSwitches()) {
Sangho Shin43cee112014-09-25 16:43:34 -07001494 String dpidStr = sw.getDpid().toString();
1495 if (dpid.equals(dpidStr)) {
Sangho Shineb083032014-09-22 16:11:34 -07001496 mplsLabel = sw.getStringAttribute("nodeSid");
1497 break;
Sangho Shin1aa93542014-09-22 09:49:44 -07001498 }
1499 }
1500
Sangho Shineb083032014-09-22 16:11:34 -07001501 return mplsLabel;
Sangho Shin1aa93542014-09-22 09:49:44 -07001502 }
1503
Sangho Shineb083032014-09-22 16:11:34 -07001504 /**
Sangho Shin1aa93542014-09-22 09:49:44 -07001505 * The function checks if given IP matches to the given subnet mask
Sangho Shinfbc572c2014-10-02 16:37:05 -07001506 *
Sangho Shin1aa93542014-09-22 09:49:44 -07001507 * @param addr - subnet address to match
1508 * @param addr1 - IP address to check
1509 * @return true if the IP address matches to the subnet, otherwise false
1510 */
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001511 public boolean netMatch(String addr, String addr1) { // addr is subnet
1512 // address and addr1 is
1513 // ip address. Function
1514 // will return true, if
1515 // addr1 is within
1516 // addr(subnet)
Sangho Shin1aa93542014-09-22 09:49:44 -07001517
1518 String[] parts = addr.split("/");
1519 String ip = parts[0];
1520 int prefix;
1521
1522 if (parts.length < 2) {
1523 prefix = 0;
1524 } else {
1525 prefix = Integer.parseInt(parts[1]);
1526 }
1527
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001528 Inet4Address a = null;
1529 Inet4Address a1 = null;
Sangho Shin1aa93542014-09-22 09:49:44 -07001530 try {
1531 a = (Inet4Address) InetAddress.getByName(ip);
1532 a1 = (Inet4Address) InetAddress.getByName(addr1);
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001533 } catch (UnknownHostException e) {
1534 }
Sangho Shin1aa93542014-09-22 09:49:44 -07001535
1536 byte[] b = a.getAddress();
1537 int ipInt = ((b[0] & 0xFF) << 24) |
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001538 ((b[1] & 0xFF) << 16) |
1539 ((b[2] & 0xFF) << 8) |
1540 ((b[3] & 0xFF) << 0);
Sangho Shin1aa93542014-09-22 09:49:44 -07001541
1542 byte[] b1 = a1.getAddress();
1543 int ipInt1 = ((b1[0] & 0xFF) << 24) |
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001544 ((b1[1] & 0xFF) << 16) |
1545 ((b1[2] & 0xFF) << 8) |
1546 ((b1[3] & 0xFF) << 0);
Sangho Shin1aa93542014-09-22 09:49:44 -07001547
1548 int mask = ~((1 << (32 - prefix)) - 1);
1549
1550 if ((ipInt & mask) == (ipInt1 & mask)) {
1551 return true;
1552 }
1553 else {
1554 return false;
1555 }
1556 }
Sangho Shineb083032014-09-22 16:11:34 -07001557
Sangho Shinac5ee2b2014-09-28 21:27:20 -07001558 /**
1559 * Add a routing rule for the host
Sangho Shinfbc572c2014-10-02 16:37:05 -07001560 *
Sangho Shinac5ee2b2014-09-28 21:27:20 -07001561 * @param sw - Switch to add the rule
1562 * @param hostIpAddress Destination host IP address
1563 * @param hostMacAddress Destination host MAC address
1564 */
Sangho Shineb083032014-09-22 16:11:34 -07001565 public void addRouteToHost(Switch sw, int hostIpAddress, byte[] hostMacAddress) {
1566 ipHandler.addRouteToHost(sw, hostIpAddress, hostMacAddress);
Sangho Shineb083032014-09-22 16:11:34 -07001567 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -07001568
Sangho Shin463bee52014-09-29 15:14:43 -07001569 /**
1570 * Add IP packet to a buffer queue
Sangho Shinfbc572c2014-10-02 16:37:05 -07001571 *
Sangho Shin463bee52014-09-29 15:14:43 -07001572 * @param ipv4
1573 */
Sangho Shin7330c032014-10-20 10:34:51 -07001574 public void addPacketToPacketBuffer(IPv4 ipv4) {
Sangho Shin61535402014-10-01 11:37:14 -07001575 ipPacketQueue.add(ipv4);
Sangho Shin463bee52014-09-29 15:14:43 -07001576 }
1577
1578 /**
1579 * Retrieve all packets whose destination is the given address.
Sangho Shinfbc572c2014-10-02 16:37:05 -07001580 *
Sangho Shin463bee52014-09-29 15:14:43 -07001581 * @param destIp Destination address of packets to retrieve
1582 */
1583 public List<IPv4> getIpPacketFromQueue(byte[] destIp) {
1584
1585 List<IPv4> bufferedPackets = new ArrayList<IPv4>();
1586
Sangho Shin61535402014-10-01 11:37:14 -07001587 if (!ipPacketQueue.isEmpty()) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001588 for (IPv4 ip : ipPacketQueue) {
Sangho Shin61535402014-10-01 11:37:14 -07001589 int dest = ip.getDestinationAddress();
1590 IPv4Address ip1 = IPv4Address.of(dest);
1591 IPv4Address ip2 = IPv4Address.of(destIp);
1592 if (ip1.equals(ip2)) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001593 bufferedPackets.add((IPv4) (ipPacketQueue.poll()).clone());
Sangho Shin463bee52014-09-29 15:14:43 -07001594 }
1595 }
1596 }
1597
1598 return bufferedPackets;
1599 }
1600
Sangho Shin7330c032014-10-20 10:34:51 -07001601 /**
1602 * Get MAC address to known hosts
1603 *
1604 * @param destinationAddress IP address to get MAC address
1605 * @return MAC Address to given IP address
1606 */
1607 public byte[] getMacAddressFromIpAddress(int destinationAddress) {
1608
1609 // Can't we get the host IP address from the TopologyService ??
1610
1611 Iterator<ArpEntry> iterator = arpEntries.iterator();
1612
1613 IPv4Address ipAddress = IPv4Address.of(destinationAddress);
1614 byte[] ipAddressInByte = ipAddress.getBytes();
1615
1616 while (iterator.hasNext()) {
1617 ArpEntry arpEntry = iterator.next();
1618 byte[] address = arpEntry.targetIpAddress;
1619
1620 IPv4Address a = IPv4Address.of(address);
1621 IPv4Address b = IPv4Address.of(ipAddressInByte);
1622
1623 if (a.equals(b)) {
1624 log.debug("Found an arp entry");
1625 return arpEntry.targetMacAddress;
1626 }
1627 }
1628
1629 return null;
1630 }
1631
1632 /**
1633 * Send an ARP request via ArpHandler
1634 *
1635 * @param destinationAddress
1636 * @param sw
1637 * @param inPort
1638 *
1639 */
1640 public void sendArpRequest(Switch sw, int destinationAddress, Port inPort) {
1641 arpHandler.sendArpRequest(sw, destinationAddress, inPort);
1642 }
1643
1644
1645 // ************************************
1646 // Test functions
1647 // ************************************
1648
Sangho Shin55d00e12014-10-20 12:13:07 -07001649 private void runTest() {
1650
1651 if (testMode == POLICY_ADD1) {
1652 String[] routeArray = {"101", "105", "110"};
1653 List<Dpid> routeList = new ArrayList<Dpid>();
1654 for (int i = 0; i < routeArray.length; i++) {
1655 Dpid dpid = getSwitchFromNodeId(routeArray[i]).getDpid();
1656 routeList.add(dpid);
1657 }
1658
1659 if (createTunnel("1", routeList)) {
1660 IPv4Net srcIp = new IPv4Net("10.0.1.1/24");
1661 IPv4Net dstIp = new IPv4Net("10.1.2.1/24");
1662
1663 log.debug("Set the policy 1");
Sangho Shine020cc32014-10-20 13:28:02 -07001664 this.createPolicy("1", null, null, Ethernet.TYPE_IPV4, srcIp,
Sangho Shin55d00e12014-10-20 12:13:07 -07001665 dstIp, IPv4.PROTOCOL_ICMP, (short)-1, (short)-1, 10000,
Sangho Shine020cc32014-10-20 13:28:02 -07001666 "1");
Sangho Shin55d00e12014-10-20 12:13:07 -07001667 testMode = POLICY_ADD2;
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001668 testTask.reschedule(5, TimeUnit.SECONDS);
Sangho Shin55d00e12014-10-20 12:13:07 -07001669 }
1670 else {
1671 // retry it
1672 testTask.reschedule(5, TimeUnit.SECONDS);
1673 }
1674 }
1675 else if (testMode == POLICY_ADD2) {
1676 String[] routeArray = {"101", "102", "103", "104", "105", "108",
1677 "110"};
1678 List<Dpid> routeList = new ArrayList<Dpid>();
1679 for (int i = 0; i < routeArray.length; i++) {
1680 Dpid dpid = getSwitchFromNodeId(routeArray[i]).getDpid();
1681 routeList.add(dpid);
1682 }
1683
1684 if (createTunnel("2", routeList)) {
1685 IPv4Net srcIp = new IPv4Net("10.0.1.1/24");
1686 IPv4Net dstIp = new IPv4Net("10.1.2.1/24");
1687
1688 log.debug("Set the policy 2");
Sangho Shine020cc32014-10-20 13:28:02 -07001689 this.createPolicy("2", null, null, Ethernet.TYPE_IPV4, srcIp,
Sangho Shin55d00e12014-10-20 12:13:07 -07001690 dstIp, IPv4.PROTOCOL_ICMP, (short)-1, (short)-1, 20000,
Sangho Shine020cc32014-10-20 13:28:02 -07001691 "2");
Sangho Shin55d00e12014-10-20 12:13:07 -07001692 testMode = POLICY_REMOVE2;
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001693 testTask.reschedule(5, TimeUnit.SECONDS);
Sangho Shin55d00e12014-10-20 12:13:07 -07001694 }
1695 else {
1696 log.debug("Retry it");
1697 testTask.reschedule(5, TimeUnit.SECONDS);
1698 }
1699 }
1700 else if (testMode == POLICY_REMOVE2){
1701 log.debug("Remove the policy 2");
Sangho Shine020cc32014-10-20 13:28:02 -07001702 this.removePolicy("2");
Sangho Shin55d00e12014-10-20 12:13:07 -07001703 testMode = POLICY_REMOVE1;
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001704 testTask.reschedule(5, TimeUnit.SECONDS);
Sangho Shin55d00e12014-10-20 12:13:07 -07001705 }
1706 else if (testMode == POLICY_REMOVE1){
1707 log.debug("Remove the policy 1");
Sangho Shine020cc32014-10-20 13:28:02 -07001708 this.removePolicy("1");
Sangho Shin55d00e12014-10-20 12:13:07 -07001709
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001710 testMode = TUNNEL_REMOVE1;
1711 testTask.reschedule(5, TimeUnit.SECONDS);
1712 }
1713 else if (testMode == TUNNEL_REMOVE1) {
1714 log.debug("Remove the tunnel 1");
1715 this.removeTunnel("1");
1716
1717 testMode = TUNNEL_REMOVE2;
1718 testTask.reschedule(5, TimeUnit.SECONDS);
1719 }
1720 else if (testMode == TUNNEL_REMOVE2) {
1721 log.debug("Remove the tunnel 2");
1722 this.removeTunnel("2");
1723 log.debug("The end of test");
1724 }
Sangho Shin55d00e12014-10-20 12:13:07 -07001725 }
Sangho Shin7330c032014-10-20 10:34:51 -07001726
1727 private void runTest1() {
1728
1729 String dpid1 = "00:00:00:00:00:00:00:01";
1730 String dpid2 = "00:00:00:00:00:00:00:0a";
1731 Switch srcSw = mutableTopology.getSwitch(new Dpid(dpid1));
1732 Switch dstSw = mutableTopology.getSwitch(new Dpid(dpid2));
1733
1734 if (srcSw == null || dstSw == null) {
1735 testTask.reschedule(1, TimeUnit.SECONDS);
1736 log.debug("Switch is gone. Reschedule the test");
1737 return;
1738 }
1739
1740 String[] routeArray = {"101", "102", "105", "108", "110"};
1741 List<String> routeList = new ArrayList<String>();
1742 for (int i = 0; i < routeArray.length; i++)
1743 routeList.add(routeArray[i]);
1744
1745 List<String> optimizedRoute = this.getOptimizedPath(srcSw, dstSw, routeList);
1746
1747 log.debug("Test set is {}", routeList.toString());
1748 log.debug("Result set is {}", optimizedRoute.toString());
1749
1750
1751 }
1752
1753 /**
1754 * print tunnel info - used only for debugging.
1755 * @param targetSw
1756 *
1757 * @param fwdSwDpids
1758 * @param ids
1759 * @param tunnelId
1760 */
Sangho Shine020cc32014-10-20 13:28:02 -07001761 private void printTunnelInfo(IOF13Switch targetSw, String tunnelId,
Sangho Shin7330c032014-10-20 10:34:51 -07001762 List<String> ids, NeighborSet ns) {
1763 StringBuilder logStr = new StringBuilder("In switch " +
1764 targetSw.getId() + ", create a tunnel " + tunnelId + " " + " of push ");
1765 for (String id: ids)
1766 logStr.append(id + "-");
1767 logStr.append(" output to ");
1768 for (Dpid dpid: ns.getDpids())
1769 logStr.append(dpid + " - ");
1770
1771 log.debug(logStr.toString());
1772
1773 }
1774
1775 /**
1776 * Debugging function to print out the Match Action Entry
1777 * @param sw13
1778 *
1779 * @param maEntry
1780 */
1781 private void printMatchActionOperationEntry(
1782 IOF13Switch sw13, MatchActionOperationEntry maEntry) {
1783
1784 StringBuilder logStr = new StringBuilder("In switch " + sw13.getId() + ", ");
1785
1786 MatchAction ma = maEntry.getTarget();
1787 Match m = ma.getMatch();
1788 List<Action> actions = ma.getActions();
1789
1790 if (m instanceof Ipv4Match) {
1791 logStr.append("If the IP matches with ");
1792 IPv4Net ip = ((Ipv4Match) m).getDestination();
1793 logStr.append(ip.toString());
1794 logStr.append(" then ");
1795 }
1796 else if (m instanceof MplsMatch) {
1797 logStr.append("If the MPLS label matches with ");
1798 int mplsLabel = ((MplsMatch) m).getMplsLabel();
1799 logStr.append(mplsLabel);
1800 logStr.append(" then ");
1801 }
1802 else if (m instanceof PacketMatch) {
1803 GroupAction ga = (GroupAction)actions.get(0);
1804 logStr.append("if the policy match is XXX then go to group " +
1805 ga.getGroupId());
1806 log.debug(logStr.toString());
1807 return;
1808 }
1809
1810 logStr.append(" do { ");
1811 for (Action action : actions) {
1812 if (action instanceof CopyTtlInAction) {
1813 logStr.append("copy ttl In, ");
1814 }
1815 else if (action instanceof CopyTtlOutAction) {
1816 logStr.append("copy ttl Out, ");
1817 }
1818 else if (action instanceof DecMplsTtlAction) {
1819 logStr.append("Dec MPLS TTL , ");
1820 }
1821 else if (action instanceof GroupAction) {
1822 logStr.append("Forward packet to < ");
1823 NeighborSet dpids = ((GroupAction) action).getDpids();
1824 logStr.append(dpids.toString() + ",");
1825
1826 }
1827 else if (action instanceof PopMplsAction) {
1828 logStr.append("Pop MPLS label, ");
1829 }
1830 else if (action instanceof PushMplsAction) {
1831 logStr.append("Push MPLS label, ");
1832 }
1833 else if (action instanceof SetMplsIdAction) {
1834 int id = ((SetMplsIdAction) action).getMplsId();
1835 logStr.append("Set MPLS ID as " + id + ", ");
1836 }
1837 }
1838
1839 log.debug(logStr.toString());
1840
1841 }
1842
1843
1844 // ************************************
1845 // Unused classes and functions
1846 // ************************************
1847
1848 /**
1849 * Temporary class to to keep ARP entry
1850 *
1851 */
1852 private class ArpEntry {
1853
1854 byte[] targetMacAddress;
1855 byte[] targetIpAddress;
1856
1857 private ArpEntry(byte[] macAddress, byte[] ipAddress) {
1858 this.targetMacAddress = macAddress;
1859 this.targetIpAddress = ipAddress;
1860 }
1861 }
1862
1863 /**
1864 * This class is used only for link recovery optimization in
1865 * modifyEcmpRoutingRules() function.
1866 * TODO: please remove if the optimization is not used at all
1867 */
1868 private class SwitchPair {
1869 private Switch src;
1870 private Switch dst;
1871
1872 public SwitchPair(Switch src, Switch dst) {
1873 this.src = src;
1874 this.dst = dst;
1875 }
1876
1877 public Switch getSource() {
1878 return src;
1879 }
1880
1881 public Switch getDestination() {
1882 return dst;
1883 }
1884 }
1885
1886 /**
1887 * Update ARP Cache using ARP packets It is used to set destination MAC
1888 * address to forward packets to known hosts. But, it will be replace with
1889 * Host information of Topology service later.
1890 *
1891 * @param arp APR packets to use for updating ARP entries
1892 */
1893 public void updateArpCache(ARP arp) {
1894
1895 ArpEntry arpEntry = new ArpEntry(arp.getSenderHardwareAddress(),
1896 arp.getSenderProtocolAddress());
1897 // TODO: Need to check the duplication
1898 arpEntries.add(arpEntry);
1899 }
1900
1901 /**
1902 * Modify the routing rules for the lost links
1903 * - Recompute the path if the link failed is included in the path
1904 * (including src and dest).
1905 *
1906 * @param newLink
1907 */
1908 private void modifyEcmpRoutingRules(LinkData linkRemoved) {
1909
1910 //HashMap<Switch, SwitchPair> linksToRecompute = new HashMap<Switch, SwitchPair>();
1911 Set<SwitchPair> linksToRecompute = new HashSet<SwitchPair>();
1912
1913 for (ECMPShortestPathGraph ecmpSPG : graphs.values()) {
1914 Switch rootSw = ecmpSPG.getRootSwitch();
1915 HashMap<Integer, HashMap<Switch, ArrayList<Path>>> paths =
1916 ecmpSPG.getCompleteLearnedSwitchesAndPaths();
1917 for (HashMap<Switch, ArrayList<Path>> p: paths.values()) {
1918 for (Switch destSw: p.keySet()) {
1919 ArrayList<Path> path = p.get(destSw);
1920 if (checkPath(path, linkRemoved)) {
1921 boolean found = false;
1922 for (SwitchPair pair: linksToRecompute) {
1923 if (pair.getSource().getDpid() == rootSw.getDpid() &&
1924 pair.getSource().getDpid() == destSw.getDpid()) {
1925 found = true;
1926 }
1927 }
1928 if (!found) {
1929 linksToRecompute.add(new SwitchPair(rootSw, destSw));
1930 }
1931 }
1932 }
1933 }
1934 }
1935
1936 // Recompute the path for the specific route
1937 for (SwitchPair pair: linksToRecompute) {
1938
1939 log.debug("Recompute path from {} to {}", pair.getSource(), pair.getDestination());
1940 // We need the following function for optimization
1941 //ECMPShortestPathGraph ecmpSPG =
1942 // new ECMPShortestPathGraph(pair.getSource(), pair.getDestination());
1943 ECMPShortestPathGraph ecmpSPG =
1944 new ECMPShortestPathGraph(pair.getSource());
1945 populateEcmpRoutingRulesForPath(pair.getSource(), ecmpSPG, true);
1946 }
1947 }
1948
1949 /**
1950 * Optimize the mpls label
1951 * The feature will be used only for policy of "avoid a specific switch".
1952 * Check route to each router in route backward.
1953 * If there is only one route to the router and the routers are included in
1954 * the route, remove the id from the path.
1955 * A-B-C-D-E => A-B-C-D-E -> A-E
1956 * | | => A-B-H-I -> A-I
Sangho Shin5b8f5452014-10-20 11:46:01 -07001957 * F-G-H-I => A-D-I > A-D-I
Sangho Shin7330c032014-10-20 10:34:51 -07001958 */
1959 private List<String> getOptimizedPath(Switch srcSw, Switch dstSw, List<String> route) {
1960
1961 List<String> optimizedPath = new ArrayList<String>();
1962 optimizedPath.addAll(route);
1963 ECMPShortestPathGraph ecmpSPG = new ECMPShortestPathGraph(srcSw);
1964
1965 HashMap<Integer, HashMap<Switch, ArrayList<Path>>> paths =
1966 ecmpSPG.getCompleteLearnedSwitchesAndPaths();
1967 for (HashMap<Switch, ArrayList<Path>> p: paths.values()) {
1968 for (Switch s: p.keySet()) {
1969 if (s.getDpid().toString().equals(dstSw.getDpid().toString())) {
1970 ArrayList<Path> ecmpPaths = p.get(s);
1971 if (ecmpPaths!= null && ecmpPaths.size() == 1) {
1972 for (Path path: ecmpPaths) {
1973 for (LinkData link: path) {
1974 String srcId = getMplsLabel(link.getSrc().getDpid().toString());
1975 String dstId = getMplsLabel(link.getSrc().getDpid().toString());
1976 if (optimizedPath.contains(srcId)) {
1977 optimizedPath.remove(srcId);
1978 }
1979 if (optimizedPath.contains(dstId)) {
1980 optimizedPath.remove(dstId);
1981 }
1982 }
1983 }
1984 }
1985 }
1986 }
1987 }
1988
1989 return optimizedPath;
1990
1991 }
1992
1993 /**
1994 * Check if the path is affected from the link removed
1995 *
1996 * @param path Path to check
1997 * @param linkRemoved link removed
1998 * @return true if the path contains the link removed
1999 */
2000 private boolean checkPath(ArrayList<Path> path, LinkData linkRemoved) {
2001
2002 for (Path ppp: path) {
2003 // TODO: need to check if this is a bidirectional or
2004 // unidirectional
2005 for (LinkData link: ppp) {
2006 if (link.getDst().getDpid().equals(linkRemoved.getDst().getDpid()) &&
2007 link.getSrc().getDpid().equals(linkRemoved.getSrc().getDpid()))
2008 return true;
2009 }
2010 }
2011
2012 return false;
2013 }
Sangho Shin15273b62014-10-16 22:22:05 -07002014
2015
Sangho Shin2f263692014-09-15 14:09:41 -07002016}