blob: 429eadc56f2866381da172d611d205baa278522e [file] [log] [blame]
Sangho Shin2f263692014-09-15 14:09:41 -07001package net.onrc.onos.apps.segmentrouting;
2
Sangho Shin9c0f4c32014-09-26 16:02:38 -07003import java.io.IOException;
Sangho Shin1aa93542014-09-22 09:49:44 -07004import java.net.Inet4Address;
5import java.net.InetAddress;
6import java.net.UnknownHostException;
Sangho Shin2f263692014-09-15 14:09:41 -07007import java.util.ArrayList;
8import java.util.Collection;
Srikanth Vavilapalli363f1dc2014-09-22 14:30:23 -07009import java.util.HashMap;
Sangho Shin5be3e532014-10-03 17:20:58 -070010import java.util.HashSet;
Sangho Shin2f263692014-09-15 14:09:41 -070011import java.util.Iterator;
12import java.util.List;
13import java.util.Map;
Sangho Shin5be3e532014-10-03 17:20:58 -070014import java.util.Set;
Sangho Shin61535402014-10-01 11:37:14 -070015import java.util.concurrent.ConcurrentLinkedQueue;
Sangho Shin11d4e0f2014-09-30 12:00:33 -070016import java.util.concurrent.ExecutionException;
Sangho Shin43cee112014-09-25 16:43:34 -070017import java.util.concurrent.ScheduledExecutorService;
18import java.util.concurrent.TimeUnit;
Sangho Shin11d4e0f2014-09-30 12:00:33 -070019import java.util.concurrent.TimeoutException;
Sangho Shin2f263692014-09-15 14:09:41 -070020
21import net.floodlightcontroller.core.IFloodlightProviderService;
Sangho Shin9c0f4c32014-09-26 16:02:38 -070022import net.floodlightcontroller.core.IOF13Switch;
Sangho Shin0df01982014-09-25 17:11:18 -070023import net.floodlightcontroller.core.IOF13Switch.NeighborSet;
Sangho Shin11d4e0f2014-09-30 12:00:33 -070024import net.floodlightcontroller.core.internal.OFBarrierReplyFuture;
Sangho Shin2f263692014-09-15 14:09:41 -070025import net.floodlightcontroller.core.module.FloodlightModuleContext;
26import net.floodlightcontroller.core.module.FloodlightModuleException;
27import net.floodlightcontroller.core.module.IFloodlightModule;
28import net.floodlightcontroller.core.module.IFloodlightService;
Sangho Shin43cee112014-09-25 16:43:34 -070029import net.floodlightcontroller.core.util.SingletonTask;
30import net.floodlightcontroller.threadpool.IThreadPoolService;
Sangho Shin15273b62014-10-16 22:22:05 -070031import net.floodlightcontroller.util.MACAddress;
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070032import net.onrc.onos.api.packet.IPacketListener;
Sangho Shin2f263692014-09-15 14:09:41 -070033import net.onrc.onos.api.packet.IPacketService;
34import net.onrc.onos.core.flowprogrammer.IFlowPusherService;
Sangho Shinfbc572c2014-10-02 16:37:05 -070035import net.onrc.onos.core.intent.Path;
Sangho Shin2f263692014-09-15 14:09:41 -070036import net.onrc.onos.core.main.config.IConfigInfoService;
Sangho Shin43cee112014-09-25 16:43:34 -070037import net.onrc.onos.core.matchaction.MatchAction;
38import net.onrc.onos.core.matchaction.MatchActionId;
39import net.onrc.onos.core.matchaction.MatchActionOperationEntry;
Sangho Shin5be3e532014-10-03 17:20:58 -070040import net.onrc.onos.core.matchaction.MatchActionOperations.Operator;
Sangho Shin43cee112014-09-25 16:43:34 -070041import net.onrc.onos.core.matchaction.action.Action;
42import net.onrc.onos.core.matchaction.action.CopyTtlInAction;
43import net.onrc.onos.core.matchaction.action.CopyTtlOutAction;
44import net.onrc.onos.core.matchaction.action.DecMplsTtlAction;
45import net.onrc.onos.core.matchaction.action.DecNwTtlAction;
46import net.onrc.onos.core.matchaction.action.GroupAction;
47import net.onrc.onos.core.matchaction.action.PopMplsAction;
48import net.onrc.onos.core.matchaction.action.PushMplsAction;
49import net.onrc.onos.core.matchaction.action.SetMplsIdAction;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -070050import net.onrc.onos.core.matchaction.match.Ipv4Match;
Sangho Shin43cee112014-09-25 16:43:34 -070051import net.onrc.onos.core.matchaction.match.Match;
52import net.onrc.onos.core.matchaction.match.MplsMatch;
Sangho Shin15273b62014-10-16 22:22:05 -070053import net.onrc.onos.core.matchaction.match.PacketMatch;
54import net.onrc.onos.core.matchaction.match.PacketMatchBuilder;
Sangho Shin2f263692014-09-15 14:09:41 -070055import net.onrc.onos.core.packet.ARP;
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070056import net.onrc.onos.core.packet.Ethernet;
57import net.onrc.onos.core.packet.IPv4;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070058import net.onrc.onos.core.topology.ITopologyListener;
Sangho Shin1aa93542014-09-22 09:49:44 -070059import net.onrc.onos.core.topology.ITopologyService;
Sangho Shinbce900e2014-10-07 17:13:23 -070060import net.onrc.onos.core.topology.Link;
Sangho Shinc8d2f592014-09-30 16:53:57 -070061import net.onrc.onos.core.topology.LinkData;
Sangho Shinbce900e2014-10-07 17:13:23 -070062import net.onrc.onos.core.topology.MastershipData;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070063import net.onrc.onos.core.topology.MutableTopology;
Sangho Shineb083032014-09-22 16:11:34 -070064import net.onrc.onos.core.topology.Port;
Sangho Shinc8d2f592014-09-30 16:53:57 -070065import net.onrc.onos.core.topology.PortData;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070066import net.onrc.onos.core.topology.Switch;
Sangho Shin5be3e532014-10-03 17:20:58 -070067import net.onrc.onos.core.topology.SwitchData;
Sangho Shin1aa93542014-09-22 09:49:44 -070068import net.onrc.onos.core.topology.TopologyEvents;
Srikanth Vavilapalli363f1dc2014-09-22 14:30:23 -070069import net.onrc.onos.core.util.Dpid;
Sangho Shin43cee112014-09-25 16:43:34 -070070import net.onrc.onos.core.util.IPv4Net;
71import net.onrc.onos.core.util.SwitchPort;
Sangho Shin2f263692014-09-15 14:09:41 -070072
Sangho Shin43cee112014-09-25 16:43:34 -070073import org.json.JSONArray;
74import org.json.JSONException;
Saurav Dasbc594a42014-09-25 20:13:50 -070075import org.projectfloodlight.openflow.types.EthType;
Sangho Shin2f263692014-09-15 14:09:41 -070076import org.projectfloodlight.openflow.types.IPv4Address;
77import org.slf4j.Logger;
78import org.slf4j.LoggerFactory;
79
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070080public class SegmentRoutingManager implements IFloodlightModule,
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -070081 ITopologyListener, IPacketListener {
Sangho Shin2f263692014-09-15 14:09:41 -070082
83 private static final Logger log = LoggerFactory
84 .getLogger(SegmentRoutingManager.class);
Sangho Shin23f898d2014-10-13 16:54:00 -070085
Fahad Naeem Khan5b558f22014-10-16 10:35:20 -070086 private ITopologyService topologyService;
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070087 private IPacketService packetService;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070088 private MutableTopology mutableTopology;
Sangho Shin61535402014-10-01 11:37:14 -070089 private ConcurrentLinkedQueue<IPv4> ipPacketQueue;
Sangho Shin2f263692014-09-15 14:09:41 -070090
91 private List<ArpEntry> arpEntries;
Sangho Shineb083032014-09-22 16:11:34 -070092 private ArpHandler arpHandler;
93 private GenericIpHandler ipHandler;
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070094 private IcmpHandler icmpHandler;
Sangho Shin43cee112014-09-25 16:43:34 -070095 private IThreadPoolService threadPool;
96 private SingletonTask discoveryTask;
Sangho Shin23f898d2014-10-13 16:54:00 -070097 private SingletonTask linkAddTask;
Sangho Shin15273b62014-10-16 22:22:05 -070098 private SingletonTask testTask;
Sangho Shin9c0f4c32014-09-26 16:02:38 -070099 private IFloodlightProviderService floodlightProvider;
Sangho Shin2f263692014-09-15 14:09:41 -0700100
Sangho Shinfbc572c2014-10-02 16:37:05 -0700101 private HashMap<Switch, ECMPShortestPathGraph> graphs;
Sangho Shin23f898d2014-10-13 16:54:00 -0700102 private HashMap<String, LinkData> linksDown;
103 private HashMap<String, LinkData> linksToAdd;
Sangho Shin5be3e532014-10-03 17:20:58 -0700104 private ConcurrentLinkedQueue<TopologyEvents> topologyEventQueue;
Sangho Shin15273b62014-10-16 22:22:05 -0700105 private HashMap<Integer, HashMap<String, PolicyRouteInfo>> stitchInfo;
106 private HashMap<Integer, HashMap<String, Integer>> tunnelGroupMap;
Sangho Shinbce900e2014-10-07 17:13:23 -0700107
108 private int numOfEvents = 0;
109 private int numOfEventProcess = 0;
110 private int numOfPopulation = 0;
Sangho Shin99918bd2014-10-08 15:52:35 -0700111 private long matchActionId = 0L;
Sangho Shin23f898d2014-10-13 16:54:00 -0700112 private final int DELAY_TO_ADD_LINK = 10;
Sangho Shin15273b62014-10-16 22:22:05 -0700113 private final int MAX_NUM_LABELS = 3;
Sangho Shinfbc572c2014-10-02 16:37:05 -0700114
Sangho Shin2f263692014-09-15 14:09:41 -0700115 @Override
116 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
117 // TODO Auto-generated method stub
118 return null;
119 }
120
121 @Override
122 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
123 // TODO Auto-generated method stub
124 return null;
125 }
126
127 @Override
128 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
129 Collection<Class<? extends IFloodlightService>> l = new ArrayList<Class<? extends IFloodlightService>>();
130
131 l.add(IFloodlightProviderService.class);
132 l.add(IConfigInfoService.class);
133 l.add(ITopologyService.class);
134 l.add(IPacketService.class);
135 l.add(IFlowPusherService.class);
136 l.add(ITopologyService.class);
137
138 return l;
139
140 }
141
142 @Override
143 public void init(FloodlightModuleContext context) throws FloodlightModuleException {
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700144 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Sangho Shineb083032014-09-22 16:11:34 -0700145 arpHandler = new ArpHandler(context, this);
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700146 icmpHandler = new IcmpHandler(context, this);
Sangho Shineb083032014-09-22 16:11:34 -0700147 ipHandler = new GenericIpHandler(context, this);
Sangho Shin2f263692014-09-15 14:09:41 -0700148 arpEntries = new ArrayList<ArpEntry>();
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700149 topologyService = context.getServiceImpl(ITopologyService.class);
Sangho Shin43cee112014-09-25 16:43:34 -0700150 threadPool = context.getServiceImpl(IThreadPoolService.class);
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700151 mutableTopology = topologyService.getTopology();
Sangho Shin61535402014-10-01 11:37:14 -0700152 ipPacketQueue = new ConcurrentLinkedQueue<IPv4>();
Sangho Shinfbc572c2014-10-02 16:37:05 -0700153 graphs = new HashMap<Switch, ECMPShortestPathGraph>();
Sangho Shin23f898d2014-10-13 16:54:00 -0700154 linksDown = new HashMap<String, LinkData>();
155 linksToAdd = new HashMap<String, LinkData>();
Sangho Shin5be3e532014-10-03 17:20:58 -0700156 topologyEventQueue = new ConcurrentLinkedQueue<TopologyEvents>();
Sangho Shin15273b62014-10-16 22:22:05 -0700157 stitchInfo = new HashMap<Integer, HashMap<String, PolicyRouteInfo>>();
158 packetService = context.getServiceImpl(IPacketService.class);
159 tunnelGroupMap = new HashMap<Integer, HashMap<String, Integer>>();
Sangho Shin2f263692014-09-15 14:09:41 -0700160
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700161 packetService.registerPacketListener(this);
Sangho Shin15273b62014-10-16 22:22:05 -0700162 topologyService.addListener(this, false);
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700163
Sangho Shin99918bd2014-10-08 15:52:35 -0700164
Sangho Shin2f263692014-09-15 14:09:41 -0700165 }
166
167 @Override
168 public void startUp(FloodlightModuleContext context) throws FloodlightModuleException {
Sangho Shinc8d2f592014-09-30 16:53:57 -0700169 ScheduledExecutorService ses = threadPool.getScheduledExecutor();
Sangho Shin2f263692014-09-15 14:09:41 -0700170
Sangho Shinc8d2f592014-09-30 16:53:57 -0700171 discoveryTask = new SingletonTask(ses, new Runnable() {
172 @Override
173 public void run() {
Sangho Shin5be3e532014-10-03 17:20:58 -0700174 handleTopologyChangeEvents();
Sangho Shinc8d2f592014-09-30 16:53:57 -0700175 }
176 });
Sangho Shin23f898d2014-10-13 16:54:00 -0700177
178 linkAddTask = new SingletonTask(ses, new Runnable() {
179 @Override
180 public void run() {
181 delayedAddLink();
182 }
183 });
184
Sangho Shin15273b62014-10-16 22:22:05 -0700185 testTask = new SingletonTask(ses, new Runnable() {
186 @Override
187 public void run() {
188 runTest();
189 }
190 });
191
192 // policy routing test task
193 //testTask.reschedule(20, TimeUnit.SECONDS);
Sangho Shin2f263692014-09-15 14:09:41 -0700194 }
195
Sangho Shin15273b62014-10-16 22:22:05 -0700196
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700197 @Override
198 public void receive(Switch sw, Port inPort, Ethernet payload) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700199 if (payload.getEtherType() == Ethernet.TYPE_ARP)
200 arpHandler.processPacketIn(sw, inPort, payload);
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700201 if (payload.getEtherType() == Ethernet.TYPE_IPV4) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700202 addPacket((IPv4) payload.getPayload());
203 if (((IPv4) payload.getPayload()).getProtocol() == IPv4.PROTOCOL_ICMP)
204 icmpHandler.processPacketIn(sw, inPort, payload);
205 else
206 ipHandler.processPacketIn(sw, inPort, payload);
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700207 }
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700208 else {
209 log.debug("{}", payload.toString());
210 }
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700211 }
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700212
Sangho Shin2f263692014-09-15 14:09:41 -0700213 /**
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700214 * Update ARP Cache using ARP packets It is used to set destination MAC
215 * address to forward packets to known hosts. But, it will be replace with
216 * Host information of Topology service later.
Sangho Shinfbc572c2014-10-02 16:37:05 -0700217 *
Sangho Shin2f263692014-09-15 14:09:41 -0700218 * @param arp APR packets to use for updating ARP entries
219 */
220 public void updateArpCache(ARP arp) {
221
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700222 ArpEntry arpEntry = new ArpEntry(arp.getSenderHardwareAddress(),
223 arp.getSenderProtocolAddress());
Sangho Shin2f263692014-09-15 14:09:41 -0700224 // TODO: Need to check the duplication
225 arpEntries.add(arpEntry);
226 }
227
228 /**
229 * Get MAC address to known hosts
Sangho Shinfbc572c2014-10-02 16:37:05 -0700230 *
Sangho Shin2f263692014-09-15 14:09:41 -0700231 * @param destinationAddress IP address to get MAC address
232 * @return MAC Address to given IP address
233 */
234 public byte[] getMacAddressFromIpAddress(int destinationAddress) {
235
236 // Can't we get the host IP address from the TopologyService ??
237
238 Iterator<ArpEntry> iterator = arpEntries.iterator();
239
240 IPv4Address ipAddress = IPv4Address.of(destinationAddress);
241 byte[] ipAddressInByte = ipAddress.getBytes();
242
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700243 while (iterator.hasNext()) {
Sangho Shin2f263692014-09-15 14:09:41 -0700244 ArpEntry arpEntry = iterator.next();
245 byte[] address = arpEntry.targetIpAddress;
246
247 IPv4Address a = IPv4Address.of(address);
248 IPv4Address b = IPv4Address.of(ipAddressInByte);
249
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700250 if (a.equals(b)) {
Sangho Shin2f263692014-09-15 14:09:41 -0700251 log.debug("Found an arp entry");
252 return arpEntry.targetMacAddress;
253 }
254 }
255
256 return null;
257 }
258
Sangho Shineb083032014-09-22 16:11:34 -0700259 /**
260 * Send an ARP request via ArpHandler
Sangho Shinfbc572c2014-10-02 16:37:05 -0700261 *
Sangho Shineb083032014-09-22 16:11:34 -0700262 * @param destinationAddress
263 * @param sw
264 * @param inPort
Sangho Shinfbc572c2014-10-02 16:37:05 -0700265 *
Sangho Shineb083032014-09-22 16:11:34 -0700266 */
267 public void sendArpRequest(Switch sw, int destinationAddress, Port inPort) {
268 arpHandler.sendArpRequest(sw, destinationAddress, inPort);
269 }
Sangho Shin2f263692014-09-15 14:09:41 -0700270
271 /**
272 * Temporary class to to keep ARP entry
Sangho Shinfbc572c2014-10-02 16:37:05 -0700273 *
Sangho Shin2f263692014-09-15 14:09:41 -0700274 */
275 private class ArpEntry {
276
277 byte[] targetMacAddress;
278 byte[] targetIpAddress;
279
280 private ArpEntry(byte[] macAddress, byte[] ipAddress) {
281 this.targetMacAddress = macAddress;
282 this.targetIpAddress = ipAddress;
283 }
Sangho Shin2f263692014-09-15 14:09:41 -0700284 }
Sangho Shineb083032014-09-22 16:11:34 -0700285
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700286 /**
287 * Topology events that have been generated.
Sangho Shinfbc572c2014-10-02 16:37:05 -0700288 *
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700289 * @param topologyEvents the generated Topology Events
290 * @see TopologyEvents
291 */
292 public void topologyEvents(TopologyEvents topologyEvents)
293 {
Sangho Shin5be3e532014-10-03 17:20:58 -0700294 topologyEventQueue.add(topologyEvents);
Sangho Shinbce900e2014-10-07 17:13:23 -0700295 discoveryTask.reschedule(100, TimeUnit.MILLISECONDS);
Sangho Shin5be3e532014-10-03 17:20:58 -0700296 }
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700297
Sangho Shin23f898d2014-10-13 16:54:00 -0700298 /**
299 * Process the multiple topology events with some delay (100MS at most for now)
300 *
301 */
Sangho Shin5be3e532014-10-03 17:20:58 -0700302 private void handleTopologyChangeEvents() {
Sangho Shinbce900e2014-10-07 17:13:23 -0700303 numOfEventProcess ++;
304
305 Collection<LinkData> linkEntriesAdded = new ArrayList<LinkData>();
306 Collection<PortData> portEntriesAdded = new ArrayList<PortData>();
307 Collection<PortData> portEntriesRemoved = new ArrayList<PortData>();
308 Collection<LinkData> linkEntriesRemoved = new ArrayList<LinkData>();
Sangho Shin99918bd2014-10-08 15:52:35 -0700309 Collection<SwitchData> switchAdded = new ArrayList<SwitchData>();
Sangho Shinbce900e2014-10-07 17:13:23 -0700310 Collection<SwitchData> switchRemoved = new ArrayList<SwitchData>();
311 Collection<MastershipData> mastershipRemoved = new ArrayList<MastershipData>();
312
Sangho Shin5be3e532014-10-03 17:20:58 -0700313 while (!topologyEventQueue.isEmpty()) {
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700314 // We should handle the events in the order of when they happen
315 // TODO: We need to simulate the final results of multiple events
316 // and shoot only the final state.
317 // Ex: link s1-s2 down, link s1-s2 up --> Do nothing
318 // Ex: ink s1-s2 up, s1-p1,p2 down --> link s1-s2 down
Sangho Shin5be3e532014-10-03 17:20:58 -0700319 TopologyEvents topologyEvents = topologyEventQueue.poll();
Sangho Shin99918bd2014-10-08 15:52:35 -0700320 linkEntriesAdded.addAll(topologyEvents.getAddedLinkDataEntries());
321 portEntriesAdded.addAll(topologyEvents.getAddedPortDataEntries());
322 portEntriesRemoved.addAll(topologyEvents.getRemovedPortDataEntries());
323 linkEntriesRemoved.addAll(topologyEvents.getRemovedLinkDataEntries());
324 switchAdded.addAll(topologyEvents.getAddedSwitchDataEntries());
325 switchRemoved.addAll(topologyEvents.getRemovedSwitchDataEntries());
326 mastershipRemoved.addAll(topologyEvents.getRemovedMastershipDataEntries());
Sangho Shinbce900e2014-10-07 17:13:23 -0700327 numOfEvents++;
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700328
329 if (!portEntriesRemoved.isEmpty()) {
330 processPortRemoval(portEntriesRemoved);
331 }
332
333 if (!linkEntriesRemoved.isEmpty()) {
334 processLinkRemoval(linkEntriesRemoved);
335 }
336
337 if (!switchRemoved.isEmpty()) {
338 processSwitchRemoved(switchRemoved);
339 }
340
341 if (!mastershipRemoved.isEmpty()) {
Sangho Shin23f898d2014-10-13 16:54:00 -0700342 log.debug("Mastership is removed. Check if ports are down also.");
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700343 }
344
345 if (!linkEntriesAdded.isEmpty()) {
Sangho Shin23f898d2014-10-13 16:54:00 -0700346 processLinkAdd(linkEntriesAdded, false);
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700347 }
348
349 if (!portEntriesAdded.isEmpty()) {
350 processPortAdd(portEntriesAdded);
351 }
352
353 if (!switchAdded.isEmpty()) {
354 processSwitchAdd(switchAdded);
355 }
Saurav Das82e62972014-10-16 14:53:57 -0700356 linkEntriesAdded.clear();
357 portEntriesAdded.clear();
358 portEntriesRemoved.clear();
359 linkEntriesRemoved.clear();
360 switchAdded.clear();
361 switchRemoved.clear();
362 mastershipRemoved.clear();
363
Sangho Shinbce900e2014-10-07 17:13:23 -0700364 }
365
Sangho Shin23f898d2014-10-13 16:54:00 -0700366 // TODO: 100ms is enough to check both mastership removed events
367 // and the port removed events? What if the PORT_STATUS packets comes late?
368 if (!mastershipRemoved.isEmpty()) {
369 if (portEntriesRemoved.isEmpty()) {
Saurav Das82e62972014-10-16 14:53:57 -0700370 log.debug("Just mastership is removed. Do not do anthing.");
Sangho Shin23f898d2014-10-13 16:54:00 -0700371 }
372 else {
373 HashMap<String, MastershipData> mastershipToRemove =
374 new HashMap<String, MastershipData>();
375 for (MastershipData ms: mastershipRemoved) {
376 for (PortData port: portEntriesRemoved) {
377 // TODO: check ALL ports of the switch are dead ..
378 if (port.getDpid().equals(ms.getDpid())) {
379 mastershipToRemove.put(ms.getDpid().toString(), ms);
380 }
381 }
382 log.debug("Swtich {} is really down.", ms.getDpid());
383 }
384 processMastershipRemoved(mastershipToRemove.values());
385 }
386 }
387
Sangho Shinbce900e2014-10-07 17:13:23 -0700388 log.debug("num events {}, num of process {}, "
389 + "num of Population {}", numOfEvents, numOfEventProcess,
390 numOfPopulation);
391 }
392
393 /**
Sangho Shin23f898d2014-10-13 16:54:00 -0700394 * Add the link immediately
395 * The function is scheduled when link add event happens and called
396 * DELAY_TO_ADD_LINK seconds after the event to avoid link flip-flop.
397 */
398 private void delayedAddLink() {
399
400 processLinkAdd(linksToAdd.values(), true);
401
402 }
403
404 /**
Sangho Shin99918bd2014-10-08 15:52:35 -0700405 * Process the SwitchAdded events from topologyMananger.
406 * It does nothing. When a switch is added, then link will be added too.
407 * LinkAdded event will handle process all re-computation.
408 *
409 * @param switchAdded
410 */
411 private void processSwitchAdd(Collection<SwitchData> switchAdded) {
412
413 }
414
415 /**
Sangho Shinbce900e2014-10-07 17:13:23 -0700416 * Remove all ports connected to the switch removed
417 *
418 * @param mastershipRemoved master switch info removed
419 */
420 private void processMastershipRemoved(Collection<MastershipData>
421 mastershipRemoved) {
422 for (MastershipData mastership: mastershipRemoved) {
423 Switch sw = mutableTopology.getSwitch(mastership.getDpid());
424 for (Link link: sw.getOutgoingLinks()) {
425 Port dstPort = link.getDstPort();
426 IOF13Switch dstSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
427 getSwId(dstPort.getDpid().toString()));
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700428 if (dstSw != null) {
429 dstSw.removePortFromGroups(dstPort.getNumber());
430 log.debug("MasterSwitch {} is gone: remove port {}", sw.getDpid(), dstPort);
431 }
Sangho Shinbce900e2014-10-07 17:13:23 -0700432 }
Sangho Shin61535402014-10-01 11:37:14 -0700433 }
Sangho Shin23f898d2014-10-13 16:54:00 -0700434
435 linksToAdd.clear();
436 linksDown.clear();
Sangho Shin61535402014-10-01 11:37:14 -0700437 }
Sangho Shinc8d2f592014-09-30 16:53:57 -0700438
Sangho Shinbce900e2014-10-07 17:13:23 -0700439 /**
440 * Remove all ports connected to the switch removed
441 *
442 * @param switchRemoved Switch removed
443 */
Sangho Shin5be3e532014-10-03 17:20:58 -0700444 private void processSwitchRemoved(Collection<SwitchData> switchRemoved) {
Sangho Shin23f898d2014-10-13 16:54:00 -0700445 log.debug("SwitchRemoved event occurred !!!");
Sangho Shin5be3e532014-10-03 17:20:58 -0700446 }
447
Sangho Shin61535402014-10-01 11:37:14 -0700448 /**
Sangho Shin99918bd2014-10-08 15:52:35 -0700449 * Report ports added to driver
Sangho Shinfbc572c2014-10-02 16:37:05 -0700450 *
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700451 * @param portEntries
452 */
453 private void processPortAdd(Collection<PortData> portEntries) {
Sangho Shin99918bd2014-10-08 15:52:35 -0700454 // TODO: do we need to add ports with delay?
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700455 for (PortData port : portEntries) {
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700456 Dpid dpid = port.getDpid();
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700457
Sangho Shinfbc572c2014-10-02 16:37:05 -0700458 IOF13Switch sw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700459 getSwId(port.getDpid().toString()));
Sangho Shin815af0c2014-10-10 13:05:45 -0700460 if (sw != null) {
Sangho Shin721ca042014-10-09 13:03:40 -0700461 sw.addPortToGroups(port.getPortNumber());
Sangho Shin15273b62014-10-16 22:22:05 -0700462 //log.debug("Add port {} to switch {}", port, dpid);
Sangho Shin815af0c2014-10-10 13:05:45 -0700463 }
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700464 }
465 }
466
467 /**
468 * Reports ports of new links to driver and recalculate ECMP SPG
Sangho Shin23f898d2014-10-13 16:54:00 -0700469 * If the link to add was removed before, then we just schedule the add link
470 * event and do not recompute the path now.
Sangho Shinfbc572c2014-10-02 16:37:05 -0700471 *
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700472 * @param linkEntries
473 */
Sangho Shin23f898d2014-10-13 16:54:00 -0700474 private void processLinkAdd(Collection<LinkData> linkEntries, boolean delayed) {
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700475
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700476 for (LinkData link : linkEntries) {
Sangho Shin5be3e532014-10-03 17:20:58 -0700477
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700478 SwitchPort srcPort = link.getSrc();
479 SwitchPort dstPort = link.getDst();
480
Sangho Shin23f898d2014-10-13 16:54:00 -0700481 String key = srcPort.getDpid().toString() +
482 dstPort.getDpid().toString();
483 if (!delayed) {
484 if (linksDown.containsKey(key)) {
485 linksToAdd.put(key, link);
486 linksDown.remove(key);
487 linkAddTask.reschedule(DELAY_TO_ADD_LINK, TimeUnit.SECONDS);
488 log.debug("Add link {} with 5 sec delay", link);
489 // TODO: What if we have multiple events of add link:
490 // one is new link add, the other one is link up for
491 // broken link? ECMPSPG function cannot deal with it for now
492 return;
493 }
494 }
495 else {
496 if (linksDown.containsKey(key)) {
497 linksToAdd.remove(key);
498 log.debug("Do not add the link {}: it is down again!", link);
499 return;
500 }
501 }
502
Sangho Shinfbc572c2014-10-02 16:37:05 -0700503 IOF13Switch srcSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700504 getSwId(srcPort.getDpid().toString()));
Sangho Shinfbc572c2014-10-02 16:37:05 -0700505 IOF13Switch dstSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700506 getSwId(dstPort.getDpid().toString()));
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700507
Sangho Shin815af0c2014-10-10 13:05:45 -0700508 if ((srcSw == null) || (dstSw == null))
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700509 continue;
510
511 srcSw.addPortToGroups(srcPort.getPortNumber());
512 dstSw.addPortToGroups(dstPort.getPortNumber());
Sangho Shin5be3e532014-10-03 17:20:58 -0700513
Sangho Shin15273b62014-10-16 22:22:05 -0700514 //log.debug("Add a link port {} to switch {} to add link {}", srcPort, srcSw,
515 // link);
516 //log.debug("Add a link port {} to switch {} to add link {}", dstPort, dstSw,
517 // link);
Sangho Shin815af0c2014-10-10 13:05:45 -0700518
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700519 }
Sangho Shinbce900e2014-10-07 17:13:23 -0700520 populateEcmpRoutingRules(false);
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700521 }
522
523 /**
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700524 * Check if all links are gone b/w the two switches. If all links are gone,
525 * then we need to recalculate the path. Otherwise, just report link failure
526 * to the driver.
Sangho Shinfbc572c2014-10-02 16:37:05 -0700527 *
Sangho Shin61535402014-10-01 11:37:14 -0700528 * @param linkEntries
529 */
530 private void processLinkRemoval(Collection<LinkData> linkEntries) {
Sangho Shinbce900e2014-10-07 17:13:23 -0700531 boolean recomputationRequired = false;
532
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700533 for (LinkData link : linkEntries) {
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700534 SwitchPort srcPort = link.getSrc();
535 SwitchPort dstPort = link.getDst();
Sangho Shinc8d2f592014-09-30 16:53:57 -0700536
Sangho Shinfbc572c2014-10-02 16:37:05 -0700537 IOF13Switch srcSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700538 getSwId(srcPort.getDpid().toString()));
Sangho Shinfbc572c2014-10-02 16:37:05 -0700539 IOF13Switch dstSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700540 getSwId(dstPort.getDpid().toString()));
Sangho Shin815af0c2014-10-10 13:05:45 -0700541 if ((srcSw == null) || (dstSw == null))
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700542 /* If this link is not between two switches, ignore it */
543 continue;
Sangho Shin23f898d2014-10-13 16:54:00 -0700544
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700545 srcSw.removePortFromGroups(srcPort.getPortNumber());
546 dstSw.removePortFromGroups(dstPort.getPortNumber());
Sangho Shin815af0c2014-10-10 13:05:45 -0700547 log.debug("Remove port {} from switch {}", srcPort, srcSw);
548 log.debug("Remove port {} from switch {}", dstPort, dstSw);
549
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700550 Switch srcSwitch = mutableTopology.getSwitch(srcPort.getDpid());
551 if (srcSwitch.getLinkToNeighbor(dstPort.getDpid()) == null) {
Sangho Shinbce900e2014-10-07 17:13:23 -0700552 // TODO: it is only for debugging purpose.
Sangho Shin99918bd2014-10-08 15:52:35 -0700553 // We just need to call populateEcmpRoutingRules() and return;
Sangho Shinbce900e2014-10-07 17:13:23 -0700554 recomputationRequired = true;
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700555 log.debug("All links are gone b/w {} and {}", srcPort.getDpid(),
Sangho Shin5be3e532014-10-03 17:20:58 -0700556 dstPort.getDpid());
Sangho Shinc8d2f592014-09-30 16:53:57 -0700557 }
Sangho Shin23f898d2014-10-13 16:54:00 -0700558
559 String key = link.getSrc().getDpid().toString()+
560 link.getDst().getDpid().toString();
561 if (!linksDown.containsKey(key)) {
562 linksDown.put(key, link);
563 }
Sangho Shinc8d2f592014-09-30 16:53:57 -0700564 }
Sangho Shinbce900e2014-10-07 17:13:23 -0700565
566 if (recomputationRequired)
567 populateEcmpRoutingRules(false);
Sangho Shin61535402014-10-01 11:37:14 -0700568 }
Sangho Shinc8d2f592014-09-30 16:53:57 -0700569
Sangho Shin61535402014-10-01 11:37:14 -0700570 /**
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700571 * report ports removed to the driver immediately
Sangho Shinfbc572c2014-10-02 16:37:05 -0700572 *
Sangho Shin61535402014-10-01 11:37:14 -0700573 * @param portEntries
574 */
575 private void processPortRemoval(Collection<PortData> portEntries) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700576 for (PortData port : portEntries) {
Sangho Shin61535402014-10-01 11:37:14 -0700577 Dpid dpid = port.getDpid();
Sangho Shin61535402014-10-01 11:37:14 -0700578
Sangho Shinfbc572c2014-10-02 16:37:05 -0700579 IOF13Switch sw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin61535402014-10-01 11:37:14 -0700580 getSwId(port.getDpid().toString()));
Sangho Shin815af0c2014-10-10 13:05:45 -0700581 if (sw != null) {
Sangho Shinfbc572c2014-10-02 16:37:05 -0700582 sw.removePortFromGroups(port.getPortNumber());
Sangho Shin815af0c2014-10-10 13:05:45 -0700583 log.debug("Remove port {} from switch {}", port, dpid);
584 }
Sangho Shin61535402014-10-01 11:37:14 -0700585 }
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700586 }
Sangho Shin1aa93542014-09-22 09:49:44 -0700587
588 /**
Sangho Shin43cee112014-09-25 16:43:34 -0700589 * Populate routing rules walking through the ECMP shortest paths
Sangho Shinfbc572c2014-10-02 16:37:05 -0700590 *
Sangho Shin99918bd2014-10-08 15:52:35 -0700591 * @param modified if true, it "modifies" the rules
Sangho Shin1aa93542014-09-22 09:49:44 -0700592 */
Sangho Shin5be3e532014-10-03 17:20:58 -0700593 private void populateEcmpRoutingRules(boolean modified) {
594 graphs.clear();
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700595 Iterable<Switch> switches = mutableTopology.getSwitches();
Sangho Shin43cee112014-09-25 16:43:34 -0700596 for (Switch sw : switches) {
597 ECMPShortestPathGraph ecmpSPG = new ECMPShortestPathGraph(sw);
Sangho Shinfbc572c2014-10-02 16:37:05 -0700598 graphs.put(sw, ecmpSPG);
599 //log.debug("ECMPShortestPathGraph is computed for switch {}",
600 // HexString.toHexString(sw.getDpid().value()));
Sangho Shin5be3e532014-10-03 17:20:58 -0700601 populateEcmpRoutingRulesForPath(sw, ecmpSPG, modified);
Sangho Shinfbc572c2014-10-02 16:37:05 -0700602 }
Sangho Shinbce900e2014-10-07 17:13:23 -0700603 numOfPopulation++;
Sangho Shinfbc572c2014-10-02 16:37:05 -0700604 }
Sangho Shin1aa93542014-09-22 09:49:44 -0700605
Sangho Shin99918bd2014-10-08 15:52:35 -0700606 /**
607 * populate routing rules to forward packets from the switch given to
608 * all other switches.
609 *
610 * @param sw source switch
611 * @param ecmpSPG shortest path from the the source switch to all others
612 * @param modified modification flag
613 */
Sangho Shinfbc572c2014-10-02 16:37:05 -0700614 private void populateEcmpRoutingRulesForPath(Switch sw,
Sangho Shin5be3e532014-10-03 17:20:58 -0700615 ECMPShortestPathGraph ecmpSPG, boolean modified) {
Sangho Shin43cee112014-09-25 16:43:34 -0700616
Sangho Shinfbc572c2014-10-02 16:37:05 -0700617 HashMap<Integer, HashMap<Switch, ArrayList<ArrayList<Dpid>>>> switchVia =
618 ecmpSPG.getAllLearnedSwitchesAndVia();
619 for (Integer itrIdx : switchVia.keySet()) {
620 //log.debug("ECMPShortestPathGraph:Switches learned in "
621 // + "Iteration{} from switch {}:",
622 // itrIdx,
623 // HexString.toHexString(sw.getDpid().value()));
624 HashMap<Switch, ArrayList<ArrayList<Dpid>>> swViaMap =
625 switchVia.get(itrIdx);
626 for (Switch targetSw : swViaMap.keySet()) {
Sangho Shin5be3e532014-10-03 17:20:58 -0700627 //log.debug("ECMPShortestPathGraph:****switch {} via:",
628 // HexString.toHexString(targetSw.getDpid().value()));
Sangho Shinfbc572c2014-10-02 16:37:05 -0700629 String destSw = sw.getDpid().toString();
630 List<String> fwdToSw = new ArrayList<String>();
631
Sangho Shinfbc572c2014-10-02 16:37:05 -0700632 for (ArrayList<Dpid> via : swViaMap.get(targetSw)) {
Sangho Shin5be3e532014-10-03 17:20:58 -0700633 //log.debug("ECMPShortestPathGraph:******{}) {}", ++i, via);
Sangho Shinfbc572c2014-10-02 16:37:05 -0700634 if (via.isEmpty()) {
635 fwdToSw.add(destSw);
Sangho Shin43cee112014-09-25 16:43:34 -0700636 }
Sangho Shinfbc572c2014-10-02 16:37:05 -0700637 else {
638 fwdToSw.add(via.get(0).toString());
639 }
Sangho Shin43cee112014-09-25 16:43:34 -0700640 }
Sangho Shin5be3e532014-10-03 17:20:58 -0700641 setRoutingRule(targetSw, destSw, fwdToSw, modified);
Sangho Shineb083032014-09-22 16:11:34 -0700642 }
Sangho Shinfbc572c2014-10-02 16:37:05 -0700643
644 // Send Barrier Message and make sure all rules are set
645 // before we set the rules to next routers
646 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
647 getSwId(sw.getDpid().toString()));
Sangho Shin5be3e532014-10-03 17:20:58 -0700648 if (sw13 != null) {
649 try {
650 OFBarrierReplyFuture replyFuture = sw13.sendBarrier();
651 replyFuture.get(10, TimeUnit.SECONDS);
652 } catch (IOException e) {
653 e.printStackTrace();
654 } catch (InterruptedException | ExecutionException | TimeoutException e) {
655 log.error("Barrier message not received for sw: {}", sw.getDpid());
656 e.printStackTrace();
657 }
Sangho Shinfbc572c2014-10-02 16:37:05 -0700658 }
659 }
660
661 }
662
663
Sangho Shin99918bd2014-10-08 15:52:35 -0700664 /**
Sangho Shinbce900e2014-10-07 17:13:23 -0700665 * This class is used only for link recovery optimization in
666 * modifyEcmpRoutingRules() function.
Sangho Shin99918bd2014-10-08 15:52:35 -0700667 * TODO: please remove if the optimization is not used at all
Sangho Shinbce900e2014-10-07 17:13:23 -0700668 */
Sangho Shinfbc572c2014-10-02 16:37:05 -0700669 private class SwitchPair {
670 private Switch src;
671 private Switch dst;
672
673 public SwitchPair(Switch src, Switch dst) {
674 this.src = src;
675 this.dst = dst;
676 }
677
678 public Switch getSource() {
679 return src;
680 }
681
682 public Switch getDestination() {
683 return dst;
Sangho Shineb083032014-09-22 16:11:34 -0700684 }
Sangho Shin43cee112014-09-25 16:43:34 -0700685 }
686
687 /**
Sangho Shinfbc572c2014-10-02 16:37:05 -0700688 * Modify the routing rules for the lost links
689 * - Recompute the path if the link failed is included in the path
690 * (including src and dest).
691 *
692 * @param newLink
693 */
694 private void modifyEcmpRoutingRules(LinkData linkRemoved) {
695
696 //HashMap<Switch, SwitchPair> linksToRecompute = new HashMap<Switch, SwitchPair>();
Sangho Shin5be3e532014-10-03 17:20:58 -0700697 Set<SwitchPair> linksToRecompute = new HashSet<SwitchPair>();
Sangho Shinfbc572c2014-10-02 16:37:05 -0700698
699 for (ECMPShortestPathGraph ecmpSPG : graphs.values()) {
700 Switch rootSw = ecmpSPG.getRootSwitch();
701 HashMap<Integer, HashMap<Switch, ArrayList<Path>>> paths =
702 ecmpSPG.getCompleteLearnedSwitchesAndPaths();
703 for (HashMap<Switch, ArrayList<Path>> p: paths.values()) {
704 for (Switch destSw: p.keySet()) {
705 ArrayList<Path> path = p.get(destSw);
706 if (checkPath(path, linkRemoved)) {
Sangho Shin5be3e532014-10-03 17:20:58 -0700707 boolean found = false;
708 for (SwitchPair pair: linksToRecompute) {
709 if (pair.getSource().getDpid() == rootSw.getDpid() &&
710 pair.getSource().getDpid() == destSw.getDpid()) {
711 found = true;
712 }
713 }
714 if (!found) {
715 linksToRecompute.add(new SwitchPair(rootSw, destSw));
716 }
Sangho Shinfbc572c2014-10-02 16:37:05 -0700717 }
718 }
719 }
720 }
721
722 // Recompute the path for the specific route
723 for (SwitchPair pair: linksToRecompute) {
724
725 log.debug("Recompute path from {} to {}", pair.getSource(), pair.getDestination());
Sangho Shin99918bd2014-10-08 15:52:35 -0700726 // We need the following function for optimization
Sangho Shinfbc572c2014-10-02 16:37:05 -0700727 //ECMPShortestPathGraph ecmpSPG =
728 // new ECMPShortestPathGraph(pair.getSource(), pair.getDestination());
729 ECMPShortestPathGraph ecmpSPG =
730 new ECMPShortestPathGraph(pair.getSource());
Sangho Shin5be3e532014-10-03 17:20:58 -0700731 populateEcmpRoutingRulesForPath(pair.getSource(), ecmpSPG, true);
Sangho Shinfbc572c2014-10-02 16:37:05 -0700732 }
733 }
734
735 /**
736 * Check if the path is affected from the link removed
737 *
738 * @param path Path to check
739 * @param linkRemoved link removed
740 * @return true if the path contains the link removed
741 */
742 private boolean checkPath(ArrayList<Path> path, LinkData linkRemoved) {
743
744 for (Path ppp: path) {
745 // TODO: need to check if this is a bidirectional or
746 // unidirectional
Sangho Shin5be3e532014-10-03 17:20:58 -0700747 for (LinkData link: ppp) {
Sangho Shin5be3e532014-10-03 17:20:58 -0700748 if (link.getDst().getDpid().equals(linkRemoved.getDst().getDpid()) &&
749 link.getSrc().getDpid().equals(linkRemoved.getSrc().getDpid()))
750 return true;
Sangho Shinfbc572c2014-10-02 16:37:05 -0700751 }
752 }
753
754 return false;
755 }
756
757 /**
758 *
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700759 * Set routing rules in targetSw {forward packets to fwdToSw switches in
760 * order to send packets to destSw} - If the target switch is an edge router
761 * and final destnation switch is also an edge router, then set IP
762 * forwarding rules to subnets - If only the target switch is an edge
763 * router, then set IP forwarding rule to the transit router loopback IP
764 * address - If the target is a transit router, then just set the MPLS
765 * forwarding rule
Sangho Shinfbc572c2014-10-02 16:37:05 -0700766 *
Sangho Shin43cee112014-09-25 16:43:34 -0700767 * @param targetSw Switch to set the rules
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700768 * @param destSw Final destination switches
Sangho Shin43cee112014-09-25 16:43:34 -0700769 * @param fwdToSw next hop switches
770 */
Sangho Shin99918bd2014-10-08 15:52:35 -0700771 private void setRoutingRule(Switch targetSw, String destSw,
772 List<String> fwdToSw, boolean modified) {
Sangho Shin43cee112014-09-25 16:43:34 -0700773
Sangho Shin43cee112014-09-25 16:43:34 -0700774 if (fwdToSw.isEmpty()) {
775 fwdToSw.add(destSw);
776 }
777
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700778 // if both target SW and dest SW are an edge router, then set IP table
Sangho Shin43cee112014-09-25 16:43:34 -0700779 if (IsEdgeRouter(targetSw.getDpid().toString()) &&
780 IsEdgeRouter(destSw)) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700781 // We assume that there is at least one transit router b/w edge
782 // routers
Sangho Shin43cee112014-09-25 16:43:34 -0700783 Switch destSwitch = mutableTopology.getSwitch(new Dpid(destSw));
784 String subnets = destSwitch.getStringAttribute("subnets");
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700785 setIpTableRouterSubnet(targetSw, subnets, getMplsLabel(destSw)
Sangho Shin5be3e532014-10-03 17:20:58 -0700786 , fwdToSw, modified);
Sangho Shin43cee112014-09-25 16:43:34 -0700787
Sangho Shin43cee112014-09-25 16:43:34 -0700788 String routerIp = destSwitch.getStringAttribute("routerIp");
Sangho Shin5be3e532014-10-03 17:20:58 -0700789 setIpTableRouter(targetSw, routerIp, getMplsLabel(destSw), fwdToSw,
790 null, modified);
Sangho Shin721ca042014-10-09 13:03:40 -0700791 // Edge router can be a transit router
792 setMplsTable(targetSw, getMplsLabel(destSw), fwdToSw, modified);
Sangho Shin43cee112014-09-25 16:43:34 -0700793 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700794 // Only if the target switch is the edge router, then set the IP rules
Sangho Shin43cee112014-09-25 16:43:34 -0700795 else if (IsEdgeRouter(targetSw.getDpid().toString())) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700796 // We assume that there is at least one transit router b/w edge
797 // routers
Sangho Shin43cee112014-09-25 16:43:34 -0700798 Switch destSwitch = mutableTopology.getSwitch(new Dpid(destSw));
799 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 }
805 // if it is a transit router, then set rules in the MPLS table
806 else {
Sangho Shin5be3e532014-10-03 17:20:58 -0700807 setMplsTable(targetSw, getMplsLabel(destSw), fwdToSw, modified);
Sangho Shin43cee112014-09-25 16:43:34 -0700808 }
809
810 }
811
Sangho Shinfbc572c2014-10-02 16:37:05 -0700812 /**
813 * Set IP forwarding rule to the gateway of each subnet of switches
814 *
815 * @param targetSw Switch to set rules
816 * @param subnets subnet information
817 * @param mplsLabel destination MPLS label
818 * @param fwdToSw router to forward packets to
819 */
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700820 private void setIpTableRouterSubnet(Switch targetSw, String subnets,
Sangho Shin5be3e532014-10-03 17:20:58 -0700821 String mplsLabel, List<String> fwdToSw, boolean modified) {
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700822
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700823 Collection<MatchActionOperationEntry> entries =
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700824 new ArrayList<MatchActionOperationEntry>();
825
826 try {
827 JSONArray arry = new JSONArray(subnets);
828 for (int i = 0; i < arry.length(); i++) {
829 String subnetIp = (String) arry.getJSONObject(i).get("subnetIp");
Sangho Shin5be3e532014-10-03 17:20:58 -0700830 setIpTableRouter(targetSw, subnetIp, mplsLabel, fwdToSw, entries,
831 modified);
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700832 }
833 } catch (JSONException e) {
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700834 e.printStackTrace();
835 }
836
837 if (!entries.isEmpty()) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700838 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700839 getSwId(targetSw.getDpid().toString()));
840
Sangho Shin721ca042014-10-09 13:03:40 -0700841 if (sw13 != null) {
842 try {
843 sw13.pushFlows(entries);
844 } catch (IOException e) {
845 e.printStackTrace();
846 }
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700847 }
848 }
849
850 }
851
Sangho Shin43cee112014-09-25 16:43:34 -0700852 /**
Sangho Shin99918bd2014-10-08 15:52:35 -0700853 * Check if the switch is the edge router or not.
Sangho Shinfbc572c2014-10-02 16:37:05 -0700854 *
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700855 * @param dpid Dpid of the switch to check
Sangho Shin43cee112014-09-25 16:43:34 -0700856 * @return true if it is an edge router, otherwise false
857 */
858 private boolean IsEdgeRouter(String dpid) {
859
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700860 for (Switch sw : mutableTopology.getSwitches()) {
Sangho Shin43cee112014-09-25 16:43:34 -0700861 String dpidStr = sw.getDpid().toString();
862 if (dpid.equals(dpidStr)) {
Sangho Shinbce900e2014-10-07 17:13:23 -0700863 /*
Sangho Shin43cee112014-09-25 16:43:34 -0700864 String subnetInfo = sw.getStringAttribute("subnets");
865 if (subnetInfo == null || subnetInfo.equals("[]")) {
866 return false;
867 }
868 else
869 return true;
Sangho Shinbce900e2014-10-07 17:13:23 -0700870 */
871 String isEdge = sw.getStringAttribute("isEdgeRouter");
872 if (isEdge != null) {
873 if (isEdge.equals("true"))
874 return true;
875 else
876 return false;
877 }
Sangho Shin43cee112014-09-25 16:43:34 -0700878 }
879 }
880
881 return false;
882 }
883
884 /**
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700885 * Set IP forwarding rule - If the destination is the next hop, then do not
886 * push MPLS, just decrease the NW TTL - Otherwise, push MPLS label and set
887 * the MPLS ID
Sangho Shinfbc572c2014-10-02 16:37:05 -0700888 *
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700889 * @param sw target switch to set rules
Sangho Shin43cee112014-09-25 16:43:34 -0700890 * @param subnetIp Match IP address
891 * @param mplsLabel MPLS label of final destination router
892 * @param fwdToSws next hop routers
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700893 * @param entries
Sangho Shin43cee112014-09-25 16:43:34 -0700894 */
895 private void setIpTableRouter(Switch sw, String subnetIp, String mplsLabel,
Sangho Shin5be3e532014-10-03 17:20:58 -0700896 List<String> fwdToSws, Collection<MatchActionOperationEntry> entries,
897 boolean modified) {
Sangho Shin43cee112014-09-25 16:43:34 -0700898
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700899 Ipv4Match ipMatch = new Ipv4Match(subnetIp);
Sangho Shin43cee112014-09-25 16:43:34 -0700900 List<Action> actions = new ArrayList<>();
Sangho Shin721ca042014-10-09 13:03:40 -0700901 GroupAction groupAction = new GroupAction();
Sangho Shin43cee112014-09-25 16:43:34 -0700902
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700903 // If destination SW is the same as the fwd SW, then do not push MPLS
904 // label
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700905 if (fwdToSws.size() > 1) {
Sangho Shin43cee112014-09-25 16:43:34 -0700906 PushMplsAction pushMplsAction = new PushMplsAction();
907 SetMplsIdAction setIdAction = new SetMplsIdAction(Integer.parseInt(mplsLabel));
908 CopyTtlOutAction copyTtlOutAction = new CopyTtlOutAction();
Sangho Shin463bee52014-09-29 15:14:43 -0700909 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
Sangho Shin43cee112014-09-25 16:43:34 -0700910
Sangho Shin62ce5c12014-10-08 16:24:40 -0700911 //actions.add(pushMplsAction);
912 //actions.add(copyTtlOutAction);
913 //actions.add(decMplsTtlAction);
Saurav Das82e62972014-10-16 14:53:57 -0700914 // actions.add(setIdAction);
Sangho Shin721ca042014-10-09 13:03:40 -0700915 groupAction.setEdgeLabel(Integer.parseInt(mplsLabel));
Sangho Shin43cee112014-09-25 16:43:34 -0700916 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700917 else {
918 String fwdToSw = fwdToSws.get(0);
919 if (getMplsLabel(fwdToSw).equals(mplsLabel)) {
920 DecNwTtlAction decTtlAction = new DecNwTtlAction(1);
921 actions.add(decTtlAction);
922 }
923 else {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700924 SetMplsIdAction setIdAction = new SetMplsIdAction(
925 Integer.parseInt(mplsLabel));
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700926 CopyTtlOutAction copyTtlOutAction = new CopyTtlOutAction();
Sangho Shin463bee52014-09-29 15:14:43 -0700927 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700928
Sangho Shin62ce5c12014-10-08 16:24:40 -0700929 //actions.add(pushMplsAction);
930 //actions.add(copyTtlOutAction);
931 //actions.add(decMplsTtlAction);
Saurav Das82e62972014-10-16 14:53:57 -0700932 // actions.add(setIdAction);
Sangho Shin721ca042014-10-09 13:03:40 -0700933 groupAction.setEdgeLabel(Integer.parseInt(mplsLabel));
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700934 }
935 }
Sangho Shin43cee112014-09-25 16:43:34 -0700936
Sangho Shin43cee112014-09-25 16:43:34 -0700937 for (String fwdSw : fwdToSws) {
938 groupAction.addSwitch(new Dpid(fwdSw));
939 }
940 actions.add(groupAction);
941
Sangho Shin99918bd2014-10-08 15:52:35 -0700942 MatchAction matchAction = new MatchAction(new MatchActionId(matchActionId++),
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700943 new SwitchPort((long) 0, (short) 0), ipMatch, actions);
Sangho Shin43cee112014-09-25 16:43:34 -0700944
Sangho Shin5be3e532014-10-03 17:20:58 -0700945 Operator operator = null;
946 if (modified)
947 operator = Operator.MODIFY;
948 else
949 operator = Operator.ADD;
950
Sangho Shin43cee112014-09-25 16:43:34 -0700951 MatchActionOperationEntry maEntry =
Sangho Shin5be3e532014-10-03 17:20:58 -0700952 new MatchActionOperationEntry(operator, matchAction);
Sangho Shin43cee112014-09-25 16:43:34 -0700953
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700954 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700955 getSwId(sw.getDpid().toString()));
956
Sangho Shin5be3e532014-10-03 17:20:58 -0700957 if (sw13 != null) {
958 try {
Sangho Shinbce900e2014-10-07 17:13:23 -0700959 //printMatchActionOperationEntry(sw, maEntry);
Sangho Shin5be3e532014-10-03 17:20:58 -0700960 if (entries != null)
961 entries.add(maEntry);
962 else
963 sw13.pushFlow(maEntry);
964 } catch (IOException e) {
965 e.printStackTrace();
966 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700967 }
968
Sangho Shin43cee112014-09-25 16:43:34 -0700969 }
970
Sangho Shinac5ee2b2014-09-28 21:27:20 -0700971 /**
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700972 * Set MPLS forwarding rules to MPLS table
973 * </p>
974 * If the destination is the same as the next hop to forward packets then,
975 * pop the MPLS label according to PHP rule. Here, if BoS is set, then
976 * copy TTL In and decrement NW TTL. Otherwise, it just decrement the MPLS
977 * TTL of the another MPLS header.
978 * If the next hop is not the destination, just forward packets to next
979 * hops using Group action.
Sangho Shinfbc572c2014-10-02 16:37:05 -0700980 *
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700981 * @param sw Switch to set the rules
Sangho Shin43cee112014-09-25 16:43:34 -0700982 * @param mplsLabel destination MPLS label
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700983 * @param fwdSws next hop switches
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700984 * */
Sangho Shin5be3e532014-10-03 17:20:58 -0700985 private void setMplsTable(Switch sw, String mplsLabel, List<String> fwdSws,
986 boolean modified) {
Sangho Shin463bee52014-09-29 15:14:43 -0700987
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700988 if (fwdSws.isEmpty())
989 return;
Sangho Shin43cee112014-09-25 16:43:34 -0700990
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700991 Collection<MatchActionOperationEntry> maEntries =
992 new ArrayList<MatchActionOperationEntry>();
993 String fwdSw1 = fwdSws.get(0);
Sangho Shin43cee112014-09-25 16:43:34 -0700994
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700995 if (fwdSws.size() == 1 && mplsLabel.equals(getMplsLabel(fwdSw1))) {
996 // One rule for Bos = 1
997 MplsMatch mplsMatch = new MplsMatch(Integer.parseInt(mplsLabel), true);
998 List<Action> actions = new ArrayList<Action>();
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700999
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001000 PopMplsAction popAction = new PopMplsAction(EthType.IPv4);
1001 CopyTtlInAction copyTtlInAction = new CopyTtlInAction();
1002 DecNwTtlAction decNwTtlAction = new DecNwTtlAction(1);
1003
1004 actions.add(copyTtlInAction);
1005 actions.add(popAction);
1006 actions.add(decNwTtlAction);
1007
1008 GroupAction groupAction = new GroupAction();
1009 groupAction.addSwitch(new Dpid(fwdSw1));
1010 actions.add(groupAction);
1011
1012 MatchAction matchAction = new MatchAction(new MatchActionId(matchActionId++),
1013 new SwitchPort((long) 0, (short) 0), mplsMatch, actions);
1014 Operator operator = Operator.ADD;
1015 MatchActionOperationEntry maEntry =
1016 new MatchActionOperationEntry(operator, matchAction);
1017 maEntries.add(maEntry);
1018
1019 // One rule for Bos = 0
Sangho Shin23f898d2014-10-13 16:54:00 -07001020 MplsMatch mplsMatchBos = new MplsMatch(Integer.parseInt(mplsLabel), false);
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001021 List<Action> actionsBos = new ArrayList<Action>();
Sangho Shin15273b62014-10-16 22:22:05 -07001022 PopMplsAction popActionBos = new PopMplsAction(EthType.MPLS_UNICAST);
1023 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
1024
1025 actionsBos.add(copyTtlInAction);
1026 actionsBos.add(popActionBos);
1027 actionsBos.add(decMplsTtlAction);
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001028 actionsBos.add(groupAction);
1029
1030 MatchAction matchActionBos = new MatchAction(new MatchActionId(matchActionId++),
1031 new SwitchPort((long) 0, (short) 0), mplsMatchBos, actionsBos);
1032 MatchActionOperationEntry maEntryBos =
1033 new MatchActionOperationEntry(operator, matchActionBos);
1034 maEntries.add(maEntryBos);
Sangho Shin9c0f4c32014-09-26 16:02:38 -07001035 }
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001036 else {
1037 MplsMatch mplsMatch = new MplsMatch(Integer.parseInt(mplsLabel), false);
1038 List<Action> actions = new ArrayList<Action>();
Sangho Shin43cee112014-09-25 16:43:34 -07001039
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001040 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
1041 actions.add(decMplsTtlAction);
Sangho Shin43cee112014-09-25 16:43:34 -07001042
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001043 GroupAction groupAction = new GroupAction();
1044 for (String fwdSw : fwdSws)
1045 groupAction.addSwitch(new Dpid(fwdSw));
1046 actions.add(groupAction);
Sangho Shin5be3e532014-10-03 17:20:58 -07001047
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001048 MatchAction matchAction = new MatchAction(new MatchActionId(
1049 matchActionId++),
1050 new SwitchPort((long) 0, (short) 0), mplsMatch, actions);
1051 Operator operator = Operator.ADD;
1052 MatchActionOperationEntry maEntry =
1053 new MatchActionOperationEntry(operator, matchAction);
1054 maEntries.add(maEntry);
Sangho Shine2e9bcd2014-10-13 15:14:18 -07001055
1056 // BoS = 1
1057 MplsMatch mplsMatchBoS = new MplsMatch(Integer.parseInt(mplsLabel), true);
1058 List<Action> actionsBoS = new ArrayList<Action>();
1059
1060 DecMplsTtlAction decMplsTtlActionBoS = new DecMplsTtlAction(1);
1061 actionsBoS.add(decMplsTtlActionBoS);
1062
1063 GroupAction groupActionBoS = new GroupAction();
1064 for (String fwdSw : fwdSws)
1065 groupActionBoS.addSwitch(new Dpid(fwdSw));
1066 actionsBoS.add(groupActionBoS);
1067
1068 MatchAction matchActionBos = new MatchAction(new MatchActionId(
1069 matchActionId++),
1070 new SwitchPort((long) 0, (short) 0), mplsMatchBoS, actionsBoS);
1071 MatchActionOperationEntry maEntryBoS =
1072 new MatchActionOperationEntry(operator, matchActionBos);
1073 maEntries.add(maEntryBoS);
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001074 }
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001075 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin9c0f4c32014-09-26 16:02:38 -07001076 getSwId(sw.getDpid().toString()));
1077
Sangho Shin5be3e532014-10-03 17:20:58 -07001078 if (sw13 != null) {
1079 try {
Sangho Shinbce900e2014-10-07 17:13:23 -07001080 //printMatchActionOperationEntry(sw, maEntry);
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001081 sw13.pushFlows(maEntries);
Sangho Shin5be3e532014-10-03 17:20:58 -07001082 } catch (IOException e) {
1083 e.printStackTrace();
1084 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -07001085 }
Sangho Shin43cee112014-09-25 16:43:34 -07001086 }
1087
Sangho Shin15273b62014-10-16 22:22:05 -07001088 /**
1089 * Create a tunnel for policy routing
1090 * It delivers the node IDs of tunnels to driver.
1091 * Split the node IDs if number of IDs exceeds the limit for stitching.
1092 *
1093 * @param tunnelId Node IDs for the tunnel
1094 * @param Ids tunnel ID
1095 */
1096 public boolean createTunnel(int tunnelId, List<String> Ids) {
1097
1098 if (tunnelId < 0) {
1099 log.debug("Tunnel ID should be posivtive integer.");
1100 return false;
1101 }
1102
1103 if (Ids.isEmpty() || Ids.size() < 2) {
1104 log.debug("Wrong tunnel information");
1105 return false;
1106 }
1107
1108 HashMap<String, PolicyRouteInfo> stitchingRule = getStitchingRule(Ids);
1109 stitchInfo.put(Integer.valueOf(tunnelId), stitchingRule);
1110 if (stitchingRule == null) {
1111 log.debug("Failed to get the policy rule.");
1112 return false;
1113 }
1114 HashMap<String, Integer> switchGroupPair = new HashMap<String, Integer>();
1115 for (String targetDpid: stitchingRule.keySet()) {
1116 PolicyRouteInfo route = stitchingRule.get(targetDpid);
1117
1118 IOF13Switch targetSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
1119 getSwId(targetDpid.toString()));
1120
1121 if (targetSw == null) {
1122 log.debug("Switch {} is gone.", targetDpid);
1123 return false;
1124 }
1125
1126 NeighborSet ns = new NeighborSet();
1127 for (Dpid dpid: route.getFwdSwDpid())
1128 ns.addDpid(dpid);
1129
1130 printTunnelInfo(targetSw, tunnelId, route.getRoute(), ns);
1131 int groupId = targetSw.createTunnel(tunnelId, route.getRoute(), ns);
1132 switchGroupPair.put(targetDpid.toString(), groupId);
1133
1134 }
1135
1136 tunnelGroupMap.put(Integer.valueOf(tunnelId), switchGroupPair);
1137
1138 return true;
1139 }
1140
1141 /**
1142 * Set policy table for policy routing
1143 *
1144 * @param sw
1145 * @param mplsLabel
1146 */
1147 private void setPolicyTable(MACAddress srcMac, MACAddress dstMac,
1148 Short etherType, IPv4Net srcIp, IPv4Net dstIp, Byte ipProto,
1149 Short srcTcpPort, Short dstTcpPort, int tid) {
1150
1151 HashMap<String, PolicyRouteInfo> routeInfo = stitchInfo.get(Integer.valueOf(tid));
1152 HashMap<String, Integer> switchGroupPair = tunnelGroupMap.get(Integer.valueOf(tid));
1153 for (String srcDpid: routeInfo.keySet()) {
1154
1155 PacketMatchBuilder packetBuilder = new PacketMatchBuilder();
1156
1157 if (srcMac != null)
1158 packetBuilder.setSrcMac(srcMac);
1159 if (dstMac != null)
1160 packetBuilder.setDstMac(dstMac);
1161 if (etherType != null) {
1162 packetBuilder.setEtherType(etherType);
1163 }
1164 if (srcIp != null) {
1165 packetBuilder.setSrcIp(srcIp.address(), srcIp.prefixLen());
1166 }
1167 if (dstIp != null) {
1168 packetBuilder.setDstIp(dstIp.address(), dstIp.prefixLen());
1169 }
1170 if (ipProto != null) {
1171 packetBuilder.setIpProto(ipProto);
1172 }
1173 if (srcTcpPort > 0) {
1174 packetBuilder.setSrcTcpPort(srcTcpPort);
1175 }
1176 if (dstTcpPort > 0) {
1177 packetBuilder.setDstTcpPort(dstTcpPort);
1178 }
1179 PacketMatch policyMatch = packetBuilder.build();
1180
1181 List<Action> actions = new ArrayList<>();
1182 GroupAction groupAction = new GroupAction();
1183 int gropuId = switchGroupPair.get(srcDpid);
1184 groupAction.setGroupId(gropuId);
1185 actions.add(groupAction);
1186
1187 MatchAction matchAction = new MatchAction(new MatchActionId(
1188 matchActionId++),
1189 new SwitchPort((long) 0, (short) 0), policyMatch, actions);
1190 MatchActionOperationEntry maEntry =
1191 new MatchActionOperationEntry(Operator.ADD, matchAction);
1192
1193 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
1194 getSwId(srcDpid));
1195
1196 if (sw13 != null) {
1197 printMatchActionOperationEntry(sw13, maEntry);
1198 try {
1199 sw13.pushFlow(maEntry);
1200 } catch (IOException e) {
1201 e.printStackTrace();
1202 }
1203 }
1204 }
1205 }
1206
1207 /**
1208 * Get the forwarding Switch DPIDs to send packets to a node
1209 *
1210 * @param srcSw source switch
1211 * @param nodeId destination node Id
1212 * @return list of switch DPID to forward packets to
1213 */
1214
1215 private List<Dpid> getForwardingSwitchForNodeId(Switch srcSw, String nodeId) {
1216
1217 List<Dpid> fwdSws = new ArrayList<Dpid>();
1218 Switch destSw = null;
1219
1220 destSw = getSwitchFromNodeId(nodeId);
1221
1222 if (destSw == null) {
1223 log.debug("Cannot find the switch with ID {}", nodeId);
1224 return null;
1225 }
1226
1227 ECMPShortestPathGraph ecmpSPG = new ECMPShortestPathGraph(srcSw);
1228
1229 HashMap<Integer, HashMap<Switch, ArrayList<ArrayList<Dpid>>>> switchVia =
1230 ecmpSPG.getAllLearnedSwitchesAndVia();
1231 for (Integer itrIdx : switchVia.keySet()) {
1232 HashMap<Switch, ArrayList<ArrayList<Dpid>>> swViaMap =
1233 switchVia.get(itrIdx);
1234 for (Switch targetSw : swViaMap.keySet()) {
1235 String destSwDpid = destSw.getDpid().toString();
1236 if (targetSw.getDpid().toString().equals(destSwDpid)) {
1237 for (ArrayList<Dpid> via : swViaMap.get(targetSw)) {
1238 if (via.isEmpty()) {
1239 fwdSws.add(destSw.getDpid());
1240 }
1241 else {
1242 fwdSws.add(via.get(0));
1243 }
1244 }
1245 }
1246 }
1247 }
1248
1249 return fwdSws;
1250 }
1251
1252 /**
1253 * Get switch for the node Id specified
1254 *
1255 * @param nodeId node ID for switch
1256 * @return Switch
1257 */
1258 private Switch getSwitchFromNodeId(String nodeId) {
1259
1260 for (Switch sw : mutableTopology.getSwitches()) {
1261 String id = sw.getStringAttribute("nodeSid");
1262 if (id.equals(nodeId)) {
1263 return sw;
1264 }
1265 }
1266
1267 return null;
1268 }
1269
1270 /**
1271 * Convert a string DPID to its Switch Id (integer)
1272 *
1273 * @param dpid
1274 * @return
1275 */
1276 private long getSwId(String dpid) {
1277
1278 long swId = 0;
1279
1280 String swIdHexStr = "0x"+dpid.substring(dpid.lastIndexOf(":") + 1);
1281 if (swIdHexStr != null)
1282 swId = Integer.decode(swIdHexStr);
1283
1284 return swId;
1285 }
1286
1287 private void runTest() {
1288
1289 String[] routeArray = {"101", "102", "103", "104", "105", "108", "110"};
1290 List<String> routeList = new ArrayList<String>();
1291 for (int i = 0; i < routeArray.length; i++)
1292 routeList.add(routeArray[i]);
1293
1294 if (createTunnel(1, routeList)) {
1295 IPv4Net srcIp = new IPv4Net("10.0.1.1/24");
1296 IPv4Net dstIp = new IPv4Net("10.1.2.1/24");
1297
1298 this.setPolicyTable(null, null, Ethernet.TYPE_IPV4, srcIp, dstIp, IPv4.PROTOCOL_ICMP, (short)-1, (short)-1, 1);
1299 }
1300 else {
1301 testTask.reschedule(5, TimeUnit.SECONDS);
1302 }
1303 }
1304
1305 private void runTest1() {
1306
1307 String dpid1 = "00:00:00:00:00:00:00:01";
1308 String dpid2 = "00:00:00:00:00:00:00:0a";
1309 Switch srcSw = mutableTopology.getSwitch(new Dpid(dpid1));
1310 Switch dstSw = mutableTopology.getSwitch(new Dpid(dpid2));
1311
1312 if (srcSw == null || dstSw == null) {
1313 testTask.reschedule(1, TimeUnit.SECONDS);
1314 log.debug("Switch is gone. Reschedule the test");
1315 return;
1316 }
1317
1318 String[] routeArray = {"101", "102", "105", "108", "110"};
1319 List<String> routeList = new ArrayList<String>();
1320 for (int i = 0; i < routeArray.length; i++)
1321 routeList.add(routeArray[i]);
1322
1323 List<String> optimizedRoute = this.getOptimizedPath(srcSw, dstSw, routeList);
1324
1325 log.debug("Test set is {}", routeList.toString());
1326 log.debug("Result set is {}", optimizedRoute.toString());
1327
1328
1329 }
1330
1331 /**
1332 * Optimize the mpls label
1333 * The feature will be used only for policy of "avoid a specific switch".
1334 * Check route to each router in route backward.
1335 * If there is only one route to the router and the routers are included in
1336 * the route, remove the id from the path.
1337 * A-B-C-D-E => A-B-C-D-E -> A-E
1338 * | | => A-B-H-I -> A-I
1339 * F-G-H-I => A-D-I -> A-D-I
1340 */
1341 private List<String> getOptimizedPath(Switch srcSw, Switch dstSw, List<String> route) {
1342
1343 List<String> optimizedPath = new ArrayList<String>();
1344 optimizedPath.addAll(route);
1345 ECMPShortestPathGraph ecmpSPG = new ECMPShortestPathGraph(srcSw);
1346
1347 HashMap<Integer, HashMap<Switch, ArrayList<Path>>> paths =
1348 ecmpSPG.getCompleteLearnedSwitchesAndPaths();
1349 for (HashMap<Switch, ArrayList<Path>> p: paths.values()) {
1350 for (Switch s: p.keySet()) {
1351 if (s.getDpid().toString().equals(dstSw.getDpid().toString())) {
1352 ArrayList<Path> ecmpPaths = p.get(s);
1353 if (ecmpPaths!= null && ecmpPaths.size() == 1) {
1354 for (Path path: ecmpPaths) {
1355 for (LinkData link: path) {
1356 String srcId = getMplsLabel(link.getSrc().getDpid().toString());
1357 String dstId = getMplsLabel(link.getSrc().getDpid().toString());
1358 if (optimizedPath.contains(srcId)) {
1359 optimizedPath.remove(srcId);
1360 }
1361 if (optimizedPath.contains(dstId)) {
1362 optimizedPath.remove(dstId);
1363 }
1364 }
1365 }
1366 }
1367 }
1368 }
1369 }
1370
1371 return optimizedPath;
1372
1373 }
1374
1375
1376 class PolicyRouteInfo {
1377
1378 String srcSwDpid;
1379 List<Dpid> fwdSwDpids;
1380 List<String> route;
1381
1382 PolicyRouteInfo() {
1383 fwdSwDpids = new ArrayList<Dpid>();
1384 route = new ArrayList<String>();
1385 }
1386
1387 void setSrcDpid(String dpid) {
1388 this.srcSwDpid = dpid;
1389 }
1390
1391 void setFwdSwDpid(List<Dpid> dpid) {
1392 this.fwdSwDpids = dpid;
1393 }
1394
1395 void addRoute(String id) {
1396 route.add(id);
1397 }
1398
1399 void setRoute(List<String> r) {
1400 this.route = r;
1401 }
1402
1403 String getSrcSwDpid() {
1404 return this.srcSwDpid;
1405 }
1406
1407 List<Dpid> getFwdSwDpid() {
1408 return this.fwdSwDpids;
1409 }
1410
1411 List<String> getRoute() {
1412 return this.route;
1413 }
1414 }
1415
1416
1417 /**
1418 *
1419 *
1420 * @param srcSw
1421 * @param dstSw
1422 * @param route
1423 * @return
1424 */
1425 private HashMap<String, PolicyRouteInfo> getStitchingRule(List<String> route) {
1426
1427 if (route.isEmpty() || route.size() < 2)
1428 return null;
1429
1430 HashMap<String, PolicyRouteInfo> rules = new HashMap<String, PolicyRouteInfo>();
1431
1432 Switch srcSw = this.getSwitchFromNodeId(route.get(0));
1433 String srcDpid = srcSw.getDpid().toString();
1434
1435 if (route.size() <= MAX_NUM_LABELS+1) {
1436 PolicyRouteInfo info = new PolicyRouteInfo();
1437 info.setSrcDpid(srcSw.getDpid().toString());
1438 List<Dpid> fwdSwDpids = getForwardingSwitchForNodeId(srcSw, route.get(1));
1439 info.setFwdSwDpid(fwdSwDpids);
1440 route.remove(0);
1441 info.setRoute(route);
1442 rules.put(srcDpid, info);
1443 return rules;
1444 }
1445
1446 int i = 0;
1447 PolicyRouteInfo routeInfo = new PolicyRouteInfo();
1448 String prevNodeId = null;
1449 boolean checkNeighbor = true;
1450
1451 for (String nodeId: route) {
1452 if (i == 0) {
1453 routeInfo.setSrcDpid(srcDpid);
1454 srcSw = getSwitchFromNodeId(nodeId);
1455 i++;
1456 }
1457 else if (i == 1) {
1458 if (checkNeighbor) {
1459 // Check if next node is the neighbor SW of the source SW
1460 List<Dpid> fwdSwDpids = getForwardingSwitchForNodeId(srcSw, nodeId);
1461 if (fwdSwDpids == null || fwdSwDpids.isEmpty()) {
1462 log.debug("There is no route from node {} to node {}", srcSw.getDpid(), nodeId);
1463 return null;
1464 }
1465 // If first Id is one of the neighbors, do not include it to route, but set it as a fwd SW.
1466 boolean match = false;
1467 for (Dpid dpid: fwdSwDpids) {
1468 if (getMplsLabel(dpid.toString()).toString().equals(nodeId)) {
1469 List<Dpid> fwdSws = new ArrayList<Dpid>();
1470 fwdSws.add(dpid);
1471 routeInfo.setFwdSwDpid(fwdSws);
1472 match = true;
1473 break;
1474 }
1475 }
1476 if (!match) {
1477 routeInfo.addRoute(nodeId);
1478 routeInfo.setFwdSwDpid(fwdSwDpids);
1479 i++;
1480 }
1481
1482 checkNeighbor = false;
1483 }
1484 else {
1485 routeInfo.addRoute(nodeId);
1486 i++;
1487 }
1488 }
1489 else {
1490 routeInfo.addRoute(nodeId);
1491 i++;
1492 }
1493
1494 if (i == MAX_NUM_LABELS+1) {
1495 rules.put(srcDpid, routeInfo);
1496 routeInfo = new PolicyRouteInfo();
1497 srcSw = getSwitchFromNodeId(nodeId);
1498 srcDpid = getSwitchFromNodeId(nodeId).getDpid().toString();
1499 routeInfo.setSrcDpid(srcDpid);
1500 i = 1;
1501 checkNeighbor = true;
1502 }
1503 }
1504
1505 if (i < MAX_NUM_LABELS+1) {
1506 rules.put(srcDpid, routeInfo);
1507 }
1508
1509 return rules;
1510 }
1511
1512 /**
1513 * print tunnel info - used only for debugging.
1514 * @param targetSw
1515 *
1516 * @param fwdSwDpids
1517 * @param ids
1518 * @param tunnelId
1519 */
1520 private void printTunnelInfo(IOF13Switch targetSw, int tunnelId,
1521 List<String> ids, NeighborSet ns) {
1522 StringBuilder logStr = new StringBuilder("In switch " +
1523 targetSw.getId() + ", create a tunnel " + tunnelId + " " + " of push ");
1524 for (String id: ids)
1525 logStr.append(id + "-");
1526 logStr.append(" output to ");
1527 for (Dpid dpid: ns.getDpids())
1528 logStr.append(dpid + " - ");
1529
1530 log.debug(logStr.toString());
1531
1532 }
1533
1534
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001535
Sangho Shin43cee112014-09-25 16:43:34 -07001536 /**
1537 * Debugging function to print out the Match Action Entry
Sangho Shin15273b62014-10-16 22:22:05 -07001538 * @param sw13
Sangho Shinfbc572c2014-10-02 16:37:05 -07001539 *
Sangho Shin43cee112014-09-25 16:43:34 -07001540 * @param maEntry
1541 */
Sangho Shin15273b62014-10-16 22:22:05 -07001542 private void printMatchActionOperationEntry(
1543 IOF13Switch sw13, MatchActionOperationEntry maEntry) {
Sangho Shin43cee112014-09-25 16:43:34 -07001544
Sangho Shin15273b62014-10-16 22:22:05 -07001545 StringBuilder logStr = new StringBuilder("In switch " + sw13.getId() + ", ");
Sangho Shin43cee112014-09-25 16:43:34 -07001546
1547 MatchAction ma = maEntry.getTarget();
1548 Match m = ma.getMatch();
1549 List<Action> actions = ma.getActions();
1550
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001551 if (m instanceof Ipv4Match) {
Sangho Shin43cee112014-09-25 16:43:34 -07001552 logStr.append("If the IP matches with ");
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001553 IPv4Net ip = ((Ipv4Match) m).getDestination();
Sangho Shin43cee112014-09-25 16:43:34 -07001554 logStr.append(ip.toString());
1555 logStr.append(" then ");
1556 }
1557 else if (m instanceof MplsMatch) {
1558 logStr.append("If the MPLS label matches with ");
1559 int mplsLabel = ((MplsMatch) m).getMplsLabel();
1560 logStr.append(mplsLabel);
1561 logStr.append(" then ");
1562 }
Sangho Shin15273b62014-10-16 22:22:05 -07001563 else if (m instanceof PacketMatch) {
1564 GroupAction ga = (GroupAction)actions.get(0);
1565 logStr.append("if the policy match is XXX then go to group " +
1566 ga.getGroupId());
1567 log.debug(logStr.toString());
1568 return;
1569 }
Sangho Shin43cee112014-09-25 16:43:34 -07001570
1571 logStr.append(" do { ");
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001572 for (Action action : actions) {
Sangho Shin43cee112014-09-25 16:43:34 -07001573 if (action instanceof CopyTtlInAction) {
1574 logStr.append("copy ttl In, ");
1575 }
1576 else if (action instanceof CopyTtlOutAction) {
1577 logStr.append("copy ttl Out, ");
1578 }
1579 else if (action instanceof DecMplsTtlAction) {
1580 logStr.append("Dec MPLS TTL , ");
1581 }
1582 else if (action instanceof GroupAction) {
1583 logStr.append("Forward packet to < ");
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001584 NeighborSet dpids = ((GroupAction) action).getDpids();
Sangho Shin0df01982014-09-25 17:11:18 -07001585 logStr.append(dpids.toString() + ",");
1586
Sangho Shin43cee112014-09-25 16:43:34 -07001587 }
1588 else if (action instanceof PopMplsAction) {
1589 logStr.append("Pop MPLS label, ");
1590 }
1591 else if (action instanceof PushMplsAction) {
1592 logStr.append("Push MPLS label, ");
1593 }
1594 else if (action instanceof SetMplsIdAction) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001595 int id = ((SetMplsIdAction) action).getMplsId();
Sangho Shin43cee112014-09-25 16:43:34 -07001596 logStr.append("Set MPLS ID as " + id + ", ");
Sangho Shin43cee112014-09-25 16:43:34 -07001597 }
1598 }
1599
1600 log.debug(logStr.toString());
1601
Sangho Shineb083032014-09-22 16:11:34 -07001602 }
1603
1604 /**
1605 * Get MPLS label reading the config file
Sangho Shinfbc572c2014-10-02 16:37:05 -07001606 *
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001607 * @param dipid DPID of the switch
Sangho Shineb083032014-09-22 16:11:34 -07001608 * @return MPLS label for the switch
1609 */
1610
Sangho Shin43cee112014-09-25 16:43:34 -07001611 private String getMplsLabel(String dpid) {
Sangho Shineb083032014-09-22 16:11:34 -07001612
1613 String mplsLabel = null;
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001614 for (Switch sw : mutableTopology.getSwitches()) {
Sangho Shin43cee112014-09-25 16:43:34 -07001615 String dpidStr = sw.getDpid().toString();
1616 if (dpid.equals(dpidStr)) {
Sangho Shineb083032014-09-22 16:11:34 -07001617 mplsLabel = sw.getStringAttribute("nodeSid");
1618 break;
Sangho Shin1aa93542014-09-22 09:49:44 -07001619 }
1620 }
1621
Sangho Shineb083032014-09-22 16:11:34 -07001622 return mplsLabel;
Sangho Shin1aa93542014-09-22 09:49:44 -07001623 }
1624
Sangho Shineb083032014-09-22 16:11:34 -07001625 /**
Sangho Shin1aa93542014-09-22 09:49:44 -07001626 * The function checks if given IP matches to the given subnet mask
Sangho Shinfbc572c2014-10-02 16:37:05 -07001627 *
Sangho Shin1aa93542014-09-22 09:49:44 -07001628 * @param addr - subnet address to match
1629 * @param addr1 - IP address to check
1630 * @return true if the IP address matches to the subnet, otherwise false
1631 */
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001632 public boolean netMatch(String addr, String addr1) { // addr is subnet
1633 // address and addr1 is
1634 // ip address. Function
1635 // will return true, if
1636 // addr1 is within
1637 // addr(subnet)
Sangho Shin1aa93542014-09-22 09:49:44 -07001638
1639 String[] parts = addr.split("/");
1640 String ip = parts[0];
1641 int prefix;
1642
1643 if (parts.length < 2) {
1644 prefix = 0;
1645 } else {
1646 prefix = Integer.parseInt(parts[1]);
1647 }
1648
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001649 Inet4Address a = null;
1650 Inet4Address a1 = null;
Sangho Shin1aa93542014-09-22 09:49:44 -07001651 try {
1652 a = (Inet4Address) InetAddress.getByName(ip);
1653 a1 = (Inet4Address) InetAddress.getByName(addr1);
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001654 } catch (UnknownHostException e) {
1655 }
Sangho Shin1aa93542014-09-22 09:49:44 -07001656
1657 byte[] b = a.getAddress();
1658 int ipInt = ((b[0] & 0xFF) << 24) |
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001659 ((b[1] & 0xFF) << 16) |
1660 ((b[2] & 0xFF) << 8) |
1661 ((b[3] & 0xFF) << 0);
Sangho Shin1aa93542014-09-22 09:49:44 -07001662
1663 byte[] b1 = a1.getAddress();
1664 int ipInt1 = ((b1[0] & 0xFF) << 24) |
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001665 ((b1[1] & 0xFF) << 16) |
1666 ((b1[2] & 0xFF) << 8) |
1667 ((b1[3] & 0xFF) << 0);
Sangho Shin1aa93542014-09-22 09:49:44 -07001668
1669 int mask = ~((1 << (32 - prefix)) - 1);
1670
1671 if ((ipInt & mask) == (ipInt1 & mask)) {
1672 return true;
1673 }
1674 else {
1675 return false;
1676 }
1677 }
Sangho Shineb083032014-09-22 16:11:34 -07001678
Sangho Shinac5ee2b2014-09-28 21:27:20 -07001679 /**
1680 * Add a routing rule for the host
Sangho Shinfbc572c2014-10-02 16:37:05 -07001681 *
Sangho Shinac5ee2b2014-09-28 21:27:20 -07001682 * @param sw - Switch to add the rule
1683 * @param hostIpAddress Destination host IP address
1684 * @param hostMacAddress Destination host MAC address
1685 */
Sangho Shineb083032014-09-22 16:11:34 -07001686 public void addRouteToHost(Switch sw, int hostIpAddress, byte[] hostMacAddress) {
1687 ipHandler.addRouteToHost(sw, hostIpAddress, hostMacAddress);
1688
1689 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -07001690
Sangho Shin463bee52014-09-29 15:14:43 -07001691 /**
1692 * Add IP packet to a buffer queue
Sangho Shinfbc572c2014-10-02 16:37:05 -07001693 *
Sangho Shin463bee52014-09-29 15:14:43 -07001694 * @param ipv4
1695 */
1696 public void addPacket(IPv4 ipv4) {
Sangho Shin61535402014-10-01 11:37:14 -07001697 ipPacketQueue.add(ipv4);
Sangho Shin463bee52014-09-29 15:14:43 -07001698 }
1699
1700 /**
1701 * Retrieve all packets whose destination is the given address.
Sangho Shinfbc572c2014-10-02 16:37:05 -07001702 *
Sangho Shin463bee52014-09-29 15:14:43 -07001703 * @param destIp Destination address of packets to retrieve
1704 */
1705 public List<IPv4> getIpPacketFromQueue(byte[] destIp) {
1706
1707 List<IPv4> bufferedPackets = new ArrayList<IPv4>();
1708
Sangho Shin61535402014-10-01 11:37:14 -07001709 if (!ipPacketQueue.isEmpty()) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001710 for (IPv4 ip : ipPacketQueue) {
Sangho Shin61535402014-10-01 11:37:14 -07001711 int dest = ip.getDestinationAddress();
1712 IPv4Address ip1 = IPv4Address.of(dest);
1713 IPv4Address ip2 = IPv4Address.of(destIp);
1714 if (ip1.equals(ip2)) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001715 bufferedPackets.add((IPv4) (ipPacketQueue.poll()).clone());
Sangho Shin463bee52014-09-29 15:14:43 -07001716 }
1717 }
1718 }
1719
1720 return bufferedPackets;
1721 }
1722
Sangho Shin15273b62014-10-16 22:22:05 -07001723
1724
Sangho Shin2f263692014-09-15 14:09:41 -07001725}