blob: e82520370dfb8fa2143ee3111deffa6485829c81 [file] [log] [blame]
Sangho Shin2f263692014-09-15 14:09:41 -07001package net.onrc.onos.apps.segmentrouting;
2
Sangho Shin9c0f4c32014-09-26 16:02:38 -07003import java.io.IOException;
Sangho Shin1aa93542014-09-22 09:49:44 -07004import java.net.Inet4Address;
5import java.net.InetAddress;
6import java.net.UnknownHostException;
Sangho Shin2f263692014-09-15 14:09:41 -07007import java.util.ArrayList;
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07008import java.util.Arrays;
Sangho Shin2f263692014-09-15 14:09:41 -07009import java.util.Collection;
Srikanth Vavilapalli363f1dc2014-09-22 14:30:23 -070010import java.util.HashMap;
Sangho Shin5be3e532014-10-03 17:20:58 -070011import java.util.HashSet;
Sangho Shin2f263692014-09-15 14:09:41 -070012import java.util.Iterator;
13import java.util.List;
14import java.util.Map;
Sangho Shin5be3e532014-10-03 17:20:58 -070015import java.util.Set;
Sangho Shin61535402014-10-01 11:37:14 -070016import java.util.concurrent.ConcurrentLinkedQueue;
Sangho Shin11d4e0f2014-09-30 12:00:33 -070017import java.util.concurrent.ExecutionException;
Sangho Shin43cee112014-09-25 16:43:34 -070018import java.util.concurrent.ScheduledExecutorService;
19import java.util.concurrent.TimeUnit;
Sangho Shin11d4e0f2014-09-30 12:00:33 -070020import java.util.concurrent.TimeoutException;
Sangho Shin2f263692014-09-15 14:09:41 -070021
22import net.floodlightcontroller.core.IFloodlightProviderService;
Sangho Shin9c0f4c32014-09-26 16:02:38 -070023import net.floodlightcontroller.core.IOF13Switch;
Sangho Shin0df01982014-09-25 17:11:18 -070024import net.floodlightcontroller.core.IOF13Switch.NeighborSet;
Sangho Shin11d4e0f2014-09-30 12:00:33 -070025import net.floodlightcontroller.core.internal.OFBarrierReplyFuture;
Sangho Shin2f263692014-09-15 14:09:41 -070026import net.floodlightcontroller.core.module.FloodlightModuleContext;
27import net.floodlightcontroller.core.module.FloodlightModuleException;
28import net.floodlightcontroller.core.module.IFloodlightModule;
29import net.floodlightcontroller.core.module.IFloodlightService;
Sangho Shin43cee112014-09-25 16:43:34 -070030import net.floodlightcontroller.core.util.SingletonTask;
Sangho Shin7330c032014-10-20 10:34:51 -070031import net.floodlightcontroller.restserver.IRestApiService;
Sangho Shin43cee112014-09-25 16:43:34 -070032import net.floodlightcontroller.threadpool.IThreadPoolService;
Sangho Shin15273b62014-10-16 22:22:05 -070033import net.floodlightcontroller.util.MACAddress;
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070034import net.onrc.onos.api.packet.IPacketListener;
Sangho Shin2f263692014-09-15 14:09:41 -070035import net.onrc.onos.api.packet.IPacketService;
Fahad Naeem Khan4444b952014-10-18 22:30:50 -070036import net.onrc.onos.apps.segmentrouting.web.SegmentRoutingWebRoutable;
Sangho Shin2f263692014-09-15 14:09:41 -070037import net.onrc.onos.core.flowprogrammer.IFlowPusherService;
Sangho Shinfbc572c2014-10-02 16:37:05 -070038import net.onrc.onos.core.intent.Path;
Sangho Shin2f263692014-09-15 14:09:41 -070039import net.onrc.onos.core.main.config.IConfigInfoService;
Sangho Shin43cee112014-09-25 16:43:34 -070040import net.onrc.onos.core.matchaction.MatchAction;
41import net.onrc.onos.core.matchaction.MatchActionId;
42import net.onrc.onos.core.matchaction.MatchActionOperationEntry;
Sangho Shin5be3e532014-10-03 17:20:58 -070043import net.onrc.onos.core.matchaction.MatchActionOperations.Operator;
Sangho Shin43cee112014-09-25 16:43:34 -070044import net.onrc.onos.core.matchaction.action.Action;
45import net.onrc.onos.core.matchaction.action.CopyTtlInAction;
46import net.onrc.onos.core.matchaction.action.CopyTtlOutAction;
47import net.onrc.onos.core.matchaction.action.DecMplsTtlAction;
48import net.onrc.onos.core.matchaction.action.DecNwTtlAction;
49import net.onrc.onos.core.matchaction.action.GroupAction;
Sangho Shin6d3c2f02014-10-22 10:10:55 -070050import net.onrc.onos.core.matchaction.action.ModifyDstMacAction;
51import net.onrc.onos.core.matchaction.action.ModifySrcMacAction;
52import net.onrc.onos.core.matchaction.action.OutputAction;
Sangho Shin43cee112014-09-25 16:43:34 -070053import net.onrc.onos.core.matchaction.action.PopMplsAction;
54import net.onrc.onos.core.matchaction.action.PushMplsAction;
55import net.onrc.onos.core.matchaction.action.SetMplsIdAction;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -070056import net.onrc.onos.core.matchaction.match.Ipv4Match;
Sangho Shin43cee112014-09-25 16:43:34 -070057import net.onrc.onos.core.matchaction.match.Match;
58import net.onrc.onos.core.matchaction.match.MplsMatch;
Sangho Shin15273b62014-10-16 22:22:05 -070059import net.onrc.onos.core.matchaction.match.PacketMatch;
60import net.onrc.onos.core.matchaction.match.PacketMatchBuilder;
Sangho Shin2f263692014-09-15 14:09:41 -070061import net.onrc.onos.core.packet.ARP;
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070062import net.onrc.onos.core.packet.Ethernet;
63import net.onrc.onos.core.packet.IPv4;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070064import net.onrc.onos.core.topology.ITopologyListener;
Sangho Shin1aa93542014-09-22 09:49:44 -070065import net.onrc.onos.core.topology.ITopologyService;
Sangho Shinbce900e2014-10-07 17:13:23 -070066import net.onrc.onos.core.topology.Link;
Sangho Shinc8d2f592014-09-30 16:53:57 -070067import net.onrc.onos.core.topology.LinkData;
Sangho Shinbce900e2014-10-07 17:13:23 -070068import net.onrc.onos.core.topology.MastershipData;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070069import net.onrc.onos.core.topology.MutableTopology;
Sangho Shineb083032014-09-22 16:11:34 -070070import net.onrc.onos.core.topology.Port;
Sangho Shinc8d2f592014-09-30 16:53:57 -070071import net.onrc.onos.core.topology.PortData;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070072import net.onrc.onos.core.topology.Switch;
Sangho Shin5be3e532014-10-03 17:20:58 -070073import net.onrc.onos.core.topology.SwitchData;
Sangho Shin1aa93542014-09-22 09:49:44 -070074import net.onrc.onos.core.topology.TopologyEvents;
Srikanth Vavilapalli363f1dc2014-09-22 14:30:23 -070075import net.onrc.onos.core.util.Dpid;
Sangho Shin43cee112014-09-25 16:43:34 -070076import net.onrc.onos.core.util.IPv4Net;
Sangho Shin6d3c2f02014-10-22 10:10:55 -070077import net.onrc.onos.core.util.PortNumber;
Sangho Shin43cee112014-09-25 16:43:34 -070078import net.onrc.onos.core.util.SwitchPort;
Sangho Shin2f263692014-09-15 14:09:41 -070079
Sangho Shin43cee112014-09-25 16:43:34 -070080import org.json.JSONArray;
81import org.json.JSONException;
Saurav Dasa962a692014-10-17 14:52:38 -070082import org.projectfloodlight.openflow.protocol.OFBarrierReply;
Saurav Dasbc594a42014-09-25 20:13:50 -070083import org.projectfloodlight.openflow.types.EthType;
Sangho Shin2f263692014-09-15 14:09:41 -070084import org.projectfloodlight.openflow.types.IPv4Address;
85import org.slf4j.Logger;
86import org.slf4j.LoggerFactory;
87
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070088public class SegmentRoutingManager implements IFloodlightModule,
Srikanth Vavilapalli8c49db72014-10-20 13:35:08 -070089 ITopologyListener, IPacketListener, ISegmentRoutingService {
Sangho Shin2f263692014-09-15 14:09:41 -070090
91 private static final Logger log = LoggerFactory
92 .getLogger(SegmentRoutingManager.class);
Sangho Shin23f898d2014-10-13 16:54:00 -070093
Fahad Naeem Khan5b558f22014-10-16 10:35:20 -070094 private ITopologyService topologyService;
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070095 private IPacketService packetService;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070096 private MutableTopology mutableTopology;
Sangho Shin61535402014-10-01 11:37:14 -070097 private ConcurrentLinkedQueue<IPv4> ipPacketQueue;
Fahad Naeem Khan4444b952014-10-18 22:30:50 -070098 private IRestApiService restApi;
Sangho Shin2f263692014-09-15 14:09:41 -070099 private List<ArpEntry> arpEntries;
Sangho Shineb083032014-09-22 16:11:34 -0700100 private ArpHandler arpHandler;
101 private GenericIpHandler ipHandler;
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700102 private IcmpHandler icmpHandler;
Sangho Shin43cee112014-09-25 16:43:34 -0700103 private IThreadPoolService threadPool;
104 private SingletonTask discoveryTask;
Sangho Shin23f898d2014-10-13 16:54:00 -0700105 private SingletonTask linkAddTask;
Sangho Shin15273b62014-10-16 22:22:05 -0700106 private SingletonTask testTask;
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700107 private IFloodlightProviderService floodlightProvider;
Sangho Shin2f263692014-09-15 14:09:41 -0700108
Sangho Shinfbc572c2014-10-02 16:37:05 -0700109 private HashMap<Switch, ECMPShortestPathGraph> graphs;
Sangho Shin23f898d2014-10-13 16:54:00 -0700110 private HashMap<String, LinkData> linksDown;
111 private HashMap<String, LinkData> linksToAdd;
Sangho Shin5be3e532014-10-03 17:20:58 -0700112 private ConcurrentLinkedQueue<TopologyEvents> topologyEventQueue;
Sangho Shine020cc32014-10-20 13:28:02 -0700113 private HashMap<String, PolicyInfo> policyTable;
Sangho Shin81655442014-10-20 14:22:46 -0700114 private HashMap<String, TunnelInfo> tunnelTable;
Sangho Shin204b9972014-10-22 11:08:10 -0700115 private HashMap<Integer, List<Integer>> adjacencyIdTable;
Sangho Shin5b8f5452014-10-20 11:46:01 -0700116
117 private int testMode = 0;
118
Sangho Shinbce900e2014-10-07 17:13:23 -0700119
120 private int numOfEvents = 0;
121 private int numOfEventProcess = 0;
122 private int numOfPopulation = 0;
Sangho Shin99918bd2014-10-08 15:52:35 -0700123 private long matchActionId = 0L;
Sangho Shin58182672014-10-21 13:23:38 -0700124
Sangho Shin23f898d2014-10-13 16:54:00 -0700125 private final int DELAY_TO_ADD_LINK = 10;
Sangho Shin15273b62014-10-16 22:22:05 -0700126 private final int MAX_NUM_LABELS = 3;
Sangho Shinfbc572c2014-10-02 16:37:05 -0700127
Sangho Shin5b8f5452014-10-20 11:46:01 -0700128 private final int POLICY_ADD1 = 1;
129 private final int POLICY_ADD2 = 2;
130 private final int POLICY_REMOVE1 = 3;
131 private final int POLICY_REMOVE2 = 4;
Sangho Shin4b46bcd2014-10-20 15:48:47 -0700132 private final int TUNNEL_REMOVE1 = 5;
133 private final int TUNNEL_REMOVE2 = 6;
Sangho Shin5b8f5452014-10-20 11:46:01 -0700134
135
Sangho Shin7330c032014-10-20 10:34:51 -0700136 // ************************************
137 // IFloodlightModule implementation
138 // ************************************
139
Sangho Shin2f263692014-09-15 14:09:41 -0700140 @Override
141 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Srikanth Vavilapalli8c49db72014-10-20 13:35:08 -0700142 Collection<Class<? extends IFloodlightService>> l = new ArrayList<>();
143 l.add(ISegmentRoutingService.class);
144 return l;
Sangho Shin2f263692014-09-15 14:09:41 -0700145 }
146
147 @Override
148 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Srikanth Vavilapalli8c49db72014-10-20 13:35:08 -0700149 Map<Class<? extends IFloodlightService>, IFloodlightService> m = new HashMap<>();
150 m.put(ISegmentRoutingService.class, this);
151 return m;
Sangho Shin2f263692014-09-15 14:09:41 -0700152 }
153
154 @Override
155 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
156 Collection<Class<? extends IFloodlightService>> l = new ArrayList<Class<? extends IFloodlightService>>();
157
158 l.add(IFloodlightProviderService.class);
159 l.add(IConfigInfoService.class);
160 l.add(ITopologyService.class);
161 l.add(IPacketService.class);
162 l.add(IFlowPusherService.class);
163 l.add(ITopologyService.class);
Fahad Naeem Khan4444b952014-10-18 22:30:50 -0700164 l.add(IRestApiService.class);
Sangho Shin2f263692014-09-15 14:09:41 -0700165
166 return l;
167
168 }
169
170 @Override
171 public void init(FloodlightModuleContext context) throws FloodlightModuleException {
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700172 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Sangho Shineb083032014-09-22 16:11:34 -0700173 arpHandler = new ArpHandler(context, this);
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700174 icmpHandler = new IcmpHandler(context, this);
Sangho Shineb083032014-09-22 16:11:34 -0700175 ipHandler = new GenericIpHandler(context, this);
Sangho Shin2f263692014-09-15 14:09:41 -0700176 arpEntries = new ArrayList<ArpEntry>();
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700177 topologyService = context.getServiceImpl(ITopologyService.class);
Sangho Shin43cee112014-09-25 16:43:34 -0700178 threadPool = context.getServiceImpl(IThreadPoolService.class);
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700179 mutableTopology = topologyService.getTopology();
Sangho Shin61535402014-10-01 11:37:14 -0700180 ipPacketQueue = new ConcurrentLinkedQueue<IPv4>();
Sangho Shinfbc572c2014-10-02 16:37:05 -0700181 graphs = new HashMap<Switch, ECMPShortestPathGraph>();
Sangho Shin23f898d2014-10-13 16:54:00 -0700182 linksDown = new HashMap<String, LinkData>();
183 linksToAdd = new HashMap<String, LinkData>();
Sangho Shin5be3e532014-10-03 17:20:58 -0700184 topologyEventQueue = new ConcurrentLinkedQueue<TopologyEvents>();
Sangho Shin15273b62014-10-16 22:22:05 -0700185 packetService = context.getServiceImpl(IPacketService.class);
Fahad Naeem Khan4444b952014-10-18 22:30:50 -0700186 restApi = context.getServiceImpl(IRestApiService.class);
Sangho Shine020cc32014-10-20 13:28:02 -0700187 policyTable = new HashMap<String, PolicyInfo>();
Sangho Shin81655442014-10-20 14:22:46 -0700188 tunnelTable = new HashMap<String, TunnelInfo>();
Sangho Shin204b9972014-10-22 11:08:10 -0700189 adjacencyIdTable = new HashMap<Integer, List<Integer>>();
Sangho Shin2f263692014-09-15 14:09:41 -0700190
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700191 packetService.registerPacketListener(this);
Sangho Shin15273b62014-10-16 22:22:05 -0700192 topologyService.addListener(this, false);
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700193
Sangho Shin99918bd2014-10-08 15:52:35 -0700194
Sangho Shin2f263692014-09-15 14:09:41 -0700195 }
196
197 @Override
198 public void startUp(FloodlightModuleContext context) throws FloodlightModuleException {
Sangho Shinc8d2f592014-09-30 16:53:57 -0700199 ScheduledExecutorService ses = threadPool.getScheduledExecutor();
Fahad Naeem Khan4444b952014-10-18 22:30:50 -0700200 restApi.addRestletRoutable(new SegmentRoutingWebRoutable());
Sangho Shin2f263692014-09-15 14:09:41 -0700201
Sangho Shinc8d2f592014-09-30 16:53:57 -0700202 discoveryTask = new SingletonTask(ses, new Runnable() {
203 @Override
204 public void run() {
Sangho Shin5be3e532014-10-03 17:20:58 -0700205 handleTopologyChangeEvents();
Sangho Shinc8d2f592014-09-30 16:53:57 -0700206 }
207 });
Sangho Shin23f898d2014-10-13 16:54:00 -0700208
209 linkAddTask = new SingletonTask(ses, new Runnable() {
210 @Override
211 public void run() {
212 delayedAddLink();
213 }
214 });
215
Sangho Shin15273b62014-10-16 22:22:05 -0700216 testTask = new SingletonTask(ses, new Runnable() {
217 @Override
218 public void run() {
219 runTest();
220 }
221 });
222
Sangho Shin5b8f5452014-10-20 11:46:01 -0700223 testMode = POLICY_ADD1;
Sangho Shin204b9972014-10-22 11:08:10 -0700224 //testTask.reschedule(20, TimeUnit.SECONDS);
Sangho Shin2f263692014-09-15 14:09:41 -0700225 }
226
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700227 @Override
228 public void receive(Switch sw, Port inPort, Ethernet payload) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700229 if (payload.getEtherType() == Ethernet.TYPE_ARP)
230 arpHandler.processPacketIn(sw, inPort, payload);
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700231 if (payload.getEtherType() == Ethernet.TYPE_IPV4) {
Sangho Shin7330c032014-10-20 10:34:51 -0700232 addPacketToPacketBuffer((IPv4) payload.getPayload());
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700233 if (((IPv4) payload.getPayload()).getProtocol() == IPv4.PROTOCOL_ICMP)
234 icmpHandler.processPacketIn(sw, inPort, payload);
235 else
236 ipHandler.processPacketIn(sw, inPort, payload);
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700237 }
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700238 else {
239 log.debug("{}", payload.toString());
240 }
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700241 }
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700242
Sangho Shin2f263692014-09-15 14:09:41 -0700243
Sangho Shin7330c032014-10-20 10:34:51 -0700244 // ************************************
245 // Topology event handlers
246 // ************************************
Sangho Shineb083032014-09-22 16:11:34 -0700247
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700248 /**
249 * Topology events that have been generated.
Sangho Shinfbc572c2014-10-02 16:37:05 -0700250 *
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700251 * @param topologyEvents the generated Topology Events
252 * @see TopologyEvents
253 */
254 public void topologyEvents(TopologyEvents topologyEvents)
255 {
Sangho Shin5be3e532014-10-03 17:20:58 -0700256 topologyEventQueue.add(topologyEvents);
Sangho Shinbce900e2014-10-07 17:13:23 -0700257 discoveryTask.reschedule(100, TimeUnit.MILLISECONDS);
Sangho Shin5be3e532014-10-03 17:20:58 -0700258 }
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700259
Sangho Shin23f898d2014-10-13 16:54:00 -0700260 /**
261 * Process the multiple topology events with some delay (100MS at most for now)
262 *
263 */
Sangho Shin5be3e532014-10-03 17:20:58 -0700264 private void handleTopologyChangeEvents() {
Sangho Shinbce900e2014-10-07 17:13:23 -0700265 numOfEventProcess ++;
266
Sangho Shin51625342014-10-17 09:30:48 -0700267 Collection<LinkData> linkEntriesAddedAll = new ArrayList<LinkData>();
268 Collection<PortData> portEntriesAddedAll = new ArrayList<PortData>();
269 Collection<PortData> portEntriesRemovedAll = new ArrayList<PortData>();
270 Collection<LinkData> linkEntriesRemovedAll = new ArrayList<LinkData>();
271 Collection<SwitchData> switchAddedAll = new ArrayList<SwitchData>();
272 Collection<SwitchData> switchRemovedAll = new ArrayList<SwitchData>();
273 Collection<MastershipData> mastershipRemovedAll = new ArrayList<MastershipData>();
Sangho Shinbce900e2014-10-07 17:13:23 -0700274
Sangho Shin5be3e532014-10-03 17:20:58 -0700275 while (!topologyEventQueue.isEmpty()) {
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700276 // We should handle the events in the order of when they happen
277 // TODO: We need to simulate the final results of multiple events
278 // and shoot only the final state.
279 // Ex: link s1-s2 down, link s1-s2 up --> Do nothing
280 // Ex: ink s1-s2 up, s1-p1,p2 down --> link s1-s2 down
Sangho Shin51625342014-10-17 09:30:48 -0700281
Sangho Shin5be3e532014-10-03 17:20:58 -0700282 TopologyEvents topologyEvents = topologyEventQueue.poll();
Sangho Shin51625342014-10-17 09:30:48 -0700283
284 Collection<LinkData> linkEntriesAdded = topologyEvents.getAddedLinkDataEntries();
285 Collection<PortData> portEntriesAdded = topologyEvents.getAddedPortDataEntries();
286 Collection<PortData> portEntriesRemoved = topologyEvents.getRemovedPortDataEntries();
287 Collection<LinkData> linkEntriesRemoved = topologyEvents.getRemovedLinkDataEntries();
288 Collection<SwitchData> switchAdded = topologyEvents.getAddedSwitchDataEntries();
289 Collection<SwitchData> switchRemoved = topologyEvents.getRemovedSwitchDataEntries();
290 Collection<MastershipData> mastershipRemoved = topologyEvents.getRemovedMastershipDataEntries();
291
292 linkEntriesAddedAll.addAll(linkEntriesAdded);
293 portEntriesAddedAll.addAll(portEntriesAdded);
294 portEntriesRemovedAll.addAll(portEntriesRemoved);
295 linkEntriesRemovedAll.addAll(linkEntriesRemoved);
296 switchAddedAll.addAll(switchAdded);
297 switchRemovedAll.addAll(switchRemoved);
298 mastershipRemovedAll.addAll(mastershipRemoved);
Sangho Shinbce900e2014-10-07 17:13:23 -0700299 numOfEvents++;
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700300
301 if (!portEntriesRemoved.isEmpty()) {
302 processPortRemoval(portEntriesRemoved);
303 }
304
305 if (!linkEntriesRemoved.isEmpty()) {
306 processLinkRemoval(linkEntriesRemoved);
307 }
308
309 if (!switchRemoved.isEmpty()) {
310 processSwitchRemoved(switchRemoved);
311 }
312
313 if (!mastershipRemoved.isEmpty()) {
Sangho Shin23f898d2014-10-13 16:54:00 -0700314 log.debug("Mastership is removed. Check if ports are down also.");
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700315 }
316
317 if (!linkEntriesAdded.isEmpty()) {
Sangho Shin23f898d2014-10-13 16:54:00 -0700318 processLinkAdd(linkEntriesAdded, false);
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700319 }
320
321 if (!portEntriesAdded.isEmpty()) {
322 processPortAdd(portEntriesAdded);
323 }
324
325 if (!switchAdded.isEmpty()) {
326 processSwitchAdd(switchAdded);
327 }
Sangho Shin51625342014-10-17 09:30:48 -0700328
Sangho Shinbce900e2014-10-07 17:13:23 -0700329 }
330
Sangho Shin23f898d2014-10-13 16:54:00 -0700331 // TODO: 100ms is enough to check both mastership removed events
332 // and the port removed events? What if the PORT_STATUS packets comes late?
Sangho Shin51625342014-10-17 09:30:48 -0700333 if (!mastershipRemovedAll.isEmpty()) {
334 if (portEntriesRemovedAll.isEmpty()) {
Saurav Das82e62972014-10-16 14:53:57 -0700335 log.debug("Just mastership is removed. Do not do anthing.");
Sangho Shin23f898d2014-10-13 16:54:00 -0700336 }
337 else {
338 HashMap<String, MastershipData> mastershipToRemove =
339 new HashMap<String, MastershipData>();
Sangho Shin51625342014-10-17 09:30:48 -0700340 for (MastershipData ms: mastershipRemovedAll) {
341 for (PortData port: portEntriesRemovedAll) {
Sangho Shin23f898d2014-10-13 16:54:00 -0700342 // TODO: check ALL ports of the switch are dead ..
343 if (port.getDpid().equals(ms.getDpid())) {
344 mastershipToRemove.put(ms.getDpid().toString(), ms);
345 }
346 }
347 log.debug("Swtich {} is really down.", ms.getDpid());
348 }
349 processMastershipRemoved(mastershipToRemove.values());
350 }
351 }
352
Sangho Shinbce900e2014-10-07 17:13:23 -0700353 log.debug("num events {}, num of process {}, "
354 + "num of Population {}", numOfEvents, numOfEventProcess,
355 numOfPopulation);
356 }
357
358 /**
Sangho Shin99918bd2014-10-08 15:52:35 -0700359 * Process the SwitchAdded events from topologyMananger.
360 * It does nothing. When a switch is added, then link will be added too.
361 * LinkAdded event will handle process all re-computation.
362 *
363 * @param switchAdded
364 */
365 private void processSwitchAdd(Collection<SwitchData> switchAdded) {
366
367 }
368
369 /**
Sangho Shinbce900e2014-10-07 17:13:23 -0700370 * Remove all ports connected to the switch removed
371 *
372 * @param mastershipRemoved master switch info removed
373 */
374 private void processMastershipRemoved(Collection<MastershipData>
375 mastershipRemoved) {
376 for (MastershipData mastership: mastershipRemoved) {
377 Switch sw = mutableTopology.getSwitch(mastership.getDpid());
378 for (Link link: sw.getOutgoingLinks()) {
379 Port dstPort = link.getDstPort();
380 IOF13Switch dstSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
381 getSwId(dstPort.getDpid().toString()));
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700382 if (dstSw != null) {
383 dstSw.removePortFromGroups(dstPort.getNumber());
384 log.debug("MasterSwitch {} is gone: remove port {}", sw.getDpid(), dstPort);
385 }
Sangho Shinbce900e2014-10-07 17:13:23 -0700386 }
Sangho Shin61535402014-10-01 11:37:14 -0700387 }
Sangho Shin23f898d2014-10-13 16:54:00 -0700388
389 linksToAdd.clear();
390 linksDown.clear();
Sangho Shin61535402014-10-01 11:37:14 -0700391 }
Sangho Shinc8d2f592014-09-30 16:53:57 -0700392
Sangho Shinbce900e2014-10-07 17:13:23 -0700393 /**
394 * Remove all ports connected to the switch removed
395 *
396 * @param switchRemoved Switch removed
397 */
Sangho Shin5be3e532014-10-03 17:20:58 -0700398 private void processSwitchRemoved(Collection<SwitchData> switchRemoved) {
Sangho Shin23f898d2014-10-13 16:54:00 -0700399 log.debug("SwitchRemoved event occurred !!!");
Sangho Shin5be3e532014-10-03 17:20:58 -0700400 }
401
Sangho Shin61535402014-10-01 11:37:14 -0700402 /**
Sangho Shin99918bd2014-10-08 15:52:35 -0700403 * Report ports added to driver
Sangho Shinfbc572c2014-10-02 16:37:05 -0700404 *
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700405 * @param portEntries
406 */
407 private void processPortAdd(Collection<PortData> portEntries) {
Sangho Shin99918bd2014-10-08 15:52:35 -0700408 // TODO: do we need to add ports with delay?
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700409 for (PortData port : portEntries) {
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700410 Dpid dpid = port.getDpid();
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700411
Sangho Shinfbc572c2014-10-02 16:37:05 -0700412 IOF13Switch sw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700413 getSwId(port.getDpid().toString()));
Sangho Shin815af0c2014-10-10 13:05:45 -0700414 if (sw != null) {
Sangho Shin721ca042014-10-09 13:03:40 -0700415 sw.addPortToGroups(port.getPortNumber());
Sangho Shin15273b62014-10-16 22:22:05 -0700416 //log.debug("Add port {} to switch {}", port, dpid);
Sangho Shin815af0c2014-10-10 13:05:45 -0700417 }
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700418 }
419 }
420
421 /**
422 * Reports ports of new links to driver and recalculate ECMP SPG
Sangho Shin23f898d2014-10-13 16:54:00 -0700423 * If the link to add was removed before, then we just schedule the add link
424 * event and do not recompute the path now.
Sangho Shinfbc572c2014-10-02 16:37:05 -0700425 *
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700426 * @param linkEntries
427 */
Sangho Shin23f898d2014-10-13 16:54:00 -0700428 private void processLinkAdd(Collection<LinkData> linkEntries, boolean delayed) {
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700429
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700430 for (LinkData link : linkEntries) {
Sangho Shin5be3e532014-10-03 17:20:58 -0700431
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700432 SwitchPort srcPort = link.getSrc();
433 SwitchPort dstPort = link.getDst();
434
Sangho Shin23f898d2014-10-13 16:54:00 -0700435 String key = srcPort.getDpid().toString() +
436 dstPort.getDpid().toString();
437 if (!delayed) {
438 if (linksDown.containsKey(key)) {
439 linksToAdd.put(key, link);
440 linksDown.remove(key);
441 linkAddTask.reschedule(DELAY_TO_ADD_LINK, TimeUnit.SECONDS);
442 log.debug("Add link {} with 5 sec delay", link);
443 // TODO: What if we have multiple events of add link:
444 // one is new link add, the other one is link up for
445 // broken link? ECMPSPG function cannot deal with it for now
446 return;
447 }
448 }
449 else {
450 if (linksDown.containsKey(key)) {
451 linksToAdd.remove(key);
452 log.debug("Do not add the link {}: it is down again!", link);
453 return;
454 }
455 }
456
Sangho Shinfbc572c2014-10-02 16:37:05 -0700457 IOF13Switch srcSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700458 getSwId(srcPort.getDpid().toString()));
Sangho Shinfbc572c2014-10-02 16:37:05 -0700459 IOF13Switch dstSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700460 getSwId(dstPort.getDpid().toString()));
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700461
Sangho Shin815af0c2014-10-10 13:05:45 -0700462 if ((srcSw == null) || (dstSw == null))
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700463 continue;
464
465 srcSw.addPortToGroups(srcPort.getPortNumber());
466 dstSw.addPortToGroups(dstPort.getPortNumber());
Sangho Shin5be3e532014-10-03 17:20:58 -0700467
Sangho Shin15273b62014-10-16 22:22:05 -0700468 //log.debug("Add a link port {} to switch {} to add link {}", srcPort, srcSw,
469 // link);
470 //log.debug("Add a link port {} to switch {} to add link {}", dstPort, dstSw,
471 // link);
Sangho Shin815af0c2014-10-10 13:05:45 -0700472
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700473 }
Sangho Shinbce900e2014-10-07 17:13:23 -0700474 populateEcmpRoutingRules(false);
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700475 }
476
477 /**
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700478 * Check if all links are gone b/w the two switches. If all links are gone,
479 * then we need to recalculate the path. Otherwise, just report link failure
480 * to the driver.
Sangho Shinfbc572c2014-10-02 16:37:05 -0700481 *
Sangho Shin61535402014-10-01 11:37:14 -0700482 * @param linkEntries
483 */
484 private void processLinkRemoval(Collection<LinkData> linkEntries) {
Sangho Shinbce900e2014-10-07 17:13:23 -0700485 boolean recomputationRequired = false;
486
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700487 for (LinkData link : linkEntries) {
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700488 SwitchPort srcPort = link.getSrc();
489 SwitchPort dstPort = link.getDst();
Sangho Shinc8d2f592014-09-30 16:53:57 -0700490
Sangho Shinfbc572c2014-10-02 16:37:05 -0700491 IOF13Switch srcSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700492 getSwId(srcPort.getDpid().toString()));
Sangho Shinfbc572c2014-10-02 16:37:05 -0700493 IOF13Switch dstSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700494 getSwId(dstPort.getDpid().toString()));
Sangho Shin815af0c2014-10-10 13:05:45 -0700495 if ((srcSw == null) || (dstSw == null))
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700496 /* If this link is not between two switches, ignore it */
497 continue;
Sangho Shin23f898d2014-10-13 16:54:00 -0700498
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700499 srcSw.removePortFromGroups(srcPort.getPortNumber());
500 dstSw.removePortFromGroups(dstPort.getPortNumber());
Sangho Shin815af0c2014-10-10 13:05:45 -0700501 log.debug("Remove port {} from switch {}", srcPort, srcSw);
502 log.debug("Remove port {} from switch {}", dstPort, dstSw);
503
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700504 Switch srcSwitch = mutableTopology.getSwitch(srcPort.getDpid());
505 if (srcSwitch.getLinkToNeighbor(dstPort.getDpid()) == null) {
Sangho Shinbce900e2014-10-07 17:13:23 -0700506 // TODO: it is only for debugging purpose.
Sangho Shin99918bd2014-10-08 15:52:35 -0700507 // We just need to call populateEcmpRoutingRules() and return;
Sangho Shinbce900e2014-10-07 17:13:23 -0700508 recomputationRequired = true;
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700509 log.debug("All links are gone b/w {} and {}", srcPort.getDpid(),
Sangho Shin5be3e532014-10-03 17:20:58 -0700510 dstPort.getDpid());
Sangho Shinc8d2f592014-09-30 16:53:57 -0700511 }
Sangho Shin23f898d2014-10-13 16:54:00 -0700512
513 String key = link.getSrc().getDpid().toString()+
514 link.getDst().getDpid().toString();
515 if (!linksDown.containsKey(key)) {
516 linksDown.put(key, link);
517 }
Sangho Shinc8d2f592014-09-30 16:53:57 -0700518 }
Sangho Shinbce900e2014-10-07 17:13:23 -0700519
520 if (recomputationRequired)
521 populateEcmpRoutingRules(false);
Sangho Shin61535402014-10-01 11:37:14 -0700522 }
Sangho Shinc8d2f592014-09-30 16:53:57 -0700523
Sangho Shin61535402014-10-01 11:37:14 -0700524 /**
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700525 * report ports removed to the driver immediately
Sangho Shinfbc572c2014-10-02 16:37:05 -0700526 *
Sangho Shin61535402014-10-01 11:37:14 -0700527 * @param portEntries
528 */
529 private void processPortRemoval(Collection<PortData> portEntries) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700530 for (PortData port : portEntries) {
Sangho Shin61535402014-10-01 11:37:14 -0700531 Dpid dpid = port.getDpid();
Sangho Shin61535402014-10-01 11:37:14 -0700532
Sangho Shinfbc572c2014-10-02 16:37:05 -0700533 IOF13Switch sw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin61535402014-10-01 11:37:14 -0700534 getSwId(port.getDpid().toString()));
Sangho Shin815af0c2014-10-10 13:05:45 -0700535 if (sw != null) {
Sangho Shinfbc572c2014-10-02 16:37:05 -0700536 sw.removePortFromGroups(port.getPortNumber());
Sangho Shin815af0c2014-10-10 13:05:45 -0700537 log.debug("Remove port {} from switch {}", port, dpid);
538 }
Sangho Shin61535402014-10-01 11:37:14 -0700539 }
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700540 }
Sangho Shin1aa93542014-09-22 09:49:44 -0700541
542 /**
Sangho Shin7330c032014-10-20 10:34:51 -0700543 * Add the link immediately
544 * The function is scheduled when link add event happens and called
545 * DELAY_TO_ADD_LINK seconds after the event to avoid link flip-flop.
546 */
547 private void delayedAddLink() {
548
549 processLinkAdd(linksToAdd.values(), true);
550
551 }
552
553
554 // ************************************
555 // ECMP shorted path routing functions
556 // ************************************
557
558 /**
Sangho Shin43cee112014-09-25 16:43:34 -0700559 * Populate routing rules walking through the ECMP shortest paths
Sangho Shinfbc572c2014-10-02 16:37:05 -0700560 *
Sangho Shin99918bd2014-10-08 15:52:35 -0700561 * @param modified if true, it "modifies" the rules
Sangho Shin1aa93542014-09-22 09:49:44 -0700562 */
Sangho Shin5be3e532014-10-03 17:20:58 -0700563 private void populateEcmpRoutingRules(boolean modified) {
564 graphs.clear();
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700565 Iterable<Switch> switches = mutableTopology.getSwitches();
Sangho Shin43cee112014-09-25 16:43:34 -0700566 for (Switch sw : switches) {
567 ECMPShortestPathGraph ecmpSPG = new ECMPShortestPathGraph(sw);
Sangho Shinfbc572c2014-10-02 16:37:05 -0700568 graphs.put(sw, ecmpSPG);
569 //log.debug("ECMPShortestPathGraph is computed for switch {}",
570 // HexString.toHexString(sw.getDpid().value()));
Sangho Shin5be3e532014-10-03 17:20:58 -0700571 populateEcmpRoutingRulesForPath(sw, ecmpSPG, modified);
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700572
573 // Set adjacency routing rule for all switches
574 try {
575 populateAdjacencyncyRule(sw);
576 } catch (JSONException e) {
577 // TODO Auto-generated catch block
578 e.printStackTrace();
579 }
Sangho Shinfbc572c2014-10-02 16:37:05 -0700580 }
Sangho Shinbce900e2014-10-07 17:13:23 -0700581 numOfPopulation++;
Sangho Shinfbc572c2014-10-02 16:37:05 -0700582 }
Sangho Shin1aa93542014-09-22 09:49:44 -0700583
Sangho Shin204b9972014-10-22 11:08:10 -0700584 /**
585 * populate the MPLS rules to handle Adjacency IDs
586 *
587 * @param sw Switch
588 * @throws JSONException
589 */
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700590 private void populateAdjacencyncyRule(Switch sw) throws JSONException {
591 String adjInfo = sw.getStringAttribute("adjacencySids");
Sangho Shin204b9972014-10-22 11:08:10 -0700592 String nodeSidStr = sw.getStringAttribute("nodeSid");
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700593 String srcMac = sw.getStringAttribute("routerMac");
Sangho Shin204b9972014-10-22 11:08:10 -0700594 String autoAdjInfo = sw.getStringAttribute("autogenAdjSids");
595
596 if (adjInfo == null || srcMac == null || nodeSidStr == null)
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700597 return;
598
599 JSONArray arry = new JSONArray(adjInfo);
600 for (int i = 0; i < arry.length(); i++) {
Sangho Shin204b9972014-10-22 11:08:10 -0700601 //Object a = arry.getJSONObject(i);
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700602 Integer adjId = (Integer) arry.getJSONObject(i).get("adjSid");
Sangho Shin204b9972014-10-22 11:08:10 -0700603 JSONArray portNos = (JSONArray) arry.getJSONObject(i).get("ports");
604 if (adjId == null || portNos == null)
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700605 continue;
606
Sangho Shin204b9972014-10-22 11:08:10 -0700607 List<Integer> portNoList = new ArrayList<Integer>();
608 for (int j = 0; j < portNos.length(); j++) {
609 portNoList.add(Integer.valueOf(portNos.getInt(0)));
610 }
611
612 adjacencyIdTable.put(Integer.parseInt(nodeSidStr), portNoList);
613
614 /*
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700615 Dpid dstDpid = null;
616 for (Link link: sw.getOutgoingLinks()) {
Sangho Shin204b9972014-10-22 11:08:10 -0700617 if (link.getSrcPort().getPortNumber().value() == portNos[1]) {
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700618 dstDpid = link.getDstPort().getDpid();
619 break;
620 }
621 }
622 if (dstDpid == null) {
623 log.debug("Cannot find the destination switch for the adjacency ID {}", adjId);
624 continue;
625 }
626 Switch dstSw = mutableTopology.getSwitch(dstDpid);
627 String dstMac = null;
628 if (dstSw == null) {
629 log.debug("Cannot find SW {}", dstDpid.toString());
630 continue;
631 }
632 else {
633 dstMac = dstSw.getStringAttribute("routerMac");
634 }
635
636 setAdjRule(sw, adjId, srcMac, dstMac, portNo, true); // BoS = 1
637 setAdjRule(sw, adjId, srcMac, dstMac, portNo, false); // BoS = 0
Sangho Shin204b9972014-10-22 11:08:10 -0700638 */
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700639 }
640
641 }
642
Sangho Shin204b9972014-10-22 11:08:10 -0700643 /**
644 * Push the MPLS rule for Adjacency ID
645 *
646 * @param sw Switch to push the rule
647 * @param id Adjacency ID
648 * @param srcMac source MAC address
649 * @param dstMac destination MAC address
650 * @param portNo port number assigned to the ID
651 * @param bos BoS option
652 */
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700653 private void setAdjRule(Switch sw, int id, String srcMac, String dstMac, int portNo,
654 boolean bos) {
655
656 MplsMatch mplsMatch = new MplsMatch(id, bos);
657 List<Action> actions = new ArrayList<Action>();
658
659 if (bos) {
660 PopMplsAction popAction = new PopMplsAction(EthType.IPv4);
661 CopyTtlInAction copyTtlInAction = new CopyTtlInAction();
662 DecNwTtlAction decNwTtlAction = new DecNwTtlAction(1);
663 actions.add(copyTtlInAction);
664 actions.add(popAction);
665 actions.add(decNwTtlAction);
666 }
667 else {
668 PopMplsAction popAction = new PopMplsAction(EthType.MPLS_UNICAST);
669 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
670 actions.add(popAction);
671 actions.add(decMplsTtlAction);
672 }
673
674 ModifyDstMacAction setDstAction = new ModifyDstMacAction(MACAddress.valueOf(srcMac));
675 ModifySrcMacAction setSrcAction = new ModifySrcMacAction(MACAddress.valueOf(dstMac));
676 OutputAction outportAction = new OutputAction(PortNumber.uint32(portNo));
677
678 actions.add(setDstAction);
679 actions.add(setSrcAction);
680 actions.add(outportAction);
681
682 MatchAction matchAction = new MatchAction(new MatchActionId(matchActionId++),
683 new SwitchPort((long) 0, (short) 0), mplsMatch, actions);
684 Operator operator = Operator.ADD;
685 MatchActionOperationEntry maEntry =
686 new MatchActionOperationEntry(operator, matchAction);
687
688 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
689 getSwId(sw.getDpid().toString()));
690
691 if (sw13 != null) {
692 try {
693 //printMatchActionOperationEntry(sw, maEntry);
694 sw13.pushFlow(maEntry);
695 } catch (IOException e) {
696 e.printStackTrace();
697 }
698 }
699 }
700
Sangho Shin99918bd2014-10-08 15:52:35 -0700701 /**
702 * populate routing rules to forward packets from the switch given to
703 * all other switches.
704 *
705 * @param sw source switch
706 * @param ecmpSPG shortest path from the the source switch to all others
707 * @param modified modification flag
708 */
Sangho Shinfbc572c2014-10-02 16:37:05 -0700709 private void populateEcmpRoutingRulesForPath(Switch sw,
Sangho Shin5be3e532014-10-03 17:20:58 -0700710 ECMPShortestPathGraph ecmpSPG, boolean modified) {
Sangho Shin43cee112014-09-25 16:43:34 -0700711
Sangho Shinfbc572c2014-10-02 16:37:05 -0700712 HashMap<Integer, HashMap<Switch, ArrayList<ArrayList<Dpid>>>> switchVia =
713 ecmpSPG.getAllLearnedSwitchesAndVia();
714 for (Integer itrIdx : switchVia.keySet()) {
715 //log.debug("ECMPShortestPathGraph:Switches learned in "
716 // + "Iteration{} from switch {}:",
717 // itrIdx,
718 // HexString.toHexString(sw.getDpid().value()));
719 HashMap<Switch, ArrayList<ArrayList<Dpid>>> swViaMap =
720 switchVia.get(itrIdx);
721 for (Switch targetSw : swViaMap.keySet()) {
Sangho Shin5be3e532014-10-03 17:20:58 -0700722 //log.debug("ECMPShortestPathGraph:****switch {} via:",
723 // HexString.toHexString(targetSw.getDpid().value()));
Sangho Shinfbc572c2014-10-02 16:37:05 -0700724 String destSw = sw.getDpid().toString();
725 List<String> fwdToSw = new ArrayList<String>();
726
Sangho Shinfbc572c2014-10-02 16:37:05 -0700727 for (ArrayList<Dpid> via : swViaMap.get(targetSw)) {
Sangho Shin5be3e532014-10-03 17:20:58 -0700728 //log.debug("ECMPShortestPathGraph:******{}) {}", ++i, via);
Sangho Shinfbc572c2014-10-02 16:37:05 -0700729 if (via.isEmpty()) {
730 fwdToSw.add(destSw);
Sangho Shin43cee112014-09-25 16:43:34 -0700731 }
Sangho Shinfbc572c2014-10-02 16:37:05 -0700732 else {
733 fwdToSw.add(via.get(0).toString());
734 }
Sangho Shin43cee112014-09-25 16:43:34 -0700735 }
Sangho Shin5be3e532014-10-03 17:20:58 -0700736 setRoutingRule(targetSw, destSw, fwdToSw, modified);
Sangho Shineb083032014-09-22 16:11:34 -0700737 }
Sangho Shinfbc572c2014-10-02 16:37:05 -0700738
739 // Send Barrier Message and make sure all rules are set
740 // before we set the rules to next routers
Saurav Dasa962a692014-10-17 14:52:38 -0700741 // TODO: barriers to all switches in this update stage
Sangho Shinfbc572c2014-10-02 16:37:05 -0700742 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
743 getSwId(sw.getDpid().toString()));
Sangho Shin5be3e532014-10-03 17:20:58 -0700744 if (sw13 != null) {
Saurav Dasa962a692014-10-17 14:52:38 -0700745 OFBarrierReplyFuture replyFuture = null;
Sangho Shin5be3e532014-10-03 17:20:58 -0700746 try {
Saurav Dasa962a692014-10-17 14:52:38 -0700747 replyFuture = sw13.sendBarrier();
Sangho Shin5be3e532014-10-03 17:20:58 -0700748 } catch (IOException e) {
Saurav Dasa962a692014-10-17 14:52:38 -0700749 log.error("Error sending barrier request to switch {}",
750 sw13.getId(), e.getCause());
Sangho Shin5be3e532014-10-03 17:20:58 -0700751 }
Saurav Dasa962a692014-10-17 14:52:38 -0700752 OFBarrierReply br = null;
753 try {
754 br = replyFuture.get(2, TimeUnit.SECONDS);
755 } catch (TimeoutException | InterruptedException | ExecutionException e) {
756 // XXX for some reason these exceptions are not being thrown
757 }
758 if (br == null) {
759 log.warn("Did not receive barrier-reply from {}", sw13.getId());
760 // XXX take corrective action
761 }
762
Sangho Shinfbc572c2014-10-02 16:37:05 -0700763 }
764 }
765
766 }
767
Sangho Shinfbc572c2014-10-02 16:37:05 -0700768 /**
769 *
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700770 * Set routing rules in targetSw {forward packets to fwdToSw switches in
771 * order to send packets to destSw} - If the target switch is an edge router
772 * and final destnation switch is also an edge router, then set IP
773 * forwarding rules to subnets - If only the target switch is an edge
774 * router, then set IP forwarding rule to the transit router loopback IP
775 * address - If the target is a transit router, then just set the MPLS
776 * forwarding rule
Sangho Shinfbc572c2014-10-02 16:37:05 -0700777 *
Sangho Shin43cee112014-09-25 16:43:34 -0700778 * @param targetSw Switch to set the rules
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700779 * @param destSw Final destination switches
Sangho Shin43cee112014-09-25 16:43:34 -0700780 * @param fwdToSw next hop switches
781 */
Sangho Shin99918bd2014-10-08 15:52:35 -0700782 private void setRoutingRule(Switch targetSw, String destSw,
783 List<String> fwdToSw, boolean modified) {
Sangho Shin43cee112014-09-25 16:43:34 -0700784
Sangho Shin43cee112014-09-25 16:43:34 -0700785 if (fwdToSw.isEmpty()) {
786 fwdToSw.add(destSw);
787 }
788
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700789 // if both target SW and dest SW are an edge router, then set IP table
Sangho Shin43cee112014-09-25 16:43:34 -0700790 if (IsEdgeRouter(targetSw.getDpid().toString()) &&
791 IsEdgeRouter(destSw)) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700792 // We assume that there is at least one transit router b/w edge
793 // routers
Sangho Shin43cee112014-09-25 16:43:34 -0700794 Switch destSwitch = mutableTopology.getSwitch(new Dpid(destSw));
795 String subnets = destSwitch.getStringAttribute("subnets");
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700796 setIpTableRouterSubnet(targetSw, subnets, getMplsLabel(destSw)
Sangho Shin5be3e532014-10-03 17:20:58 -0700797 , fwdToSw, modified);
Sangho Shin43cee112014-09-25 16:43:34 -0700798
Sangho Shin43cee112014-09-25 16:43:34 -0700799 String routerIp = destSwitch.getStringAttribute("routerIp");
Sangho Shin5be3e532014-10-03 17:20:58 -0700800 setIpTableRouter(targetSw, routerIp, getMplsLabel(destSw), fwdToSw,
801 null, modified);
Sangho Shin721ca042014-10-09 13:03:40 -0700802 // Edge router can be a transit router
803 setMplsTable(targetSw, getMplsLabel(destSw), fwdToSw, modified);
Sangho Shin43cee112014-09-25 16:43:34 -0700804 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700805 // Only if the target switch is the edge router, then set the IP rules
Sangho Shin43cee112014-09-25 16:43:34 -0700806 else if (IsEdgeRouter(targetSw.getDpid().toString())) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700807 // We assume that there is at least one transit router b/w edge
808 // routers
Sangho Shin43cee112014-09-25 16:43:34 -0700809 Switch destSwitch = mutableTopology.getSwitch(new Dpid(destSw));
810 String routerIp = destSwitch.getStringAttribute("routerIp");
Sangho Shin5be3e532014-10-03 17:20:58 -0700811 setIpTableRouter(targetSw, routerIp, getMplsLabel(destSw), fwdToSw,
812 null, modified);
Sangho Shin721ca042014-10-09 13:03:40 -0700813 // Edge router can be a transit router
814 setMplsTable(targetSw, getMplsLabel(destSw), fwdToSw, modified);
Sangho Shin43cee112014-09-25 16:43:34 -0700815 }
816 // if it is a transit router, then set rules in the MPLS table
817 else {
Sangho Shin5be3e532014-10-03 17:20:58 -0700818 setMplsTable(targetSw, getMplsLabel(destSw), fwdToSw, modified);
Sangho Shin43cee112014-09-25 16:43:34 -0700819 }
820
821 }
822
Sangho Shinfbc572c2014-10-02 16:37:05 -0700823 /**
824 * Set IP forwarding rule to the gateway of each subnet of switches
825 *
826 * @param targetSw Switch to set rules
827 * @param subnets subnet information
828 * @param mplsLabel destination MPLS label
829 * @param fwdToSw router to forward packets to
830 */
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700831 private void setIpTableRouterSubnet(Switch targetSw, String subnets,
Sangho Shin5be3e532014-10-03 17:20:58 -0700832 String mplsLabel, List<String> fwdToSw, boolean modified) {
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700833
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700834 Collection<MatchActionOperationEntry> entries =
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700835 new ArrayList<MatchActionOperationEntry>();
836
837 try {
838 JSONArray arry = new JSONArray(subnets);
839 for (int i = 0; i < arry.length(); i++) {
840 String subnetIp = (String) arry.getJSONObject(i).get("subnetIp");
Sangho Shin5be3e532014-10-03 17:20:58 -0700841 setIpTableRouter(targetSw, subnetIp, mplsLabel, fwdToSw, entries,
842 modified);
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700843 }
844 } catch (JSONException e) {
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700845 e.printStackTrace();
846 }
847
848 if (!entries.isEmpty()) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700849 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700850 getSwId(targetSw.getDpid().toString()));
851
Sangho Shin721ca042014-10-09 13:03:40 -0700852 if (sw13 != null) {
853 try {
854 sw13.pushFlows(entries);
855 } catch (IOException e) {
856 e.printStackTrace();
857 }
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700858 }
859 }
860
861 }
862
Sangho Shin43cee112014-09-25 16:43:34 -0700863 /**
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700864 * Set IP forwarding rule - If the destination is the next hop, then do not
865 * push MPLS, just decrease the NW TTL - Otherwise, push MPLS label and set
866 * the MPLS ID
Sangho Shinfbc572c2014-10-02 16:37:05 -0700867 *
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700868 * @param sw target switch to set rules
Sangho Shin43cee112014-09-25 16:43:34 -0700869 * @param subnetIp Match IP address
870 * @param mplsLabel MPLS label of final destination router
871 * @param fwdToSws next hop routers
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700872 * @param entries
Sangho Shin43cee112014-09-25 16:43:34 -0700873 */
874 private void setIpTableRouter(Switch sw, String subnetIp, String mplsLabel,
Sangho Shin5be3e532014-10-03 17:20:58 -0700875 List<String> fwdToSws, Collection<MatchActionOperationEntry> entries,
876 boolean modified) {
Sangho Shin43cee112014-09-25 16:43:34 -0700877
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700878 Ipv4Match ipMatch = new Ipv4Match(subnetIp);
Sangho Shin43cee112014-09-25 16:43:34 -0700879 List<Action> actions = new ArrayList<>();
Sangho Shin721ca042014-10-09 13:03:40 -0700880 GroupAction groupAction = new GroupAction();
Sangho Shin43cee112014-09-25 16:43:34 -0700881
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700882 // If destination SW is the same as the fwd SW, then do not push MPLS
883 // label
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700884 if (fwdToSws.size() > 1) {
Sangho Shin43cee112014-09-25 16:43:34 -0700885 PushMplsAction pushMplsAction = new PushMplsAction();
886 SetMplsIdAction setIdAction = new SetMplsIdAction(Integer.parseInt(mplsLabel));
887 CopyTtlOutAction copyTtlOutAction = new CopyTtlOutAction();
Sangho Shin463bee52014-09-29 15:14:43 -0700888 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
Sangho Shin43cee112014-09-25 16:43:34 -0700889
Sangho Shin62ce5c12014-10-08 16:24:40 -0700890 //actions.add(pushMplsAction);
891 //actions.add(copyTtlOutAction);
892 //actions.add(decMplsTtlAction);
Saurav Das82e62972014-10-16 14:53:57 -0700893 // actions.add(setIdAction);
Sangho Shin721ca042014-10-09 13:03:40 -0700894 groupAction.setEdgeLabel(Integer.parseInt(mplsLabel));
Sangho Shin43cee112014-09-25 16:43:34 -0700895 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700896 else {
897 String fwdToSw = fwdToSws.get(0);
898 if (getMplsLabel(fwdToSw).equals(mplsLabel)) {
899 DecNwTtlAction decTtlAction = new DecNwTtlAction(1);
900 actions.add(decTtlAction);
901 }
902 else {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700903 SetMplsIdAction setIdAction = new SetMplsIdAction(
904 Integer.parseInt(mplsLabel));
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700905 CopyTtlOutAction copyTtlOutAction = new CopyTtlOutAction();
Sangho Shin463bee52014-09-29 15:14:43 -0700906 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700907
Sangho Shin62ce5c12014-10-08 16:24:40 -0700908 //actions.add(pushMplsAction);
909 //actions.add(copyTtlOutAction);
910 //actions.add(decMplsTtlAction);
Saurav Das82e62972014-10-16 14:53:57 -0700911 // actions.add(setIdAction);
Sangho Shin721ca042014-10-09 13:03:40 -0700912 groupAction.setEdgeLabel(Integer.parseInt(mplsLabel));
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700913 }
914 }
Sangho Shin43cee112014-09-25 16:43:34 -0700915
Sangho Shin43cee112014-09-25 16:43:34 -0700916 for (String fwdSw : fwdToSws) {
917 groupAction.addSwitch(new Dpid(fwdSw));
918 }
919 actions.add(groupAction);
920
Sangho Shin99918bd2014-10-08 15:52:35 -0700921 MatchAction matchAction = new MatchAction(new MatchActionId(matchActionId++),
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700922 new SwitchPort((long) 0, (short) 0), ipMatch, actions);
Sangho Shin43cee112014-09-25 16:43:34 -0700923
Sangho Shin5be3e532014-10-03 17:20:58 -0700924 Operator operator = null;
925 if (modified)
926 operator = Operator.MODIFY;
927 else
928 operator = Operator.ADD;
929
Sangho Shin43cee112014-09-25 16:43:34 -0700930 MatchActionOperationEntry maEntry =
Sangho Shin5be3e532014-10-03 17:20:58 -0700931 new MatchActionOperationEntry(operator, matchAction);
Sangho Shin43cee112014-09-25 16:43:34 -0700932
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700933 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700934 getSwId(sw.getDpid().toString()));
935
Sangho Shin5be3e532014-10-03 17:20:58 -0700936 if (sw13 != null) {
937 try {
Sangho Shinbce900e2014-10-07 17:13:23 -0700938 //printMatchActionOperationEntry(sw, maEntry);
Sangho Shin5be3e532014-10-03 17:20:58 -0700939 if (entries != null)
940 entries.add(maEntry);
941 else
942 sw13.pushFlow(maEntry);
943 } catch (IOException e) {
944 e.printStackTrace();
945 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700946 }
947
Sangho Shin43cee112014-09-25 16:43:34 -0700948 }
949
Sangho Shinac5ee2b2014-09-28 21:27:20 -0700950 /**
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700951 * Set MPLS forwarding rules to MPLS table
952 * </p>
953 * If the destination is the same as the next hop to forward packets then,
954 * pop the MPLS label according to PHP rule. Here, if BoS is set, then
955 * copy TTL In and decrement NW TTL. Otherwise, it just decrement the MPLS
956 * TTL of the another MPLS header.
957 * If the next hop is not the destination, just forward packets to next
958 * hops using Group action.
Sangho Shinfbc572c2014-10-02 16:37:05 -0700959 *
Sangho Shin204b9972014-10-22 11:08:10 -0700960 * TODO: refactoring required
961 *
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700962 * @param sw Switch to set the rules
Sangho Shin43cee112014-09-25 16:43:34 -0700963 * @param mplsLabel destination MPLS label
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700964 * @param fwdSws next hop switches
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700965 * */
Sangho Shin5be3e532014-10-03 17:20:58 -0700966 private void setMplsTable(Switch sw, String mplsLabel, List<String> fwdSws,
967 boolean modified) {
Sangho Shin463bee52014-09-29 15:14:43 -0700968
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700969 if (fwdSws.isEmpty())
970 return;
Sangho Shin43cee112014-09-25 16:43:34 -0700971
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700972 Collection<MatchActionOperationEntry> maEntries =
973 new ArrayList<MatchActionOperationEntry>();
974 String fwdSw1 = fwdSws.get(0);
Sangho Shin43cee112014-09-25 16:43:34 -0700975
Sangho Shin204b9972014-10-22 11:08:10 -0700976 //If the next hop is the destination router
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700977 if (fwdSws.size() == 1 && mplsLabel.equals(getMplsLabel(fwdSw1))) {
978 // One rule for Bos = 1
979 MplsMatch mplsMatch = new MplsMatch(Integer.parseInt(mplsLabel), true);
980 List<Action> actions = new ArrayList<Action>();
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700981
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700982 PopMplsAction popAction = new PopMplsAction(EthType.IPv4);
983 CopyTtlInAction copyTtlInAction = new CopyTtlInAction();
984 DecNwTtlAction decNwTtlAction = new DecNwTtlAction(1);
985
986 actions.add(copyTtlInAction);
987 actions.add(popAction);
988 actions.add(decNwTtlAction);
989
990 GroupAction groupAction = new GroupAction();
991 groupAction.addSwitch(new Dpid(fwdSw1));
992 actions.add(groupAction);
993
994 MatchAction matchAction = new MatchAction(new MatchActionId(matchActionId++),
995 new SwitchPort((long) 0, (short) 0), mplsMatch, actions);
996 Operator operator = Operator.ADD;
997 MatchActionOperationEntry maEntry =
998 new MatchActionOperationEntry(operator, matchAction);
999 maEntries.add(maEntry);
1000
1001 // One rule for Bos = 0
Sangho Shin23f898d2014-10-13 16:54:00 -07001002 MplsMatch mplsMatchBos = new MplsMatch(Integer.parseInt(mplsLabel), false);
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001003 List<Action> actionsBos = new ArrayList<Action>();
Sangho Shin15273b62014-10-16 22:22:05 -07001004 PopMplsAction popActionBos = new PopMplsAction(EthType.MPLS_UNICAST);
1005 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
1006
1007 actionsBos.add(copyTtlInAction);
1008 actionsBos.add(popActionBos);
1009 actionsBos.add(decMplsTtlAction);
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001010 actionsBos.add(groupAction);
1011
1012 MatchAction matchActionBos = new MatchAction(new MatchActionId(matchActionId++),
1013 new SwitchPort((long) 0, (short) 0), mplsMatchBos, actionsBos);
1014 MatchActionOperationEntry maEntryBos =
1015 new MatchActionOperationEntry(operator, matchActionBos);
1016 maEntries.add(maEntryBos);
Sangho Shin9c0f4c32014-09-26 16:02:38 -07001017 }
Sangho Shin204b9972014-10-22 11:08:10 -07001018 // If the next hop is NOT the destination router
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001019 else {
Sangho Shin204b9972014-10-22 11:08:10 -07001020 // BoS = 0
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001021 MplsMatch mplsMatch = new MplsMatch(Integer.parseInt(mplsLabel), false);
1022 List<Action> actions = new ArrayList<Action>();
Sangho Shin43cee112014-09-25 16:43:34 -07001023
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001024 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
1025 actions.add(decMplsTtlAction);
Sangho Shin43cee112014-09-25 16:43:34 -07001026
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001027 GroupAction groupAction = new GroupAction();
1028 for (String fwdSw : fwdSws)
1029 groupAction.addSwitch(new Dpid(fwdSw));
1030 actions.add(groupAction);
Sangho Shin5be3e532014-10-03 17:20:58 -07001031
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001032 MatchAction matchAction = new MatchAction(new MatchActionId(
1033 matchActionId++),
1034 new SwitchPort((long) 0, (short) 0), mplsMatch, actions);
1035 Operator operator = Operator.ADD;
1036 MatchActionOperationEntry maEntry =
1037 new MatchActionOperationEntry(operator, matchAction);
1038 maEntries.add(maEntry);
Sangho Shine2e9bcd2014-10-13 15:14:18 -07001039
1040 // BoS = 1
1041 MplsMatch mplsMatchBoS = new MplsMatch(Integer.parseInt(mplsLabel), true);
1042 List<Action> actionsBoS = new ArrayList<Action>();
1043
1044 DecMplsTtlAction decMplsTtlActionBoS = new DecMplsTtlAction(1);
1045 actionsBoS.add(decMplsTtlActionBoS);
1046
1047 GroupAction groupActionBoS = new GroupAction();
1048 for (String fwdSw : fwdSws)
1049 groupActionBoS.addSwitch(new Dpid(fwdSw));
1050 actionsBoS.add(groupActionBoS);
1051
1052 MatchAction matchActionBos = new MatchAction(new MatchActionId(
1053 matchActionId++),
1054 new SwitchPort((long) 0, (short) 0), mplsMatchBoS, actionsBoS);
1055 MatchActionOperationEntry maEntryBoS =
1056 new MatchActionOperationEntry(operator, matchActionBos);
1057 maEntries.add(maEntryBoS);
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001058 }
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001059 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin9c0f4c32014-09-26 16:02:38 -07001060 getSwId(sw.getDpid().toString()));
1061
Sangho Shin5be3e532014-10-03 17:20:58 -07001062 if (sw13 != null) {
1063 try {
Sangho Shinbce900e2014-10-07 17:13:23 -07001064 //printMatchActionOperationEntry(sw, maEntry);
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001065 sw13.pushFlows(maEntries);
Sangho Shin5be3e532014-10-03 17:20:58 -07001066 } catch (IOException e) {
1067 e.printStackTrace();
1068 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -07001069 }
Sangho Shin43cee112014-09-25 16:43:34 -07001070 }
1071
Sangho Shin7330c032014-10-20 10:34:51 -07001072
1073 // ************************************
1074 // Policy routing classes and functions
1075 // ************************************
1076
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001077 public class PolicyInfo {
Sangho Shin5b8f5452014-10-20 11:46:01 -07001078
Sangho Shin58182672014-10-21 13:23:38 -07001079 public final int TYPE_EXPLICIT = 1;
1080 public final int TYPE_AVOID = 2;
1081
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001082 private String policyId;
1083 private PacketMatch match;
1084 private int priority;
1085 private String tunnelId;
Sangho Shin58182672014-10-21 13:23:38 -07001086 private int type;
Sangho Shin5b8f5452014-10-20 11:46:01 -07001087
Sangho Shin58182672014-10-21 13:23:38 -07001088 public PolicyInfo(String pid, int type, PacketMatch match, int priority,
1089 String tid) {
1090 this.policyId = pid;
1091 this.match = match;
1092 this.priority = priority;
1093 this.tunnelId = tid;
1094 this.type = type;
1095 }
Sangho Shin204b9972014-10-22 11:08:10 -07001096
Fahad Naeem Khan95aa4012014-10-21 14:07:00 -07001097 public PolicyInfo(String pid, PacketMatch match, int priority,
1098 String tid) {
1099 this.policyId = pid;
1100 this.match = match;
1101 this.priority = priority;
1102 this.tunnelId = tid;
Fahad Naeem Khan788895c2014-10-21 19:00:24 -07001103 this.type = 0;
Fahad Naeem Khan95aa4012014-10-21 14:07:00 -07001104 }
1105 public String getPolicyId(){
1106 return this.policyId;
1107 }
1108 public PacketMatch getMatch(){
1109 return this.match;
1110 }
1111 public int getPriority(){
1112 return this.priority;
1113 }
1114 public String getTunnelId(){
1115 return this.tunnelId;
1116 }
1117 public int getType(){
1118 return this.type;
1119 }
Sangho Shin5b8f5452014-10-20 11:46:01 -07001120 }
1121
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001122 public class TunnelInfo {
1123 private String tunnelId;
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001124 private List<Integer> labelIds;
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001125 private List<TunnelRouteInfo> routes;
Sangho Shin81655442014-10-20 14:22:46 -07001126
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001127 public TunnelInfo(String tid, List<Integer> labelIds, List<TunnelRouteInfo> routes) {
Sangho Shin81655442014-10-20 14:22:46 -07001128 this.tunnelId = tid;
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001129 this.labelIds = labelIds;
Sangho Shin81655442014-10-20 14:22:46 -07001130 this.routes = routes;
1131 }
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001132 public String getTunnelId(){
1133 return this.tunnelId;
1134 }
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001135
1136 public List<Integer> getLabelids() {
1137 return this.labelIds;
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001138 }
1139 public List<TunnelRouteInfo> getRoutes(){
1140 return this.routes;
1141 }
Sangho Shin81655442014-10-20 14:22:46 -07001142 }
1143
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001144 public class TunnelRouteInfo {
Sangho Shin7330c032014-10-20 10:34:51 -07001145
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001146 private String srcSwDpid;
1147 private List<Dpid> fwdSwDpids;
1148 private List<String> route;
Sangho Shin7330c032014-10-20 10:34:51 -07001149
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001150 public TunnelRouteInfo() {
Sangho Shin7330c032014-10-20 10:34:51 -07001151 fwdSwDpids = new ArrayList<Dpid>();
1152 route = new ArrayList<String>();
1153 }
1154
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001155 private void setSrcDpid(String dpid) {
Sangho Shin7330c032014-10-20 10:34:51 -07001156 this.srcSwDpid = dpid;
1157 }
1158
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001159 private void setFwdSwDpid(List<Dpid> dpid) {
Sangho Shin7330c032014-10-20 10:34:51 -07001160 this.fwdSwDpids = dpid;
1161 }
1162
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001163 private void addRoute(String id) {
Sangho Shin7330c032014-10-20 10:34:51 -07001164 route.add(id);
1165 }
1166
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001167 private void setRoute(List<String> r) {
Sangho Shin7330c032014-10-20 10:34:51 -07001168 this.route = r;
1169 }
1170
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001171 public String getSrcSwDpid() {
Sangho Shin7330c032014-10-20 10:34:51 -07001172 return this.srcSwDpid;
1173 }
1174
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001175 public List<Dpid> getFwdSwDpid() {
Sangho Shin7330c032014-10-20 10:34:51 -07001176 return this.fwdSwDpids;
1177 }
1178
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001179 public List<String> getRoute() {
Sangho Shin7330c032014-10-20 10:34:51 -07001180 return this.route;
1181 }
1182 }
1183
Sangho Shin15273b62014-10-16 22:22:05 -07001184 /**
Sangho Shin81655442014-10-20 14:22:46 -07001185 * Return the Tunnel table
1186 *
1187 * @return collection of TunnelInfo
1188 */
1189 public Collection<TunnelInfo> getTunnelTable() {
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001190 return this.tunnelTable.values();
Sangho Shin81655442014-10-20 14:22:46 -07001191 }
Sangho Shin204b9972014-10-22 11:08:10 -07001192
Fahad Naeem Khan12fa63a2014-10-21 17:01:27 -07001193 public Collection<PolicyInfo> getPoclicyTable() {
1194 return this.policyTable.values();
1195 }
Sangho Shin81655442014-10-20 14:22:46 -07001196
1197 /**
Sangho Shin5671cbb2014-10-20 22:35:41 -07001198 * Return router DPIDs for the tunnel
1199 *
1200 * @param tid tunnel ID
1201 * @return List of DPID
1202 */
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001203 public List<Integer> getTunnelInfo(String tid) {
Sangho Shin5671cbb2014-10-20 22:35:41 -07001204 TunnelInfo tunnelInfo = tunnelTable.get(tid);
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001205 return tunnelInfo.labelIds;
Sangho Shin5671cbb2014-10-20 22:35:41 -07001206
1207 }
1208
1209 /**
1210 * Get the first group ID for the tunnel for specific source router
1211 * If Segment Stitching was required to create the tunnel, there are
1212 * mutiple source routers.
1213 *
1214 * @param tunnelId ID for the tunnel
1215 * @param dpid source router DPID
1216 * @return the first group ID of the tunnel
1217 */
1218 public int getTunnelGroupId(String tunnelId, String dpid) {
1219 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
1220 getSwId(dpid));
1221
1222 if (sw13 == null) {
1223 return -1;
1224 }
1225 else {
1226 return sw13.getTunnelGroupId(tunnelId);
1227 }
1228 }
1229
1230 /**
Sangho Shin15273b62014-10-16 22:22:05 -07001231 * Create a tunnel for policy routing
1232 * It delivers the node IDs of tunnels to driver.
1233 * Split the node IDs if number of IDs exceeds the limit for stitching.
1234 *
1235 * @param tunnelId Node IDs for the tunnel
1236 * @param Ids tunnel ID
1237 */
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001238 public boolean createTunnel(String tunnelId, List<Integer> labelIds) {
Sangho Shin15273b62014-10-16 22:22:05 -07001239
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001240 if (labelIds.isEmpty() || labelIds.size() < 2) {
Sangho Shin15273b62014-10-16 22:22:05 -07001241 log.debug("Wrong tunnel information");
1242 return false;
1243 }
1244
Sangho Shin55d00e12014-10-20 12:13:07 -07001245 List<String> Ids = new ArrayList<String>();
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001246 for (Integer label : labelIds) {
1247 Ids.add(label.toString());
Sangho Shin55d00e12014-10-20 12:13:07 -07001248 }
1249
Sangho Shin81655442014-10-20 14:22:46 -07001250 List<TunnelRouteInfo> stitchingRule = getStitchingRule(Ids);
Sangho Shin15273b62014-10-16 22:22:05 -07001251 if (stitchingRule == null) {
1252 log.debug("Failed to get the policy rule.");
1253 return false;
1254 }
Sangho Shin81655442014-10-20 14:22:46 -07001255 for (TunnelRouteInfo route: stitchingRule) {
Sangho Shin15273b62014-10-16 22:22:05 -07001256
1257 IOF13Switch targetSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin81655442014-10-20 14:22:46 -07001258 getSwId(route.srcSwDpid));
Sangho Shin15273b62014-10-16 22:22:05 -07001259
1260 if (targetSw == null) {
Sangho Shin81655442014-10-20 14:22:46 -07001261 log.debug("Switch {} is gone.", route.srcSwDpid);
Sangho Shin15273b62014-10-16 22:22:05 -07001262 return false;
1263 }
1264
1265 NeighborSet ns = new NeighborSet();
1266 for (Dpid dpid: route.getFwdSwDpid())
1267 ns.addDpid(dpid);
1268
1269 printTunnelInfo(targetSw, tunnelId, route.getRoute(), ns);
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001270 targetSw.createTunnel(tunnelId, route.getRoute(), ns);
Sangho Shin15273b62014-10-16 22:22:05 -07001271 }
1272
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001273 TunnelInfo tunnelInfo = new TunnelInfo(tunnelId, labelIds, stitchingRule);
Sangho Shin81655442014-10-20 14:22:46 -07001274 tunnelTable.put(tunnelId, tunnelInfo);
Sangho Shin15273b62014-10-16 22:22:05 -07001275
1276 return true;
1277 }
1278
1279 /**
1280 * Set policy table for policy routing
1281 *
1282 * @param sw
1283 * @param mplsLabel
Sangho Shin306633a2014-10-20 14:26:55 -07001284 * @return
Sangho Shin15273b62014-10-16 22:22:05 -07001285 */
Sangho Shin306633a2014-10-20 14:26:55 -07001286 public boolean createPolicy(String pid, MACAddress srcMac, MACAddress dstMac,
Sangho Shin15273b62014-10-16 22:22:05 -07001287 Short etherType, IPv4Net srcIp, IPv4Net dstIp, Byte ipProto,
Sangho Shine020cc32014-10-20 13:28:02 -07001288 Short srcTcpPort, Short dstTcpPort, int priority, String tid) {
Sangho Shin15273b62014-10-16 22:22:05 -07001289
Sangho Shin5b8f5452014-10-20 11:46:01 -07001290 PacketMatchBuilder packetBuilder = new PacketMatchBuilder();
1291
1292 if (srcMac != null)
1293 packetBuilder.setSrcMac(srcMac);
1294 if (dstMac != null)
1295 packetBuilder.setDstMac(dstMac);
Sangho Shin58182672014-10-21 13:23:38 -07001296 if (etherType == null) // Cqpd requires the type of IPV4
1297 packetBuilder.setEtherType(Ethernet.TYPE_IPV4);
1298 else
Sangho Shin5b8f5452014-10-20 11:46:01 -07001299 packetBuilder.setEtherType(etherType);
1300 if (srcIp != null)
1301 packetBuilder.setSrcIp(srcIp.address(), srcIp.prefixLen());
1302 if (dstIp != null)
1303 packetBuilder.setDstIp(dstIp.address(), dstIp.prefixLen());
1304 if (ipProto != null)
1305 packetBuilder.setIpProto(ipProto);
1306 if (srcTcpPort > 0)
1307 packetBuilder.setSrcTcpPort(srcTcpPort);
1308 if (dstTcpPort > 0)
1309 packetBuilder.setDstTcpPort(dstTcpPort);
1310 PacketMatch policyMatch = packetBuilder.build();
Sangho Shin81655442014-10-20 14:22:46 -07001311 TunnelInfo tunnelInfo = tunnelTable.get(tid);
1312 List<TunnelRouteInfo> routes = tunnelInfo.routes;
Sangho Shin5b8f5452014-10-20 11:46:01 -07001313
Sangho Shin81655442014-10-20 14:22:46 -07001314 for (TunnelRouteInfo route : routes) {
Sangho Shin15273b62014-10-16 22:22:05 -07001315 List<Action> actions = new ArrayList<>();
1316 GroupAction groupAction = new GroupAction();
Sangho Shin81655442014-10-20 14:22:46 -07001317 groupAction.setTunnelId(tid);
Sangho Shin15273b62014-10-16 22:22:05 -07001318 actions.add(groupAction);
1319
1320 MatchAction matchAction = new MatchAction(new MatchActionId(
1321 matchActionId++),
Sangho Shin5b8f5452014-10-20 11:46:01 -07001322 new SwitchPort((long) 0, (short) 0), policyMatch, priority,
1323 actions);
Sangho Shin15273b62014-10-16 22:22:05 -07001324 MatchActionOperationEntry maEntry =
1325 new MatchActionOperationEntry(Operator.ADD, matchAction);
1326
1327 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin81655442014-10-20 14:22:46 -07001328 getSwId(route.srcSwDpid));
Sangho Shin15273b62014-10-16 22:22:05 -07001329
1330 if (sw13 != null) {
1331 printMatchActionOperationEntry(sw13, maEntry);
1332 try {
1333 sw13.pushFlow(maEntry);
1334 } catch (IOException e) {
1335 e.printStackTrace();
Sangho Shin306633a2014-10-20 14:26:55 -07001336 return false;
Sangho Shin15273b62014-10-16 22:22:05 -07001337 }
1338 }
1339 }
Sangho Shin5b8f5452014-10-20 11:46:01 -07001340
1341 PolicyInfo policyInfo = new PolicyInfo(pid, policyMatch, priority, tid);
Sangho Shine020cc32014-10-20 13:28:02 -07001342 policyTable.put(pid, policyInfo);
Sangho Shin306633a2014-10-20 14:26:55 -07001343
1344 return true;
Sangho Shin15273b62014-10-16 22:22:05 -07001345 }
1346
1347 /**
Sangho Shin1ad7be02014-10-20 16:56:49 -07001348 * Split the nodes IDs into multiple tunnel if Segment Stitching is required.
1349 * We assume that the first node ID is the one of source router, and the last
1350 * node ID is that of the destination router.
Sangho Shin15273b62014-10-16 22:22:05 -07001351 *
Sangho Shin1ad7be02014-10-20 16:56:49 -07001352 * @param route list of node IDs
1353 * @return List of the TunnelRoutInfo
Sangho Shin15273b62014-10-16 22:22:05 -07001354 */
Sangho Shin81655442014-10-20 14:22:46 -07001355 private List<TunnelRouteInfo> getStitchingRule(List<String> route) {
Sangho Shin15273b62014-10-16 22:22:05 -07001356
1357 if (route.isEmpty() || route.size() < 2)
1358 return null;
1359
Sangho Shin81655442014-10-20 14:22:46 -07001360 List<TunnelRouteInfo> rules = new ArrayList<TunnelRouteInfo>();
Sangho Shin15273b62014-10-16 22:22:05 -07001361
1362 Switch srcSw = this.getSwitchFromNodeId(route.get(0));
1363 String srcDpid = srcSw.getDpid().toString();
1364
1365 if (route.size() <= MAX_NUM_LABELS+1) {
Sangho Shin58182672014-10-21 13:23:38 -07001366 boolean match =false;
1367 TunnelRouteInfo routeInfo = new TunnelRouteInfo();
1368 routeInfo.setSrcDpid(srcSw.getDpid().toString());
1369 String nodeId = route.get(1);
Sangho Shina000c612014-10-21 14:17:59 -07001370 List<Dpid> fwdSwDpids = getForwardingSwitchForNodeId(srcSw, nodeId);
Fahad Naeem Khan95aa4012014-10-21 14:07:00 -07001371 if (fwdSwDpids == null){
1372 return null;
1373 }
Sangho Shin58182672014-10-21 13:23:38 -07001374 for (Dpid dpid: fwdSwDpids) {
1375 if (getMplsLabel(dpid.toString()).toString().equals(nodeId)) {
1376 List<Dpid> fwdSws = new ArrayList<Dpid>();
1377 fwdSws.add(dpid);
1378 routeInfo.setFwdSwDpid(fwdSws);
1379 match = true;
1380 break;
1381 }
1382 }
1383 route.remove(0); // remove source router from the list
1384 if (match) {
1385 route.remove(0);
1386 }
1387 else {
1388 routeInfo.setFwdSwDpid(fwdSwDpids);
1389 }
1390 routeInfo.setRoute(route);
1391 rules.add(routeInfo);
Sangho Shin15273b62014-10-16 22:22:05 -07001392 return rules;
1393 }
1394
1395 int i = 0;
Sangho Shine020cc32014-10-20 13:28:02 -07001396 TunnelRouteInfo routeInfo = new TunnelRouteInfo();
Sangho Shin15273b62014-10-16 22:22:05 -07001397 boolean checkNeighbor = true;
1398
1399 for (String nodeId: route) {
Sangho Shin1ad7be02014-10-20 16:56:49 -07001400 // First node ID is always the source router
Sangho Shin15273b62014-10-16 22:22:05 -07001401 if (i == 0) {
1402 routeInfo.setSrcDpid(srcDpid);
1403 srcSw = getSwitchFromNodeId(nodeId);
1404 i++;
1405 }
Sangho Shin58182672014-10-21 13:23:38 -07001406 else if (i == 1 && checkNeighbor) {
1407 // Check if next node is the neighbor SW of the source SW
1408 List<Dpid> fwdSwDpids = getForwardingSwitchForNodeId(srcSw,
1409 nodeId);
1410 if (fwdSwDpids == null || fwdSwDpids.isEmpty()) {
1411 log.debug("There is no route from node {} to node {}",
1412 srcSw.getDpid(), nodeId);
1413 return null;
Sangho Shin15273b62014-10-16 22:22:05 -07001414 }
Sangho Shin58182672014-10-21 13:23:38 -07001415 // If first Id is one of the neighbors, do not include it to route, but set it as a fwd SW.
1416 boolean match = false;
1417 for (Dpid dpid: fwdSwDpids) {
1418 if (getMplsLabel(dpid.toString()).toString().equals(nodeId)) {
1419 List<Dpid> fwdSws = new ArrayList<Dpid>();
1420 fwdSws.add(dpid);
1421 routeInfo.setFwdSwDpid(fwdSws);
1422 match = true;
1423 break;
1424 }
1425 }
1426 if (!match) {
Sangho Shin15273b62014-10-16 22:22:05 -07001427 routeInfo.addRoute(nodeId);
Sangho Shin58182672014-10-21 13:23:38 -07001428 routeInfo.setFwdSwDpid(fwdSwDpids);
Sangho Shin15273b62014-10-16 22:22:05 -07001429 i++;
1430 }
Sangho Shin58182672014-10-21 13:23:38 -07001431 // we check only the next node ID of the source router
1432 checkNeighbor = false;
Sangho Shin15273b62014-10-16 22:22:05 -07001433 }
1434 else {
1435 routeInfo.addRoute(nodeId);
1436 i++;
1437 }
1438
Sangho Shin1ad7be02014-10-20 16:56:49 -07001439 // If the number of labels reaches the limit, start over the procedure
Sangho Shin15273b62014-10-16 22:22:05 -07001440 if (i == MAX_NUM_LABELS+1) {
Sangho Shin81655442014-10-20 14:22:46 -07001441 rules.add(routeInfo);
Sangho Shine020cc32014-10-20 13:28:02 -07001442 routeInfo = new TunnelRouteInfo();
Sangho Shin15273b62014-10-16 22:22:05 -07001443 srcSw = getSwitchFromNodeId(nodeId);
1444 srcDpid = getSwitchFromNodeId(nodeId).getDpid().toString();
1445 routeInfo.setSrcDpid(srcDpid);
1446 i = 1;
1447 checkNeighbor = true;
1448 }
1449 }
1450
1451 if (i < MAX_NUM_LABELS+1) {
Sangho Shin81655442014-10-20 14:22:46 -07001452 rules.add(routeInfo);
Sangho Shin15273b62014-10-16 22:22:05 -07001453 }
1454
1455 return rules;
1456 }
1457
Sangho Shin5b8f5452014-10-20 11:46:01 -07001458 /**
1459 * Remove all policies applied to specific tunnel.
1460 *
1461 * @param srcMac
1462 * @param dstMac
1463 * @param etherType
1464 * @param srcIp
1465 * @param dstIp
1466 * @param ipProto
1467 * @param srcTcpPort
1468 * @param dstTcpPort
1469 * @param tid
Sangho Shin306633a2014-10-20 14:26:55 -07001470 * @return
Sangho Shin5b8f5452014-10-20 11:46:01 -07001471 */
Sangho Shin306633a2014-10-20 14:26:55 -07001472 public boolean removePolicy(String pid) {
Sangho Shine020cc32014-10-20 13:28:02 -07001473 PolicyInfo policyInfo = policyTable.get(pid);
Sangho Shin5671cbb2014-10-20 22:35:41 -07001474 if (policyInfo == null)
1475 return false;
Sangho Shin5b8f5452014-10-20 11:46:01 -07001476 PacketMatch policyMatch = policyInfo.match;
Sangho Shine020cc32014-10-20 13:28:02 -07001477 String tid = policyInfo.tunnelId;
Sangho Shin5b8f5452014-10-20 11:46:01 -07001478 int priority = policyInfo.priority;
1479
1480 List<Action> actions = new ArrayList<>();
1481 int gropuId = 0; // dummy group ID
1482 GroupAction groupAction = new GroupAction();
1483 groupAction.setGroupId(gropuId);
1484 actions.add(groupAction);
1485
1486 MatchAction matchAction = new MatchAction(new MatchActionId(
1487 matchActionId++),
1488 new SwitchPort((long) 0, (short) 0), policyMatch, priority,
1489 actions);
1490 MatchActionOperationEntry maEntry =
1491 new MatchActionOperationEntry(Operator.REMOVE, matchAction);
1492
Sangho Shin81655442014-10-20 14:22:46 -07001493 TunnelInfo tunnelInfo = tunnelTable.get(tid);
Sangho Shin5671cbb2014-10-20 22:35:41 -07001494 if (tunnelInfo == null)
1495 return false;
Sangho Shin81655442014-10-20 14:22:46 -07001496 List<TunnelRouteInfo> routes = tunnelInfo.routes;
1497
1498 for (TunnelRouteInfo route : routes) {
Sangho Shin5b8f5452014-10-20 11:46:01 -07001499 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin81655442014-10-20 14:22:46 -07001500 getSwId(route.srcSwDpid));
Sangho Shin5b8f5452014-10-20 11:46:01 -07001501
Sangho Shin5671cbb2014-10-20 22:35:41 -07001502 if (sw13 == null) {
1503 return false;
1504 }
1505 else {
Sangho Shin5b8f5452014-10-20 11:46:01 -07001506 printMatchActionOperationEntry(sw13, maEntry);
1507 try {
1508 sw13.pushFlow(maEntry);
1509 } catch (IOException e) {
1510 e.printStackTrace();
1511 log.debug("policy remove failed due to pushFlow() exception");
Sangho Shin306633a2014-10-20 14:26:55 -07001512 return false;
Sangho Shin5b8f5452014-10-20 11:46:01 -07001513 }
1514 }
1515 }
1516
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001517 policyTable.remove(pid);
Sangho Shin5b8f5452014-10-20 11:46:01 -07001518 log.debug("Policy {} is removed.", pid);
Sangho Shin306633a2014-10-20 14:26:55 -07001519 return true;
Sangho Shine020cc32014-10-20 13:28:02 -07001520 }
Sangho Shin5b8f5452014-10-20 11:46:01 -07001521
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001522 /**
1523 * Remove a tunnel
1524 * It removes all groups for the tunnel if the tunnel is not used for any
1525 * policy.
1526 *
1527 * @param tunnelId tunnel ID to remove
1528 */
Sangho Shin306633a2014-10-20 14:26:55 -07001529 public boolean removeTunnel(String tunnelId) {
Sangho Shin55d00e12014-10-20 12:13:07 -07001530
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001531 // Check if the tunnel is used for any policy
1532 for (PolicyInfo policyInfo: policyTable.values()) {
Sangho Shina000c612014-10-21 14:17:59 -07001533 if (policyInfo.tunnelId.equals(tunnelId)) {
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001534 log.debug("Tunnel {} is still used for the policy {}.",
1535 policyInfo.policyId, tunnelId);
1536 return false;
1537 }
1538 }
1539
1540 TunnelInfo tunnelInfo = tunnelTable.get(tunnelId);
Sangho Shin5671cbb2014-10-20 22:35:41 -07001541 if (tunnelInfo == null)
1542 return false;
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001543
1544 List<TunnelRouteInfo> routes = tunnelInfo.routes;
1545 for (TunnelRouteInfo route: routes) {
1546 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
1547 getSwId(route.srcSwDpid));
1548
Sangho Shin5671cbb2014-10-20 22:35:41 -07001549 if (sw13 == null) {
1550 return false;
1551 }
1552 else {
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001553 sw13.removeTunnel(tunnelId);
1554 }
1555 }
1556
1557 tunnelTable.remove(tunnelId);
1558 log.debug("Tunnel {} was removed ", tunnelId);
1559
Sangho Shin306633a2014-10-20 14:26:55 -07001560 return true;
Sangho Shin55d00e12014-10-20 12:13:07 -07001561 }
1562
Sangho Shin7330c032014-10-20 10:34:51 -07001563 // ************************************
1564 // Utility functions
1565 // ************************************
1566
Sangho Shin15273b62014-10-16 22:22:05 -07001567 /**
Sangho Shin7330c032014-10-20 10:34:51 -07001568 * Get the forwarding Switch DPIDs to send packets to a node
Sangho Shin15273b62014-10-16 22:22:05 -07001569 *
Sangho Shin7330c032014-10-20 10:34:51 -07001570 * @param srcSw source switch
1571 * @param nodeId destination node Id
1572 * @return list of switch DPID to forward packets to
Sangho Shin15273b62014-10-16 22:22:05 -07001573 */
Sangho Shin7330c032014-10-20 10:34:51 -07001574 private List<Dpid> getForwardingSwitchForNodeId(Switch srcSw, String nodeId) {
Sangho Shin15273b62014-10-16 22:22:05 -07001575
Sangho Shin7330c032014-10-20 10:34:51 -07001576 List<Dpid> fwdSws = new ArrayList<Dpid>();
1577 Switch destSw = null;
Sangho Shin15273b62014-10-16 22:22:05 -07001578
Sangho Shin7330c032014-10-20 10:34:51 -07001579 destSw = getSwitchFromNodeId(nodeId);
1580
1581 if (destSw == null) {
1582 log.debug("Cannot find the switch with ID {}", nodeId);
1583 return null;
1584 }
1585
1586 ECMPShortestPathGraph ecmpSPG = new ECMPShortestPathGraph(srcSw);
1587
1588 HashMap<Integer, HashMap<Switch, ArrayList<ArrayList<Dpid>>>> switchVia =
1589 ecmpSPG.getAllLearnedSwitchesAndVia();
1590 for (Integer itrIdx : switchVia.keySet()) {
1591 HashMap<Switch, ArrayList<ArrayList<Dpid>>> swViaMap =
1592 switchVia.get(itrIdx);
1593 for (Switch targetSw : swViaMap.keySet()) {
1594 String destSwDpid = destSw.getDpid().toString();
1595 if (targetSw.getDpid().toString().equals(destSwDpid)) {
1596 for (ArrayList<Dpid> via : swViaMap.get(targetSw)) {
1597 if (via.isEmpty()) {
1598 fwdSws.add(destSw.getDpid());
1599 }
1600 else {
Sangho Shina000c612014-10-21 14:17:59 -07001601 Dpid firstVia = via.get(via.size()-1);
1602 fwdSws.add(firstVia);
Sangho Shin7330c032014-10-20 10:34:51 -07001603 }
1604 }
1605 }
1606 }
1607 }
1608
1609 return fwdSws;
Sangho Shin15273b62014-10-16 22:22:05 -07001610 }
1611
Sangho Shin7330c032014-10-20 10:34:51 -07001612 /**
1613 * Get switch for the node Id specified
1614 *
1615 * @param nodeId node ID for switch
1616 * @return Switch
1617 */
1618 private Switch getSwitchFromNodeId(String nodeId) {
Fahad Naeem Khan4444b952014-10-18 22:30:50 -07001619
Sangho Shin7330c032014-10-20 10:34:51 -07001620 for (Switch sw : mutableTopology.getSwitches()) {
1621 String id = sw.getStringAttribute("nodeSid");
1622 if (id.equals(nodeId)) {
1623 return sw;
1624 }
1625 }
1626
1627 return null;
1628 }
Fahad Naeem Khan4444b952014-10-18 22:30:50 -07001629
Sangho Shin43cee112014-09-25 16:43:34 -07001630 /**
Sangho Shin7330c032014-10-20 10:34:51 -07001631 * Convert a string DPID to its Switch Id (integer)
Sangho Shinfbc572c2014-10-02 16:37:05 -07001632 *
Sangho Shin7330c032014-10-20 10:34:51 -07001633 * @param dpid
1634 * @return
Sangho Shin43cee112014-09-25 16:43:34 -07001635 */
Sangho Shin7330c032014-10-20 10:34:51 -07001636 private long getSwId(String dpid) {
Sangho Shin43cee112014-09-25 16:43:34 -07001637
Sangho Shin7330c032014-10-20 10:34:51 -07001638 long swId = 0;
Sangho Shin43cee112014-09-25 16:43:34 -07001639
Sangho Shin7330c032014-10-20 10:34:51 -07001640 String swIdHexStr = "0x"+dpid.substring(dpid.lastIndexOf(":") + 1);
1641 if (swIdHexStr != null)
1642 swId = Integer.decode(swIdHexStr);
Sangho Shin43cee112014-09-25 16:43:34 -07001643
Sangho Shin7330c032014-10-20 10:34:51 -07001644 return swId;
1645 }
Sangho Shin43cee112014-09-25 16:43:34 -07001646
Sangho Shin7330c032014-10-20 10:34:51 -07001647 /**
1648 * Check if the switch is the edge router or not.
1649 *
1650 * @param dpid Dpid of the switch to check
1651 * @return true if it is an edge router, otherwise false
1652 */
1653 private boolean IsEdgeRouter(String dpid) {
Sangho Shin0df01982014-09-25 17:11:18 -07001654
Sangho Shin7330c032014-10-20 10:34:51 -07001655 for (Switch sw : mutableTopology.getSwitches()) {
1656 String dpidStr = sw.getDpid().toString();
1657 if (dpid.equals(dpidStr)) {
1658 /*
1659 String subnetInfo = sw.getStringAttribute("subnets");
1660 if (subnetInfo == null || subnetInfo.equals("[]")) {
1661 return false;
1662 }
1663 else
1664 return true;
1665 */
1666 String isEdge = sw.getStringAttribute("isEdgeRouter");
1667 if (isEdge != null) {
1668 if (isEdge.equals("true"))
1669 return true;
1670 else
1671 return false;
1672 }
Sangho Shin43cee112014-09-25 16:43:34 -07001673 }
1674 }
1675
Sangho Shin7330c032014-10-20 10:34:51 -07001676 return false;
Sangho Shineb083032014-09-22 16:11:34 -07001677 }
1678
1679 /**
1680 * Get MPLS label reading the config file
Sangho Shinfbc572c2014-10-02 16:37:05 -07001681 *
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001682 * @param dipid DPID of the switch
Sangho Shineb083032014-09-22 16:11:34 -07001683 * @return MPLS label for the switch
1684 */
Sangho Shin43cee112014-09-25 16:43:34 -07001685 private String getMplsLabel(String dpid) {
Sangho Shineb083032014-09-22 16:11:34 -07001686
1687 String mplsLabel = null;
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001688 for (Switch sw : mutableTopology.getSwitches()) {
Sangho Shin43cee112014-09-25 16:43:34 -07001689 String dpidStr = sw.getDpid().toString();
1690 if (dpid.equals(dpidStr)) {
Sangho Shineb083032014-09-22 16:11:34 -07001691 mplsLabel = sw.getStringAttribute("nodeSid");
1692 break;
Sangho Shin1aa93542014-09-22 09:49:44 -07001693 }
1694 }
1695
Sangho Shineb083032014-09-22 16:11:34 -07001696 return mplsLabel;
Sangho Shin1aa93542014-09-22 09:49:44 -07001697 }
1698
Sangho Shineb083032014-09-22 16:11:34 -07001699 /**
Sangho Shin1aa93542014-09-22 09:49:44 -07001700 * The function checks if given IP matches to the given subnet mask
Sangho Shinfbc572c2014-10-02 16:37:05 -07001701 *
Sangho Shin1aa93542014-09-22 09:49:44 -07001702 * @param addr - subnet address to match
1703 * @param addr1 - IP address to check
1704 * @return true if the IP address matches to the subnet, otherwise false
1705 */
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001706 public boolean netMatch(String addr, String addr1) { // addr is subnet
1707 // address and addr1 is
1708 // ip address. Function
1709 // will return true, if
1710 // addr1 is within
1711 // addr(subnet)
Sangho Shin1aa93542014-09-22 09:49:44 -07001712
1713 String[] parts = addr.split("/");
1714 String ip = parts[0];
1715 int prefix;
1716
1717 if (parts.length < 2) {
1718 prefix = 0;
1719 } else {
1720 prefix = Integer.parseInt(parts[1]);
1721 }
1722
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001723 Inet4Address a = null;
1724 Inet4Address a1 = null;
Sangho Shin1aa93542014-09-22 09:49:44 -07001725 try {
1726 a = (Inet4Address) InetAddress.getByName(ip);
1727 a1 = (Inet4Address) InetAddress.getByName(addr1);
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001728 } catch (UnknownHostException e) {
1729 }
Sangho Shin1aa93542014-09-22 09:49:44 -07001730
1731 byte[] b = a.getAddress();
1732 int ipInt = ((b[0] & 0xFF) << 24) |
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001733 ((b[1] & 0xFF) << 16) |
1734 ((b[2] & 0xFF) << 8) |
1735 ((b[3] & 0xFF) << 0);
Sangho Shin1aa93542014-09-22 09:49:44 -07001736
1737 byte[] b1 = a1.getAddress();
1738 int ipInt1 = ((b1[0] & 0xFF) << 24) |
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001739 ((b1[1] & 0xFF) << 16) |
1740 ((b1[2] & 0xFF) << 8) |
1741 ((b1[3] & 0xFF) << 0);
Sangho Shin1aa93542014-09-22 09:49:44 -07001742
1743 int mask = ~((1 << (32 - prefix)) - 1);
1744
1745 if ((ipInt & mask) == (ipInt1 & mask)) {
1746 return true;
1747 }
1748 else {
1749 return false;
1750 }
1751 }
Sangho Shineb083032014-09-22 16:11:34 -07001752
Sangho Shinac5ee2b2014-09-28 21:27:20 -07001753 /**
1754 * Add a routing rule for the host
Sangho Shinfbc572c2014-10-02 16:37:05 -07001755 *
Sangho Shinac5ee2b2014-09-28 21:27:20 -07001756 * @param sw - Switch to add the rule
1757 * @param hostIpAddress Destination host IP address
1758 * @param hostMacAddress Destination host MAC address
1759 */
Sangho Shineb083032014-09-22 16:11:34 -07001760 public void addRouteToHost(Switch sw, int hostIpAddress, byte[] hostMacAddress) {
1761 ipHandler.addRouteToHost(sw, hostIpAddress, hostMacAddress);
Sangho Shineb083032014-09-22 16:11:34 -07001762 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -07001763
Sangho Shin463bee52014-09-29 15:14:43 -07001764 /**
1765 * Add IP packet to a buffer queue
Sangho Shinfbc572c2014-10-02 16:37:05 -07001766 *
Sangho Shin463bee52014-09-29 15:14:43 -07001767 * @param ipv4
1768 */
Sangho Shin7330c032014-10-20 10:34:51 -07001769 public void addPacketToPacketBuffer(IPv4 ipv4) {
Sangho Shin61535402014-10-01 11:37:14 -07001770 ipPacketQueue.add(ipv4);
Sangho Shin463bee52014-09-29 15:14:43 -07001771 }
1772
1773 /**
1774 * Retrieve all packets whose destination is the given address.
Sangho Shinfbc572c2014-10-02 16:37:05 -07001775 *
Sangho Shin463bee52014-09-29 15:14:43 -07001776 * @param destIp Destination address of packets to retrieve
1777 */
1778 public List<IPv4> getIpPacketFromQueue(byte[] destIp) {
1779
1780 List<IPv4> bufferedPackets = new ArrayList<IPv4>();
1781
Sangho Shin61535402014-10-01 11:37:14 -07001782 if (!ipPacketQueue.isEmpty()) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001783 for (IPv4 ip : ipPacketQueue) {
Sangho Shin61535402014-10-01 11:37:14 -07001784 int dest = ip.getDestinationAddress();
1785 IPv4Address ip1 = IPv4Address.of(dest);
1786 IPv4Address ip2 = IPv4Address.of(destIp);
1787 if (ip1.equals(ip2)) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001788 bufferedPackets.add((IPv4) (ipPacketQueue.poll()).clone());
Sangho Shin463bee52014-09-29 15:14:43 -07001789 }
1790 }
1791 }
1792
1793 return bufferedPackets;
1794 }
1795
Sangho Shin7330c032014-10-20 10:34:51 -07001796 /**
1797 * Get MAC address to known hosts
1798 *
1799 * @param destinationAddress IP address to get MAC address
1800 * @return MAC Address to given IP address
1801 */
1802 public byte[] getMacAddressFromIpAddress(int destinationAddress) {
1803
1804 // Can't we get the host IP address from the TopologyService ??
1805
1806 Iterator<ArpEntry> iterator = arpEntries.iterator();
1807
1808 IPv4Address ipAddress = IPv4Address.of(destinationAddress);
1809 byte[] ipAddressInByte = ipAddress.getBytes();
1810
1811 while (iterator.hasNext()) {
1812 ArpEntry arpEntry = iterator.next();
1813 byte[] address = arpEntry.targetIpAddress;
1814
1815 IPv4Address a = IPv4Address.of(address);
1816 IPv4Address b = IPv4Address.of(ipAddressInByte);
1817
1818 if (a.equals(b)) {
1819 log.debug("Found an arp entry");
1820 return arpEntry.targetMacAddress;
1821 }
1822 }
1823
1824 return null;
1825 }
1826
1827 /**
1828 * Send an ARP request via ArpHandler
1829 *
1830 * @param destinationAddress
1831 * @param sw
1832 * @param inPort
1833 *
1834 */
1835 public void sendArpRequest(Switch sw, int destinationAddress, Port inPort) {
1836 arpHandler.sendArpRequest(sw, destinationAddress, inPort);
1837 }
1838
1839
1840 // ************************************
1841 // Test functions
1842 // ************************************
1843
Sangho Shin55d00e12014-10-20 12:13:07 -07001844 private void runTest() {
1845
1846 if (testMode == POLICY_ADD1) {
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001847 Integer[] routeArray = {101, 105, 110};
1848 /*List<Dpid> routeList = new ArrayList<Dpid>();
Sangho Shin55d00e12014-10-20 12:13:07 -07001849 for (int i = 0; i < routeArray.length; i++) {
1850 Dpid dpid = getSwitchFromNodeId(routeArray[i]).getDpid();
1851 routeList.add(dpid);
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001852 }*/
Sangho Shin55d00e12014-10-20 12:13:07 -07001853
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001854 if (createTunnel("1", Arrays.asList(routeArray))) {
Sangho Shin55d00e12014-10-20 12:13:07 -07001855 IPv4Net srcIp = new IPv4Net("10.0.1.1/24");
1856 IPv4Net dstIp = new IPv4Net("10.1.2.1/24");
1857
1858 log.debug("Set the policy 1");
Sangho Shine020cc32014-10-20 13:28:02 -07001859 this.createPolicy("1", null, null, Ethernet.TYPE_IPV4, srcIp,
Sangho Shin55d00e12014-10-20 12:13:07 -07001860 dstIp, IPv4.PROTOCOL_ICMP, (short)-1, (short)-1, 10000,
Sangho Shine020cc32014-10-20 13:28:02 -07001861 "1");
Sangho Shin55d00e12014-10-20 12:13:07 -07001862 testMode = POLICY_ADD2;
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001863 testTask.reschedule(5, TimeUnit.SECONDS);
Sangho Shin55d00e12014-10-20 12:13:07 -07001864 }
1865 else {
1866 // retry it
1867 testTask.reschedule(5, TimeUnit.SECONDS);
1868 }
1869 }
1870 else if (testMode == POLICY_ADD2) {
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001871 Integer[] routeArray = {101, 102, 103, 104, 105, 108, 110};
Sangho Shin55d00e12014-10-20 12:13:07 -07001872
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001873 if (createTunnel("2", Arrays.asList(routeArray))) {
Sangho Shin55d00e12014-10-20 12:13:07 -07001874 IPv4Net srcIp = new IPv4Net("10.0.1.1/24");
1875 IPv4Net dstIp = new IPv4Net("10.1.2.1/24");
1876
1877 log.debug("Set the policy 2");
Sangho Shine020cc32014-10-20 13:28:02 -07001878 this.createPolicy("2", null, null, Ethernet.TYPE_IPV4, srcIp,
Sangho Shin55d00e12014-10-20 12:13:07 -07001879 dstIp, IPv4.PROTOCOL_ICMP, (short)-1, (short)-1, 20000,
Sangho Shine020cc32014-10-20 13:28:02 -07001880 "2");
Fahad Naeem Khan95aa4012014-10-21 14:07:00 -07001881 //testMode = POLICY_REMOVE2;
1882 //testTask.reschedule(5, TimeUnit.SECONDS);
Sangho Shin55d00e12014-10-20 12:13:07 -07001883 }
1884 else {
1885 log.debug("Retry it");
1886 testTask.reschedule(5, TimeUnit.SECONDS);
1887 }
1888 }
1889 else if (testMode == POLICY_REMOVE2){
1890 log.debug("Remove the policy 2");
Sangho Shine020cc32014-10-20 13:28:02 -07001891 this.removePolicy("2");
Sangho Shin55d00e12014-10-20 12:13:07 -07001892 testMode = POLICY_REMOVE1;
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001893 testTask.reschedule(5, TimeUnit.SECONDS);
Sangho Shin55d00e12014-10-20 12:13:07 -07001894 }
1895 else if (testMode == POLICY_REMOVE1){
1896 log.debug("Remove the policy 1");
Sangho Shine020cc32014-10-20 13:28:02 -07001897 this.removePolicy("1");
Sangho Shin55d00e12014-10-20 12:13:07 -07001898
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001899 testMode = TUNNEL_REMOVE1;
1900 testTask.reschedule(5, TimeUnit.SECONDS);
1901 }
1902 else if (testMode == TUNNEL_REMOVE1) {
1903 log.debug("Remove the tunnel 1");
1904 this.removeTunnel("1");
1905
1906 testMode = TUNNEL_REMOVE2;
1907 testTask.reschedule(5, TimeUnit.SECONDS);
1908 }
1909 else if (testMode == TUNNEL_REMOVE2) {
1910 log.debug("Remove the tunnel 2");
1911 this.removeTunnel("2");
1912 log.debug("The end of test");
1913 }
Sangho Shin55d00e12014-10-20 12:13:07 -07001914 }
Sangho Shin7330c032014-10-20 10:34:51 -07001915
1916 private void runTest1() {
1917
1918 String dpid1 = "00:00:00:00:00:00:00:01";
1919 String dpid2 = "00:00:00:00:00:00:00:0a";
1920 Switch srcSw = mutableTopology.getSwitch(new Dpid(dpid1));
1921 Switch dstSw = mutableTopology.getSwitch(new Dpid(dpid2));
1922
1923 if (srcSw == null || dstSw == null) {
1924 testTask.reschedule(1, TimeUnit.SECONDS);
1925 log.debug("Switch is gone. Reschedule the test");
1926 return;
1927 }
1928
1929 String[] routeArray = {"101", "102", "105", "108", "110"};
1930 List<String> routeList = new ArrayList<String>();
1931 for (int i = 0; i < routeArray.length; i++)
1932 routeList.add(routeArray[i]);
1933
1934 List<String> optimizedRoute = this.getOptimizedPath(srcSw, dstSw, routeList);
1935
1936 log.debug("Test set is {}", routeList.toString());
1937 log.debug("Result set is {}", optimizedRoute.toString());
1938
1939
1940 }
1941
1942 /**
1943 * print tunnel info - used only for debugging.
1944 * @param targetSw
1945 *
1946 * @param fwdSwDpids
1947 * @param ids
1948 * @param tunnelId
1949 */
Sangho Shine020cc32014-10-20 13:28:02 -07001950 private void printTunnelInfo(IOF13Switch targetSw, String tunnelId,
Sangho Shin7330c032014-10-20 10:34:51 -07001951 List<String> ids, NeighborSet ns) {
1952 StringBuilder logStr = new StringBuilder("In switch " +
1953 targetSw.getId() + ", create a tunnel " + tunnelId + " " + " of push ");
1954 for (String id: ids)
1955 logStr.append(id + "-");
1956 logStr.append(" output to ");
1957 for (Dpid dpid: ns.getDpids())
1958 logStr.append(dpid + " - ");
1959
1960 log.debug(logStr.toString());
1961
1962 }
1963
1964 /**
1965 * Debugging function to print out the Match Action Entry
1966 * @param sw13
1967 *
1968 * @param maEntry
1969 */
1970 private void printMatchActionOperationEntry(
1971 IOF13Switch sw13, MatchActionOperationEntry maEntry) {
1972
1973 StringBuilder logStr = new StringBuilder("In switch " + sw13.getId() + ", ");
1974
1975 MatchAction ma = maEntry.getTarget();
1976 Match m = ma.getMatch();
1977 List<Action> actions = ma.getActions();
1978
1979 if (m instanceof Ipv4Match) {
1980 logStr.append("If the IP matches with ");
1981 IPv4Net ip = ((Ipv4Match) m).getDestination();
1982 logStr.append(ip.toString());
1983 logStr.append(" then ");
1984 }
1985 else if (m instanceof MplsMatch) {
1986 logStr.append("If the MPLS label matches with ");
1987 int mplsLabel = ((MplsMatch) m).getMplsLabel();
1988 logStr.append(mplsLabel);
1989 logStr.append(" then ");
1990 }
1991 else if (m instanceof PacketMatch) {
1992 GroupAction ga = (GroupAction)actions.get(0);
1993 logStr.append("if the policy match is XXX then go to group " +
1994 ga.getGroupId());
1995 log.debug(logStr.toString());
1996 return;
1997 }
1998
1999 logStr.append(" do { ");
2000 for (Action action : actions) {
2001 if (action instanceof CopyTtlInAction) {
2002 logStr.append("copy ttl In, ");
2003 }
2004 else if (action instanceof CopyTtlOutAction) {
2005 logStr.append("copy ttl Out, ");
2006 }
2007 else if (action instanceof DecMplsTtlAction) {
2008 logStr.append("Dec MPLS TTL , ");
2009 }
2010 else if (action instanceof GroupAction) {
2011 logStr.append("Forward packet to < ");
2012 NeighborSet dpids = ((GroupAction) action).getDpids();
2013 logStr.append(dpids.toString() + ",");
2014
2015 }
2016 else if (action instanceof PopMplsAction) {
2017 logStr.append("Pop MPLS label, ");
2018 }
2019 else if (action instanceof PushMplsAction) {
2020 logStr.append("Push MPLS label, ");
2021 }
2022 else if (action instanceof SetMplsIdAction) {
2023 int id = ((SetMplsIdAction) action).getMplsId();
2024 logStr.append("Set MPLS ID as " + id + ", ");
2025 }
2026 }
2027
2028 log.debug(logStr.toString());
2029
2030 }
2031
2032
2033 // ************************************
2034 // Unused classes and functions
2035 // ************************************
2036
2037 /**
2038 * Temporary class to to keep ARP entry
2039 *
2040 */
2041 private class ArpEntry {
2042
2043 byte[] targetMacAddress;
2044 byte[] targetIpAddress;
2045
2046 private ArpEntry(byte[] macAddress, byte[] ipAddress) {
2047 this.targetMacAddress = macAddress;
2048 this.targetIpAddress = ipAddress;
2049 }
2050 }
2051
2052 /**
2053 * This class is used only for link recovery optimization in
2054 * modifyEcmpRoutingRules() function.
2055 * TODO: please remove if the optimization is not used at all
2056 */
2057 private class SwitchPair {
2058 private Switch src;
2059 private Switch dst;
2060
2061 public SwitchPair(Switch src, Switch dst) {
2062 this.src = src;
2063 this.dst = dst;
2064 }
2065
2066 public Switch getSource() {
2067 return src;
2068 }
2069
2070 public Switch getDestination() {
2071 return dst;
2072 }
2073 }
2074
2075 /**
2076 * Update ARP Cache using ARP packets It is used to set destination MAC
2077 * address to forward packets to known hosts. But, it will be replace with
2078 * Host information of Topology service later.
2079 *
2080 * @param arp APR packets to use for updating ARP entries
2081 */
2082 public void updateArpCache(ARP arp) {
2083
2084 ArpEntry arpEntry = new ArpEntry(arp.getSenderHardwareAddress(),
2085 arp.getSenderProtocolAddress());
2086 // TODO: Need to check the duplication
2087 arpEntries.add(arpEntry);
2088 }
2089
2090 /**
2091 * Modify the routing rules for the lost links
2092 * - Recompute the path if the link failed is included in the path
2093 * (including src and dest).
2094 *
2095 * @param newLink
2096 */
2097 private void modifyEcmpRoutingRules(LinkData linkRemoved) {
2098
2099 //HashMap<Switch, SwitchPair> linksToRecompute = new HashMap<Switch, SwitchPair>();
2100 Set<SwitchPair> linksToRecompute = new HashSet<SwitchPair>();
2101
2102 for (ECMPShortestPathGraph ecmpSPG : graphs.values()) {
2103 Switch rootSw = ecmpSPG.getRootSwitch();
2104 HashMap<Integer, HashMap<Switch, ArrayList<Path>>> paths =
2105 ecmpSPG.getCompleteLearnedSwitchesAndPaths();
2106 for (HashMap<Switch, ArrayList<Path>> p: paths.values()) {
2107 for (Switch destSw: p.keySet()) {
2108 ArrayList<Path> path = p.get(destSw);
2109 if (checkPath(path, linkRemoved)) {
2110 boolean found = false;
2111 for (SwitchPair pair: linksToRecompute) {
2112 if (pair.getSource().getDpid() == rootSw.getDpid() &&
2113 pair.getSource().getDpid() == destSw.getDpid()) {
2114 found = true;
2115 }
2116 }
2117 if (!found) {
2118 linksToRecompute.add(new SwitchPair(rootSw, destSw));
2119 }
2120 }
2121 }
2122 }
2123 }
2124
2125 // Recompute the path for the specific route
2126 for (SwitchPair pair: linksToRecompute) {
2127
2128 log.debug("Recompute path from {} to {}", pair.getSource(), pair.getDestination());
2129 // We need the following function for optimization
2130 //ECMPShortestPathGraph ecmpSPG =
2131 // new ECMPShortestPathGraph(pair.getSource(), pair.getDestination());
2132 ECMPShortestPathGraph ecmpSPG =
2133 new ECMPShortestPathGraph(pair.getSource());
2134 populateEcmpRoutingRulesForPath(pair.getSource(), ecmpSPG, true);
2135 }
2136 }
2137
2138 /**
2139 * Optimize the mpls label
2140 * The feature will be used only for policy of "avoid a specific switch".
2141 * Check route to each router in route backward.
2142 * If there is only one route to the router and the routers are included in
2143 * the route, remove the id from the path.
2144 * A-B-C-D-E => A-B-C-D-E -> A-E
2145 * | | => A-B-H-I -> A-I
Sangho Shin5b8f5452014-10-20 11:46:01 -07002146 * F-G-H-I => A-D-I > A-D-I
Sangho Shin7330c032014-10-20 10:34:51 -07002147 */
2148 private List<String> getOptimizedPath(Switch srcSw, Switch dstSw, List<String> route) {
2149
2150 List<String> optimizedPath = new ArrayList<String>();
2151 optimizedPath.addAll(route);
2152 ECMPShortestPathGraph ecmpSPG = new ECMPShortestPathGraph(srcSw);
2153
2154 HashMap<Integer, HashMap<Switch, ArrayList<Path>>> paths =
2155 ecmpSPG.getCompleteLearnedSwitchesAndPaths();
2156 for (HashMap<Switch, ArrayList<Path>> p: paths.values()) {
2157 for (Switch s: p.keySet()) {
2158 if (s.getDpid().toString().equals(dstSw.getDpid().toString())) {
2159 ArrayList<Path> ecmpPaths = p.get(s);
2160 if (ecmpPaths!= null && ecmpPaths.size() == 1) {
2161 for (Path path: ecmpPaths) {
2162 for (LinkData link: path) {
2163 String srcId = getMplsLabel(link.getSrc().getDpid().toString());
2164 String dstId = getMplsLabel(link.getSrc().getDpid().toString());
2165 if (optimizedPath.contains(srcId)) {
2166 optimizedPath.remove(srcId);
2167 }
2168 if (optimizedPath.contains(dstId)) {
2169 optimizedPath.remove(dstId);
2170 }
2171 }
2172 }
2173 }
2174 }
2175 }
2176 }
2177
2178 return optimizedPath;
2179
2180 }
2181
2182 /**
2183 * Check if the path is affected from the link removed
2184 *
2185 * @param path Path to check
2186 * @param linkRemoved link removed
2187 * @return true if the path contains the link removed
2188 */
2189 private boolean checkPath(ArrayList<Path> path, LinkData linkRemoved) {
2190
2191 for (Path ppp: path) {
2192 // TODO: need to check if this is a bidirectional or
2193 // unidirectional
2194 for (LinkData link: ppp) {
2195 if (link.getDst().getDpid().equals(linkRemoved.getDst().getDpid()) &&
2196 link.getSrc().getDpid().equals(linkRemoved.getSrc().getDpid()))
2197 return true;
2198 }
2199 }
2200
2201 return false;
2202 }
Sangho Shin15273b62014-10-16 22:22:05 -07002203
2204
Sangho Shin2f263692014-09-15 14:09:41 -07002205}