blob: dbd3b7eaa06b56040d999de9814f565a83eb847b [file] [log] [blame]
Sangho Shin2f263692014-09-15 14:09:41 -07001package net.onrc.onos.apps.segmentrouting;
2
Sangho Shin9c0f4c32014-09-26 16:02:38 -07003import java.io.IOException;
Sangho Shin1aa93542014-09-22 09:49:44 -07004import java.net.Inet4Address;
5import java.net.InetAddress;
6import java.net.UnknownHostException;
Sangho Shin2f263692014-09-15 14:09:41 -07007import java.util.ArrayList;
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07008import java.util.Arrays;
Sangho Shin2f263692014-09-15 14:09:41 -07009import java.util.Collection;
Srikanth Vavilapalli363f1dc2014-09-22 14:30:23 -070010import java.util.HashMap;
Sangho Shin5be3e532014-10-03 17:20:58 -070011import java.util.HashSet;
Sangho Shin2f263692014-09-15 14:09:41 -070012import java.util.Iterator;
13import java.util.List;
14import java.util.Map;
Sangho Shin5be3e532014-10-03 17:20:58 -070015import java.util.Set;
Sangho Shin61535402014-10-01 11:37:14 -070016import java.util.concurrent.ConcurrentLinkedQueue;
Sangho Shin11d4e0f2014-09-30 12:00:33 -070017import java.util.concurrent.ExecutionException;
Sangho Shin43cee112014-09-25 16:43:34 -070018import java.util.concurrent.ScheduledExecutorService;
19import java.util.concurrent.TimeUnit;
Sangho Shin11d4e0f2014-09-30 12:00:33 -070020import java.util.concurrent.TimeoutException;
Sangho Shin2f263692014-09-15 14:09:41 -070021
22import net.floodlightcontroller.core.IFloodlightProviderService;
Sangho Shin9c0f4c32014-09-26 16:02:38 -070023import net.floodlightcontroller.core.IOF13Switch;
Sangho Shin0df01982014-09-25 17:11:18 -070024import net.floodlightcontroller.core.IOF13Switch.NeighborSet;
Sangho Shin11d4e0f2014-09-30 12:00:33 -070025import net.floodlightcontroller.core.internal.OFBarrierReplyFuture;
Sangho Shin2f263692014-09-15 14:09:41 -070026import net.floodlightcontroller.core.module.FloodlightModuleContext;
27import net.floodlightcontroller.core.module.FloodlightModuleException;
28import net.floodlightcontroller.core.module.IFloodlightModule;
29import net.floodlightcontroller.core.module.IFloodlightService;
Sangho Shin43cee112014-09-25 16:43:34 -070030import net.floodlightcontroller.core.util.SingletonTask;
Sangho Shin7330c032014-10-20 10:34:51 -070031import net.floodlightcontroller.restserver.IRestApiService;
Sangho Shin43cee112014-09-25 16:43:34 -070032import net.floodlightcontroller.threadpool.IThreadPoolService;
Sangho Shin15273b62014-10-16 22:22:05 -070033import net.floodlightcontroller.util.MACAddress;
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070034import net.onrc.onos.api.packet.IPacketListener;
Sangho Shin2f263692014-09-15 14:09:41 -070035import net.onrc.onos.api.packet.IPacketService;
Fahad Naeem Khan4444b952014-10-18 22:30:50 -070036import net.onrc.onos.apps.segmentrouting.web.SegmentRoutingWebRoutable;
Srikanth Vavilapalli8a661e72014-10-27 15:40:22 -070037import net.onrc.onos.core.drivermanager.OFSwitchImplDellOSR;
Sangho Shin2f263692014-09-15 14:09:41 -070038import net.onrc.onos.core.flowprogrammer.IFlowPusherService;
Sangho Shinfbc572c2014-10-02 16:37:05 -070039import net.onrc.onos.core.intent.Path;
Sangho Shin2f263692014-09-15 14:09:41 -070040import net.onrc.onos.core.main.config.IConfigInfoService;
Sangho Shin43cee112014-09-25 16:43:34 -070041import net.onrc.onos.core.matchaction.MatchAction;
42import net.onrc.onos.core.matchaction.MatchActionId;
43import net.onrc.onos.core.matchaction.MatchActionOperationEntry;
Sangho Shin5be3e532014-10-03 17:20:58 -070044import net.onrc.onos.core.matchaction.MatchActionOperations.Operator;
Sangho Shin43cee112014-09-25 16:43:34 -070045import net.onrc.onos.core.matchaction.action.Action;
46import net.onrc.onos.core.matchaction.action.CopyTtlInAction;
47import net.onrc.onos.core.matchaction.action.CopyTtlOutAction;
48import net.onrc.onos.core.matchaction.action.DecMplsTtlAction;
49import net.onrc.onos.core.matchaction.action.DecNwTtlAction;
50import net.onrc.onos.core.matchaction.action.GroupAction;
Sangho Shin6d3c2f02014-10-22 10:10:55 -070051import net.onrc.onos.core.matchaction.action.ModifyDstMacAction;
52import net.onrc.onos.core.matchaction.action.ModifySrcMacAction;
53import net.onrc.onos.core.matchaction.action.OutputAction;
Sangho Shin43cee112014-09-25 16:43:34 -070054import net.onrc.onos.core.matchaction.action.PopMplsAction;
55import net.onrc.onos.core.matchaction.action.PushMplsAction;
Sangho Shine842cad2014-10-24 16:07:35 -070056import net.onrc.onos.core.matchaction.action.SetDAAction;
Sangho Shin43cee112014-09-25 16:43:34 -070057import net.onrc.onos.core.matchaction.action.SetMplsIdAction;
Sangho Shine842cad2014-10-24 16:07:35 -070058import net.onrc.onos.core.matchaction.action.SetSAAction;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -070059import net.onrc.onos.core.matchaction.match.Ipv4Match;
Sangho Shin43cee112014-09-25 16:43:34 -070060import net.onrc.onos.core.matchaction.match.Match;
61import net.onrc.onos.core.matchaction.match.MplsMatch;
Sangho Shin15273b62014-10-16 22:22:05 -070062import net.onrc.onos.core.matchaction.match.PacketMatch;
63import net.onrc.onos.core.matchaction.match.PacketMatchBuilder;
Sangho Shin2f263692014-09-15 14:09:41 -070064import net.onrc.onos.core.packet.ARP;
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070065import net.onrc.onos.core.packet.Ethernet;
66import net.onrc.onos.core.packet.IPv4;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070067import net.onrc.onos.core.topology.ITopologyListener;
Sangho Shin1aa93542014-09-22 09:49:44 -070068import net.onrc.onos.core.topology.ITopologyService;
Sangho Shinbce900e2014-10-07 17:13:23 -070069import net.onrc.onos.core.topology.Link;
Sangho Shinc8d2f592014-09-30 16:53:57 -070070import net.onrc.onos.core.topology.LinkData;
Sangho Shinbce900e2014-10-07 17:13:23 -070071import net.onrc.onos.core.topology.MastershipData;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070072import net.onrc.onos.core.topology.MutableTopology;
Sangho Shineb083032014-09-22 16:11:34 -070073import net.onrc.onos.core.topology.Port;
Sangho Shinc8d2f592014-09-30 16:53:57 -070074import net.onrc.onos.core.topology.PortData;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070075import net.onrc.onos.core.topology.Switch;
Sangho Shin5be3e532014-10-03 17:20:58 -070076import net.onrc.onos.core.topology.SwitchData;
Sangho Shin1aa93542014-09-22 09:49:44 -070077import net.onrc.onos.core.topology.TopologyEvents;
Srikanth Vavilapalli363f1dc2014-09-22 14:30:23 -070078import net.onrc.onos.core.util.Dpid;
Sangho Shin43cee112014-09-25 16:43:34 -070079import net.onrc.onos.core.util.IPv4Net;
Sangho Shin6d3c2f02014-10-22 10:10:55 -070080import net.onrc.onos.core.util.PortNumber;
Sangho Shin43cee112014-09-25 16:43:34 -070081import net.onrc.onos.core.util.SwitchPort;
Sangho Shin2f263692014-09-15 14:09:41 -070082
Sangho Shin43cee112014-09-25 16:43:34 -070083import org.json.JSONArray;
84import org.json.JSONException;
Saurav Dasa962a692014-10-17 14:52:38 -070085import org.projectfloodlight.openflow.protocol.OFBarrierReply;
Saurav Dasbc594a42014-09-25 20:13:50 -070086import org.projectfloodlight.openflow.types.EthType;
Sangho Shin2f263692014-09-15 14:09:41 -070087import org.projectfloodlight.openflow.types.IPv4Address;
Sangho Shine842cad2014-10-24 16:07:35 -070088import org.projectfloodlight.openflow.types.MacAddress;
Sangho Shin2f263692014-09-15 14:09:41 -070089import org.slf4j.Logger;
90import org.slf4j.LoggerFactory;
91
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070092public class SegmentRoutingManager implements IFloodlightModule,
Srikanth Vavilapalli8c49db72014-10-20 13:35:08 -070093 ITopologyListener, IPacketListener, ISegmentRoutingService {
Sangho Shin2f263692014-09-15 14:09:41 -070094
95 private static final Logger log = LoggerFactory
96 .getLogger(SegmentRoutingManager.class);
Sangho Shin23f898d2014-10-13 16:54:00 -070097
Fahad Naeem Khan5b558f22014-10-16 10:35:20 -070098 private ITopologyService topologyService;
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070099 private IPacketService packetService;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700100 private MutableTopology mutableTopology;
Sangho Shin61535402014-10-01 11:37:14 -0700101 private ConcurrentLinkedQueue<IPv4> ipPacketQueue;
Fahad Naeem Khan4444b952014-10-18 22:30:50 -0700102 private IRestApiService restApi;
Sangho Shin2f263692014-09-15 14:09:41 -0700103 private List<ArpEntry> arpEntries;
Sangho Shineb083032014-09-22 16:11:34 -0700104 private ArpHandler arpHandler;
105 private GenericIpHandler ipHandler;
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700106 private IcmpHandler icmpHandler;
Sangho Shin43cee112014-09-25 16:43:34 -0700107 private IThreadPoolService threadPool;
108 private SingletonTask discoveryTask;
Sangho Shin23f898d2014-10-13 16:54:00 -0700109 private SingletonTask linkAddTask;
Sangho Shin15273b62014-10-16 22:22:05 -0700110 private SingletonTask testTask;
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700111 private IFloodlightProviderService floodlightProvider;
Sangho Shin2f263692014-09-15 14:09:41 -0700112
Sangho Shinfbc572c2014-10-02 16:37:05 -0700113 private HashMap<Switch, ECMPShortestPathGraph> graphs;
Sangho Shin23f898d2014-10-13 16:54:00 -0700114 private HashMap<String, LinkData> linksDown;
115 private HashMap<String, LinkData> linksToAdd;
Sangho Shin5be3e532014-10-03 17:20:58 -0700116 private ConcurrentLinkedQueue<TopologyEvents> topologyEventQueue;
Sangho Shine020cc32014-10-20 13:28:02 -0700117 private HashMap<String, PolicyInfo> policyTable;
Sangho Shin81655442014-10-20 14:22:46 -0700118 private HashMap<String, TunnelInfo> tunnelTable;
Sangho Shin6471d202014-10-23 10:59:36 -0700119 private HashMap<Integer, HashMap<Integer, List<Integer>>> adjacencySidTable;
Sangho Shin5b8f5452014-10-20 11:46:01 -0700120
Sangho Shine842cad2014-10-24 16:07:35 -0700121 // Flag whether transit router supports ECMP or not
Srikanth Vavilapalli8a661e72014-10-27 15:40:22 -0700122 // private boolean supportTransitECMP = true;
Sangho Shin5b8f5452014-10-20 11:46:01 -0700123
Sangho Shine842cad2014-10-24 16:07:35 -0700124 private int testMode = 0;
Sangho Shinbce900e2014-10-07 17:13:23 -0700125
126 private int numOfEvents = 0;
127 private int numOfEventProcess = 0;
128 private int numOfPopulation = 0;
Sangho Shin99918bd2014-10-08 15:52:35 -0700129 private long matchActionId = 0L;
Sangho Shin58182672014-10-21 13:23:38 -0700130
Sangho Shin23f898d2014-10-13 16:54:00 -0700131 private final int DELAY_TO_ADD_LINK = 10;
Sangho Shin15273b62014-10-16 22:22:05 -0700132 private final int MAX_NUM_LABELS = 3;
Sangho Shinfbc572c2014-10-02 16:37:05 -0700133
Sangho Shin5b8f5452014-10-20 11:46:01 -0700134 private final int POLICY_ADD1 = 1;
135 private final int POLICY_ADD2 = 2;
136 private final int POLICY_REMOVE1 = 3;
137 private final int POLICY_REMOVE2 = 4;
Sangho Shin4b46bcd2014-10-20 15:48:47 -0700138 private final int TUNNEL_REMOVE1 = 5;
139 private final int TUNNEL_REMOVE2 = 6;
Sangho Shin5b8f5452014-10-20 11:46:01 -0700140
141
Sangho Shin7330c032014-10-20 10:34:51 -0700142 // ************************************
143 // IFloodlightModule implementation
144 // ************************************
145
Sangho Shin2f263692014-09-15 14:09:41 -0700146 @Override
147 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Srikanth Vavilapalli8c49db72014-10-20 13:35:08 -0700148 Collection<Class<? extends IFloodlightService>> l = new ArrayList<>();
149 l.add(ISegmentRoutingService.class);
150 return l;
Sangho Shin2f263692014-09-15 14:09:41 -0700151 }
152
153 @Override
154 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Srikanth Vavilapalli8c49db72014-10-20 13:35:08 -0700155 Map<Class<? extends IFloodlightService>, IFloodlightService> m = new HashMap<>();
156 m.put(ISegmentRoutingService.class, this);
157 return m;
Sangho Shin2f263692014-09-15 14:09:41 -0700158 }
159
160 @Override
161 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
162 Collection<Class<? extends IFloodlightService>> l = new ArrayList<Class<? extends IFloodlightService>>();
163
164 l.add(IFloodlightProviderService.class);
165 l.add(IConfigInfoService.class);
166 l.add(ITopologyService.class);
167 l.add(IPacketService.class);
168 l.add(IFlowPusherService.class);
169 l.add(ITopologyService.class);
Fahad Naeem Khan4444b952014-10-18 22:30:50 -0700170 l.add(IRestApiService.class);
Sangho Shin2f263692014-09-15 14:09:41 -0700171
172 return l;
173
174 }
175
176 @Override
177 public void init(FloodlightModuleContext context) throws FloodlightModuleException {
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700178 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Sangho Shineb083032014-09-22 16:11:34 -0700179 arpHandler = new ArpHandler(context, this);
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700180 icmpHandler = new IcmpHandler(context, this);
Sangho Shineb083032014-09-22 16:11:34 -0700181 ipHandler = new GenericIpHandler(context, this);
Sangho Shin2f263692014-09-15 14:09:41 -0700182 arpEntries = new ArrayList<ArpEntry>();
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700183 topologyService = context.getServiceImpl(ITopologyService.class);
Sangho Shin43cee112014-09-25 16:43:34 -0700184 threadPool = context.getServiceImpl(IThreadPoolService.class);
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700185 mutableTopology = topologyService.getTopology();
Sangho Shin61535402014-10-01 11:37:14 -0700186 ipPacketQueue = new ConcurrentLinkedQueue<IPv4>();
Sangho Shinfbc572c2014-10-02 16:37:05 -0700187 graphs = new HashMap<Switch, ECMPShortestPathGraph>();
Sangho Shin23f898d2014-10-13 16:54:00 -0700188 linksDown = new HashMap<String, LinkData>();
189 linksToAdd = new HashMap<String, LinkData>();
Sangho Shin5be3e532014-10-03 17:20:58 -0700190 topologyEventQueue = new ConcurrentLinkedQueue<TopologyEvents>();
Sangho Shin15273b62014-10-16 22:22:05 -0700191 packetService = context.getServiceImpl(IPacketService.class);
Fahad Naeem Khan4444b952014-10-18 22:30:50 -0700192 restApi = context.getServiceImpl(IRestApiService.class);
Sangho Shine020cc32014-10-20 13:28:02 -0700193 policyTable = new HashMap<String, PolicyInfo>();
Sangho Shin81655442014-10-20 14:22:46 -0700194 tunnelTable = new HashMap<String, TunnelInfo>();
Sangho Shin6471d202014-10-23 10:59:36 -0700195 adjacencySidTable = new HashMap<Integer,HashMap<Integer, List<Integer>>>();
Sangho Shin2f263692014-09-15 14:09:41 -0700196
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700197 packetService.registerPacketListener(this);
Sangho Shin15273b62014-10-16 22:22:05 -0700198 topologyService.addListener(this, false);
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700199
Sangho Shin99918bd2014-10-08 15:52:35 -0700200
Sangho Shin2f263692014-09-15 14:09:41 -0700201 }
202
203 @Override
204 public void startUp(FloodlightModuleContext context) throws FloodlightModuleException {
Sangho Shinc8d2f592014-09-30 16:53:57 -0700205 ScheduledExecutorService ses = threadPool.getScheduledExecutor();
Fahad Naeem Khan4444b952014-10-18 22:30:50 -0700206 restApi.addRestletRoutable(new SegmentRoutingWebRoutable());
Sangho Shin2f263692014-09-15 14:09:41 -0700207
Sangho Shinc8d2f592014-09-30 16:53:57 -0700208 discoveryTask = new SingletonTask(ses, new Runnable() {
209 @Override
210 public void run() {
Sangho Shin5be3e532014-10-03 17:20:58 -0700211 handleTopologyChangeEvents();
Sangho Shinc8d2f592014-09-30 16:53:57 -0700212 }
213 });
Sangho Shin23f898d2014-10-13 16:54:00 -0700214
215 linkAddTask = new SingletonTask(ses, new Runnable() {
216 @Override
217 public void run() {
218 delayedAddLink();
219 }
220 });
221
Sangho Shin15273b62014-10-16 22:22:05 -0700222 testTask = new SingletonTask(ses, new Runnable() {
223 @Override
224 public void run() {
225 runTest();
226 }
227 });
228
Sangho Shin5b8f5452014-10-20 11:46:01 -0700229 testMode = POLICY_ADD1;
Sangho Shin69229fb2014-10-27 16:17:04 -0700230 //testTask.reschedule(20, TimeUnit.SECONDS);
Sangho Shin2f263692014-09-15 14:09:41 -0700231 }
232
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700233 @Override
234 public void receive(Switch sw, Port inPort, Ethernet payload) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700235 if (payload.getEtherType() == Ethernet.TYPE_ARP)
236 arpHandler.processPacketIn(sw, inPort, payload);
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700237 if (payload.getEtherType() == Ethernet.TYPE_IPV4) {
Sangho Shin7330c032014-10-20 10:34:51 -0700238 addPacketToPacketBuffer((IPv4) payload.getPayload());
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700239 if (((IPv4) payload.getPayload()).getProtocol() == IPv4.PROTOCOL_ICMP)
240 icmpHandler.processPacketIn(sw, inPort, payload);
241 else
242 ipHandler.processPacketIn(sw, inPort, payload);
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700243 }
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700244 else {
245 log.debug("{}", payload.toString());
246 }
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700247 }
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700248
Sangho Shin2f263692014-09-15 14:09:41 -0700249
Sangho Shin7330c032014-10-20 10:34:51 -0700250 // ************************************
251 // Topology event handlers
252 // ************************************
Sangho Shineb083032014-09-22 16:11:34 -0700253
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700254 /**
255 * Topology events that have been generated.
Sangho Shinfbc572c2014-10-02 16:37:05 -0700256 *
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700257 * @param topologyEvents the generated Topology Events
258 * @see TopologyEvents
259 */
260 public void topologyEvents(TopologyEvents topologyEvents)
261 {
Sangho Shin5be3e532014-10-03 17:20:58 -0700262 topologyEventQueue.add(topologyEvents);
Sangho Shinbce900e2014-10-07 17:13:23 -0700263 discoveryTask.reschedule(100, TimeUnit.MILLISECONDS);
Sangho Shin5be3e532014-10-03 17:20:58 -0700264 }
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700265
Sangho Shin23f898d2014-10-13 16:54:00 -0700266 /**
267 * Process the multiple topology events with some delay (100MS at most for now)
268 *
269 */
Sangho Shin5be3e532014-10-03 17:20:58 -0700270 private void handleTopologyChangeEvents() {
Sangho Shinbce900e2014-10-07 17:13:23 -0700271 numOfEventProcess ++;
272
Sangho Shin51625342014-10-17 09:30:48 -0700273 Collection<LinkData> linkEntriesAddedAll = new ArrayList<LinkData>();
274 Collection<PortData> portEntriesAddedAll = new ArrayList<PortData>();
275 Collection<PortData> portEntriesRemovedAll = new ArrayList<PortData>();
276 Collection<LinkData> linkEntriesRemovedAll = new ArrayList<LinkData>();
277 Collection<SwitchData> switchAddedAll = new ArrayList<SwitchData>();
278 Collection<SwitchData> switchRemovedAll = new ArrayList<SwitchData>();
279 Collection<MastershipData> mastershipRemovedAll = new ArrayList<MastershipData>();
Sangho Shinbce900e2014-10-07 17:13:23 -0700280
Sangho Shin5be3e532014-10-03 17:20:58 -0700281 while (!topologyEventQueue.isEmpty()) {
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700282 // We should handle the events in the order of when they happen
283 // TODO: We need to simulate the final results of multiple events
284 // and shoot only the final state.
285 // Ex: link s1-s2 down, link s1-s2 up --> Do nothing
286 // Ex: ink s1-s2 up, s1-p1,p2 down --> link s1-s2 down
Sangho Shin51625342014-10-17 09:30:48 -0700287
Sangho Shin5be3e532014-10-03 17:20:58 -0700288 TopologyEvents topologyEvents = topologyEventQueue.poll();
Sangho Shin51625342014-10-17 09:30:48 -0700289
290 Collection<LinkData> linkEntriesAdded = topologyEvents.getAddedLinkDataEntries();
291 Collection<PortData> portEntriesAdded = topologyEvents.getAddedPortDataEntries();
292 Collection<PortData> portEntriesRemoved = topologyEvents.getRemovedPortDataEntries();
293 Collection<LinkData> linkEntriesRemoved = topologyEvents.getRemovedLinkDataEntries();
294 Collection<SwitchData> switchAdded = topologyEvents.getAddedSwitchDataEntries();
295 Collection<SwitchData> switchRemoved = topologyEvents.getRemovedSwitchDataEntries();
296 Collection<MastershipData> mastershipRemoved = topologyEvents.getRemovedMastershipDataEntries();
297
298 linkEntriesAddedAll.addAll(linkEntriesAdded);
299 portEntriesAddedAll.addAll(portEntriesAdded);
300 portEntriesRemovedAll.addAll(portEntriesRemoved);
301 linkEntriesRemovedAll.addAll(linkEntriesRemoved);
302 switchAddedAll.addAll(switchAdded);
303 switchRemovedAll.addAll(switchRemoved);
304 mastershipRemovedAll.addAll(mastershipRemoved);
Sangho Shinbce900e2014-10-07 17:13:23 -0700305 numOfEvents++;
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700306
307 if (!portEntriesRemoved.isEmpty()) {
308 processPortRemoval(portEntriesRemoved);
309 }
310
311 if (!linkEntriesRemoved.isEmpty()) {
312 processLinkRemoval(linkEntriesRemoved);
313 }
314
315 if (!switchRemoved.isEmpty()) {
316 processSwitchRemoved(switchRemoved);
317 }
318
319 if (!mastershipRemoved.isEmpty()) {
Sangho Shin23f898d2014-10-13 16:54:00 -0700320 log.debug("Mastership is removed. Check if ports are down also.");
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700321 }
322
323 if (!linkEntriesAdded.isEmpty()) {
Sangho Shin23f898d2014-10-13 16:54:00 -0700324 processLinkAdd(linkEntriesAdded, false);
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700325 }
326
327 if (!portEntriesAdded.isEmpty()) {
328 processPortAdd(portEntriesAdded);
329 }
330
331 if (!switchAdded.isEmpty()) {
332 processSwitchAdd(switchAdded);
333 }
Sangho Shin51625342014-10-17 09:30:48 -0700334
Sangho Shinbce900e2014-10-07 17:13:23 -0700335 }
336
Sangho Shin23f898d2014-10-13 16:54:00 -0700337 // TODO: 100ms is enough to check both mastership removed events
338 // and the port removed events? What if the PORT_STATUS packets comes late?
Sangho Shin51625342014-10-17 09:30:48 -0700339 if (!mastershipRemovedAll.isEmpty()) {
340 if (portEntriesRemovedAll.isEmpty()) {
Saurav Das82e62972014-10-16 14:53:57 -0700341 log.debug("Just mastership is removed. Do not do anthing.");
Sangho Shin23f898d2014-10-13 16:54:00 -0700342 }
343 else {
344 HashMap<String, MastershipData> mastershipToRemove =
345 new HashMap<String, MastershipData>();
Sangho Shin51625342014-10-17 09:30:48 -0700346 for (MastershipData ms: mastershipRemovedAll) {
347 for (PortData port: portEntriesRemovedAll) {
Sangho Shin23f898d2014-10-13 16:54:00 -0700348 // TODO: check ALL ports of the switch are dead ..
349 if (port.getDpid().equals(ms.getDpid())) {
350 mastershipToRemove.put(ms.getDpid().toString(), ms);
351 }
352 }
353 log.debug("Swtich {} is really down.", ms.getDpid());
354 }
355 processMastershipRemoved(mastershipToRemove.values());
356 }
357 }
358
Sangho Shinbce900e2014-10-07 17:13:23 -0700359 log.debug("num events {}, num of process {}, "
360 + "num of Population {}", numOfEvents, numOfEventProcess,
361 numOfPopulation);
362 }
363
364 /**
Sangho Shin99918bd2014-10-08 15:52:35 -0700365 * Process the SwitchAdded events from topologyMananger.
366 * It does nothing. When a switch is added, then link will be added too.
367 * LinkAdded event will handle process all re-computation.
368 *
369 * @param switchAdded
370 */
371 private void processSwitchAdd(Collection<SwitchData> switchAdded) {
372
373 }
374
375 /**
Sangho Shinbce900e2014-10-07 17:13:23 -0700376 * Remove all ports connected to the switch removed
377 *
378 * @param mastershipRemoved master switch info removed
379 */
380 private void processMastershipRemoved(Collection<MastershipData>
381 mastershipRemoved) {
382 for (MastershipData mastership: mastershipRemoved) {
383 Switch sw = mutableTopology.getSwitch(mastership.getDpid());
384 for (Link link: sw.getOutgoingLinks()) {
385 Port dstPort = link.getDstPort();
386 IOF13Switch dstSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
387 getSwId(dstPort.getDpid().toString()));
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700388 if (dstSw != null) {
389 dstSw.removePortFromGroups(dstPort.getNumber());
390 log.debug("MasterSwitch {} is gone: remove port {}", sw.getDpid(), dstPort);
391 }
Sangho Shinbce900e2014-10-07 17:13:23 -0700392 }
Sangho Shin61535402014-10-01 11:37:14 -0700393 }
Sangho Shin23f898d2014-10-13 16:54:00 -0700394
395 linksToAdd.clear();
396 linksDown.clear();
Sangho Shin61535402014-10-01 11:37:14 -0700397 }
Sangho Shinc8d2f592014-09-30 16:53:57 -0700398
Sangho Shinbce900e2014-10-07 17:13:23 -0700399 /**
400 * Remove all ports connected to the switch removed
401 *
402 * @param switchRemoved Switch removed
403 */
Sangho Shin5be3e532014-10-03 17:20:58 -0700404 private void processSwitchRemoved(Collection<SwitchData> switchRemoved) {
Sangho Shin23f898d2014-10-13 16:54:00 -0700405 log.debug("SwitchRemoved event occurred !!!");
Sangho Shin5be3e532014-10-03 17:20:58 -0700406 }
407
Sangho Shin61535402014-10-01 11:37:14 -0700408 /**
Sangho Shin99918bd2014-10-08 15:52:35 -0700409 * Report ports added to driver
Sangho Shinfbc572c2014-10-02 16:37:05 -0700410 *
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700411 * @param portEntries
412 */
413 private void processPortAdd(Collection<PortData> portEntries) {
Sangho Shin99918bd2014-10-08 15:52:35 -0700414 // TODO: do we need to add ports with delay?
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700415 for (PortData port : portEntries) {
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700416 Dpid dpid = port.getDpid();
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700417
Sangho Shinfbc572c2014-10-02 16:37:05 -0700418 IOF13Switch sw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700419 getSwId(port.getDpid().toString()));
Sangho Shin815af0c2014-10-10 13:05:45 -0700420 if (sw != null) {
Sangho Shin721ca042014-10-09 13:03:40 -0700421 sw.addPortToGroups(port.getPortNumber());
Sangho Shin15273b62014-10-16 22:22:05 -0700422 //log.debug("Add port {} to switch {}", port, dpid);
Sangho Shin815af0c2014-10-10 13:05:45 -0700423 }
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700424 }
425 }
426
427 /**
428 * Reports ports of new links to driver and recalculate ECMP SPG
Sangho Shin23f898d2014-10-13 16:54:00 -0700429 * If the link to add was removed before, then we just schedule the add link
430 * event and do not recompute the path now.
Sangho Shinfbc572c2014-10-02 16:37:05 -0700431 *
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700432 * @param linkEntries
433 */
Sangho Shin23f898d2014-10-13 16:54:00 -0700434 private void processLinkAdd(Collection<LinkData> linkEntries, boolean delayed) {
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700435
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700436 for (LinkData link : linkEntries) {
Sangho Shin5be3e532014-10-03 17:20:58 -0700437
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700438 SwitchPort srcPort = link.getSrc();
439 SwitchPort dstPort = link.getDst();
440
Sangho Shin23f898d2014-10-13 16:54:00 -0700441 String key = srcPort.getDpid().toString() +
442 dstPort.getDpid().toString();
443 if (!delayed) {
444 if (linksDown.containsKey(key)) {
445 linksToAdd.put(key, link);
446 linksDown.remove(key);
447 linkAddTask.reschedule(DELAY_TO_ADD_LINK, TimeUnit.SECONDS);
448 log.debug("Add link {} with 5 sec delay", link);
449 // TODO: What if we have multiple events of add link:
450 // one is new link add, the other one is link up for
451 // broken link? ECMPSPG function cannot deal with it for now
452 return;
453 }
454 }
455 else {
456 if (linksDown.containsKey(key)) {
457 linksToAdd.remove(key);
458 log.debug("Do not add the link {}: it is down again!", link);
459 return;
460 }
461 }
462
Sangho Shinfbc572c2014-10-02 16:37:05 -0700463 IOF13Switch srcSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700464 getSwId(srcPort.getDpid().toString()));
Sangho Shinfbc572c2014-10-02 16:37:05 -0700465 IOF13Switch dstSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700466 getSwId(dstPort.getDpid().toString()));
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700467
Sangho Shin815af0c2014-10-10 13:05:45 -0700468 if ((srcSw == null) || (dstSw == null))
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700469 continue;
470
471 srcSw.addPortToGroups(srcPort.getPortNumber());
472 dstSw.addPortToGroups(dstPort.getPortNumber());
Sangho Shin5be3e532014-10-03 17:20:58 -0700473
Sangho Shin15273b62014-10-16 22:22:05 -0700474 //log.debug("Add a link port {} to switch {} to add link {}", srcPort, srcSw,
475 // link);
476 //log.debug("Add a link port {} to switch {} to add link {}", dstPort, dstSw,
477 // link);
Sangho Shin815af0c2014-10-10 13:05:45 -0700478
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700479 }
Sangho Shinbce900e2014-10-07 17:13:23 -0700480 populateEcmpRoutingRules(false);
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700481 }
482
483 /**
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700484 * Check if all links are gone b/w the two switches. If all links are gone,
485 * then we need to recalculate the path. Otherwise, just report link failure
Sangho Shin370e17b2014-10-27 11:39:08 -0700486 * to the driver. IF the switches do not support ECMP in transit routers and
487 * the link removed is between transit routers, then just recompute the path
488 * regardless of ECMP.
Sangho Shinfbc572c2014-10-02 16:37:05 -0700489 *
Sangho Shin61535402014-10-01 11:37:14 -0700490 * @param linkEntries
491 */
492 private void processLinkRemoval(Collection<LinkData> linkEntries) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700493 for (LinkData link : linkEntries) {
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700494 SwitchPort srcPort = link.getSrc();
495 SwitchPort dstPort = link.getDst();
Sangho Shinc8d2f592014-09-30 16:53:57 -0700496
Sangho Shinfbc572c2014-10-02 16:37:05 -0700497 IOF13Switch srcSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700498 getSwId(srcPort.getDpid().toString()));
Sangho Shinfbc572c2014-10-02 16:37:05 -0700499 IOF13Switch dstSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700500 getSwId(dstPort.getDpid().toString()));
Sangho Shin815af0c2014-10-10 13:05:45 -0700501 if ((srcSw == null) || (dstSw == null))
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700502 /* If this link is not between two switches, ignore it */
503 continue;
Sangho Shin23f898d2014-10-13 16:54:00 -0700504
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700505 srcSw.removePortFromGroups(srcPort.getPortNumber());
506 dstSw.removePortFromGroups(dstPort.getPortNumber());
Sangho Shin815af0c2014-10-10 13:05:45 -0700507 log.debug("Remove port {} from switch {}", srcPort, srcSw);
508 log.debug("Remove port {} from switch {}", dstPort, dstSw);
509
Sangho Shinf66aa262014-10-27 16:03:42 -0700510 if ((srcSw instanceof OFSwitchImplDellOSR &&
511 dstSw instanceof OFSwitchImplDellOSR) &&
Sangho Shin370e17b2014-10-27 11:39:08 -0700512 isTransitRouter(mutableTopology.getSwitch(srcPort.getDpid())) &&
513 isTransitRouter(mutableTopology.getSwitch(dstPort.getDpid()))) {
514 populateEcmpRoutingRules(false);
515 }
516 else {
517 Switch srcSwitch = mutableTopology.getSwitch(srcPort.getDpid());
518 if (srcSwitch.getLinkToNeighbor(dstPort.getDpid()) == null) {
519 log.debug("All links are gone b/w {} and {}", srcPort.getDpid(),
520 dstPort.getDpid());
521 log.debug("All paths will recomputed regardless of the rest "
522 + "of the event");
523 populateEcmpRoutingRules(false);
524 }
Sangho Shinc8d2f592014-09-30 16:53:57 -0700525 }
Sangho Shin23f898d2014-10-13 16:54:00 -0700526
527 String key = link.getSrc().getDpid().toString()+
528 link.getDst().getDpid().toString();
529 if (!linksDown.containsKey(key)) {
530 linksDown.put(key, link);
531 }
Sangho Shinc8d2f592014-09-30 16:53:57 -0700532 }
Sangho Shinbce900e2014-10-07 17:13:23 -0700533
Sangho Shin61535402014-10-01 11:37:14 -0700534 }
Sangho Shinc8d2f592014-09-30 16:53:57 -0700535
Sangho Shin61535402014-10-01 11:37:14 -0700536 /**
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700537 * report ports removed to the driver immediately
Sangho Shinfbc572c2014-10-02 16:37:05 -0700538 *
Sangho Shin61535402014-10-01 11:37:14 -0700539 * @param portEntries
540 */
541 private void processPortRemoval(Collection<PortData> portEntries) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700542 for (PortData port : portEntries) {
Sangho Shin61535402014-10-01 11:37:14 -0700543 Dpid dpid = port.getDpid();
Sangho Shin61535402014-10-01 11:37:14 -0700544
Sangho Shinfbc572c2014-10-02 16:37:05 -0700545 IOF13Switch sw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin61535402014-10-01 11:37:14 -0700546 getSwId(port.getDpid().toString()));
Sangho Shin815af0c2014-10-10 13:05:45 -0700547 if (sw != null) {
Sangho Shinfbc572c2014-10-02 16:37:05 -0700548 sw.removePortFromGroups(port.getPortNumber());
Sangho Shin815af0c2014-10-10 13:05:45 -0700549 log.debug("Remove port {} from switch {}", port, dpid);
550 }
Sangho Shin61535402014-10-01 11:37:14 -0700551 }
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700552 }
Sangho Shin1aa93542014-09-22 09:49:44 -0700553
554 /**
Sangho Shin7330c032014-10-20 10:34:51 -0700555 * Add the link immediately
556 * The function is scheduled when link add event happens and called
557 * DELAY_TO_ADD_LINK seconds after the event to avoid link flip-flop.
558 */
559 private void delayedAddLink() {
560
561 processLinkAdd(linksToAdd.values(), true);
562
563 }
564
565
566 // ************************************
567 // ECMP shorted path routing functions
568 // ************************************
569
570 /**
Sangho Shin43cee112014-09-25 16:43:34 -0700571 * Populate routing rules walking through the ECMP shortest paths
Sangho Shinfbc572c2014-10-02 16:37:05 -0700572 *
Sangho Shin99918bd2014-10-08 15:52:35 -0700573 * @param modified if true, it "modifies" the rules
Sangho Shin1aa93542014-09-22 09:49:44 -0700574 */
Sangho Shin5be3e532014-10-03 17:20:58 -0700575 private void populateEcmpRoutingRules(boolean modified) {
576 graphs.clear();
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700577 Iterable<Switch> switches = mutableTopology.getSwitches();
Sangho Shin43cee112014-09-25 16:43:34 -0700578 for (Switch sw : switches) {
579 ECMPShortestPathGraph ecmpSPG = new ECMPShortestPathGraph(sw);
Sangho Shinfbc572c2014-10-02 16:37:05 -0700580 graphs.put(sw, ecmpSPG);
581 //log.debug("ECMPShortestPathGraph is computed for switch {}",
582 // HexString.toHexString(sw.getDpid().value()));
Sangho Shin5be3e532014-10-03 17:20:58 -0700583 populateEcmpRoutingRulesForPath(sw, ecmpSPG, modified);
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700584
585 // Set adjacency routing rule for all switches
586 try {
587 populateAdjacencyncyRule(sw);
588 } catch (JSONException e) {
589 // TODO Auto-generated catch block
590 e.printStackTrace();
591 }
Sangho Shinfbc572c2014-10-02 16:37:05 -0700592 }
Sangho Shinbce900e2014-10-07 17:13:23 -0700593 numOfPopulation++;
Sangho Shinfbc572c2014-10-02 16:37:05 -0700594 }
Sangho Shin1aa93542014-09-22 09:49:44 -0700595
Sangho Shin204b9972014-10-22 11:08:10 -0700596 /**
597 * populate the MPLS rules to handle Adjacency IDs
598 *
599 * @param sw Switch
600 * @throws JSONException
601 */
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700602 private void populateAdjacencyncyRule(Switch sw) throws JSONException {
603 String adjInfo = sw.getStringAttribute("adjacencySids");
Sangho Shin204b9972014-10-22 11:08:10 -0700604 String nodeSidStr = sw.getStringAttribute("nodeSid");
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700605 String srcMac = sw.getStringAttribute("routerMac");
Sangho Shin204b9972014-10-22 11:08:10 -0700606 String autoAdjInfo = sw.getStringAttribute("autogenAdjSids");
607
Sangho Shinced05b62014-10-22 11:23:14 -0700608 if (autoAdjInfo == null || srcMac == null || nodeSidStr == null)
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700609 return;
610
Sangho Shinced05b62014-10-22 11:23:14 -0700611 // parse adjacency Id
Sangho Shincfef3922014-10-22 12:04:16 -0700612 HashMap<Integer, List<Integer>> adjacencyInfo = null;
Sangho Shinced05b62014-10-22 11:23:14 -0700613 if (adjInfo != null) {
Sangho Shincfef3922014-10-22 12:04:16 -0700614 adjacencyInfo = parseAdjacencySidInfo(adjInfo);
Sangho Shinced05b62014-10-22 11:23:14 -0700615 }
Sangho Shincfef3922014-10-22 12:04:16 -0700616 // parse auto generated adjacency Id
617 adjacencyInfo.putAll(parseAdjacencySidInfo(autoAdjInfo));
Sangho Shinced05b62014-10-22 11:23:14 -0700618
Sangho Shin6471d202014-10-23 10:59:36 -0700619 adjacencySidTable.put(Integer.parseInt(nodeSidStr), adjacencyInfo);
Sangho Shin204b9972014-10-22 11:08:10 -0700620
Sangho Shin6471d202014-10-23 10:59:36 -0700621 for (Integer adjId: adjacencyInfo.keySet()) {
622 List<Integer> ports = adjacencyInfo.get(adjId);
623 if (ports.size() == 1) {
624 setAdjacencyRuleOfOutput(sw, adjId, srcMac, ports.get(0));
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700625 }
626 else {
Sangho Shin6471d202014-10-23 10:59:36 -0700627 setAdjacencyRuleOfGroup(sw, adjId, ports);
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700628 }
Sangho Shin6471d202014-10-23 10:59:36 -0700629 }
630 }
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700631
Sangho Shin6471d202014-10-23 10:59:36 -0700632 /**
633 * Set Adjacency Rule to MPLS table for adjacency Ids attached to multiple
634 * ports
635 *
636 * @param sw Switch
637 * @param adjId Adjacency ID
638 * @param ports List of ports assigned to the Adjacency ID
639 */
640 private void setAdjacencyRuleOfGroup(Switch sw, Integer adjId, List<Integer> ports) {
641
642 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
643 getSwId(sw.getDpid().toString()));
644
645 int groupId = -1;
646 if (sw13 != null) {
647 List<PortNumber> portList = new ArrayList<PortNumber>();
648 for (Integer port: ports)
649 portList.add(PortNumber.uint32(port));
650 groupId = sw13.createGroup(new ArrayList<Integer>(), portList);
651 }
652
653 if (groupId < 0) {
654 log.debug("Failed to create a group at driver for adj ID {}", adjId);
655 }
656
657 pushAdjRule(sw, adjId, null, null, groupId, true);
658 pushAdjRule(sw, adjId, null, null, groupId, false);
659 }
660
661 /**
662 * Set Adjacency Rule to MPLS table for adjacency Ids attached to single port
663 *
664 * @param sw Switch
665 * @param adjId Adjacency ID
666 * @param ports List of ports assigned to the Adjacency ID
667 */
668 private void setAdjacencyRuleOfOutput(Switch sw, Integer adjId, String srcMac, Integer portNo) {
669
670 Dpid dstDpid = null;
671 for (Link link: sw.getOutgoingLinks()) {
672 if (link.getSrcPort().getPortNumber().value() == portNo) {
673 dstDpid = link.getDstPort().getDpid();
674 break;
675 }
676 }
677 if (dstDpid == null) {
678 log.debug("Cannot find the destination switch for the adjacency ID {}", adjId);
679 return;
680 }
681 Switch dstSw = mutableTopology.getSwitch(dstDpid);
682 String dstMac = null;
683 if (dstSw == null) {
684 log.debug("Cannot find SW {}", dstDpid.toString());
685 return;
686 }
687 else {
688 dstMac = dstSw.getStringAttribute("routerMac");
689 }
690
691 pushAdjRule(sw, adjId, srcMac, dstMac, portNo, true); // BoS = 1
692 pushAdjRule(sw, adjId, srcMac, dstMac, portNo, false); // BoS = 0
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700693
694 }
695
Sangho Shin204b9972014-10-22 11:08:10 -0700696 /**
697 * Push the MPLS rule for Adjacency ID
698 *
699 * @param sw Switch to push the rule
700 * @param id Adjacency ID
701 * @param srcMac source MAC address
702 * @param dstMac destination MAC address
703 * @param portNo port number assigned to the ID
704 * @param bos BoS option
705 */
Sangho Shin6471d202014-10-23 10:59:36 -0700706 private void pushAdjRule(Switch sw, int id, String srcMac, String dstMac,
707 int num, boolean bos) {
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700708
709 MplsMatch mplsMatch = new MplsMatch(id, bos);
710 List<Action> actions = new ArrayList<Action>();
711
712 if (bos) {
713 PopMplsAction popAction = new PopMplsAction(EthType.IPv4);
714 CopyTtlInAction copyTtlInAction = new CopyTtlInAction();
715 DecNwTtlAction decNwTtlAction = new DecNwTtlAction(1);
716 actions.add(copyTtlInAction);
717 actions.add(popAction);
718 actions.add(decNwTtlAction);
719 }
720 else {
721 PopMplsAction popAction = new PopMplsAction(EthType.MPLS_UNICAST);
722 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
723 actions.add(popAction);
724 actions.add(decMplsTtlAction);
725 }
726
Sangho Shin6471d202014-10-23 10:59:36 -0700727 // Output action
728 if (srcMac != null && dstMac != null) {
Sangho Shind6d8a7e2014-10-28 14:51:03 -0700729 ModifyDstMacAction setDstAction = new ModifyDstMacAction(MACAddress.valueOf(dstMac));
730 ModifySrcMacAction setSrcAction = new ModifySrcMacAction(MACAddress.valueOf(srcMac));
Sangho Shin6471d202014-10-23 10:59:36 -0700731 OutputAction outportAction = new OutputAction(PortNumber.uint32(num));
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700732
Sangho Shin6471d202014-10-23 10:59:36 -0700733 actions.add(setDstAction);
734 actions.add(setSrcAction);
735 actions.add(outportAction);
736 }
737 // Group Action
738 else {
739 GroupAction groupAction = new GroupAction();
740 groupAction.setGroupId(num);
741 actions.add(groupAction);
742 }
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700743
744 MatchAction matchAction = new MatchAction(new MatchActionId(matchActionId++),
745 new SwitchPort((long) 0, (short) 0), mplsMatch, actions);
746 Operator operator = Operator.ADD;
747 MatchActionOperationEntry maEntry =
748 new MatchActionOperationEntry(operator, matchAction);
749
750 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
751 getSwId(sw.getDpid().toString()));
752
753 if (sw13 != null) {
754 try {
755 //printMatchActionOperationEntry(sw, maEntry);
756 sw13.pushFlow(maEntry);
757 } catch (IOException e) {
758 e.printStackTrace();
759 }
760 }
761 }
762
Sangho Shin99918bd2014-10-08 15:52:35 -0700763 /**
764 * populate routing rules to forward packets from the switch given to
765 * all other switches.
766 *
767 * @param sw source switch
768 * @param ecmpSPG shortest path from the the source switch to all others
769 * @param modified modification flag
770 */
Sangho Shinfbc572c2014-10-02 16:37:05 -0700771 private void populateEcmpRoutingRulesForPath(Switch sw,
Sangho Shin5be3e532014-10-03 17:20:58 -0700772 ECMPShortestPathGraph ecmpSPG, boolean modified) {
Sangho Shin43cee112014-09-25 16:43:34 -0700773
Sangho Shinfbc572c2014-10-02 16:37:05 -0700774 HashMap<Integer, HashMap<Switch, ArrayList<ArrayList<Dpid>>>> switchVia =
775 ecmpSPG.getAllLearnedSwitchesAndVia();
776 for (Integer itrIdx : switchVia.keySet()) {
777 //log.debug("ECMPShortestPathGraph:Switches learned in "
778 // + "Iteration{} from switch {}:",
779 // itrIdx,
780 // HexString.toHexString(sw.getDpid().value()));
781 HashMap<Switch, ArrayList<ArrayList<Dpid>>> swViaMap =
782 switchVia.get(itrIdx);
783 for (Switch targetSw : swViaMap.keySet()) {
Sangho Shin5be3e532014-10-03 17:20:58 -0700784 //log.debug("ECMPShortestPathGraph:****switch {} via:",
785 // HexString.toHexString(targetSw.getDpid().value()));
Sangho Shinfbc572c2014-10-02 16:37:05 -0700786 String destSw = sw.getDpid().toString();
787 List<String> fwdToSw = new ArrayList<String>();
788
Sangho Shinfbc572c2014-10-02 16:37:05 -0700789 for (ArrayList<Dpid> via : swViaMap.get(targetSw)) {
Sangho Shin5be3e532014-10-03 17:20:58 -0700790 //log.debug("ECMPShortestPathGraph:******{}) {}", ++i, via);
Sangho Shinfbc572c2014-10-02 16:37:05 -0700791 if (via.isEmpty()) {
792 fwdToSw.add(destSw);
Sangho Shin43cee112014-09-25 16:43:34 -0700793 }
Sangho Shinfbc572c2014-10-02 16:37:05 -0700794 else {
795 fwdToSw.add(via.get(0).toString());
796 }
Sangho Shin43cee112014-09-25 16:43:34 -0700797 }
Sangho Shin5be3e532014-10-03 17:20:58 -0700798 setRoutingRule(targetSw, destSw, fwdToSw, modified);
Sangho Shineb083032014-09-22 16:11:34 -0700799 }
Sangho Shinfbc572c2014-10-02 16:37:05 -0700800
801 // Send Barrier Message and make sure all rules are set
802 // before we set the rules to next routers
Saurav Dasa962a692014-10-17 14:52:38 -0700803 // TODO: barriers to all switches in this update stage
Sangho Shinfbc572c2014-10-02 16:37:05 -0700804 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
805 getSwId(sw.getDpid().toString()));
Sangho Shin5be3e532014-10-03 17:20:58 -0700806 if (sw13 != null) {
Saurav Dasa962a692014-10-17 14:52:38 -0700807 OFBarrierReplyFuture replyFuture = null;
Sangho Shin5be3e532014-10-03 17:20:58 -0700808 try {
Saurav Dasa962a692014-10-17 14:52:38 -0700809 replyFuture = sw13.sendBarrier();
Sangho Shin5be3e532014-10-03 17:20:58 -0700810 } catch (IOException e) {
Saurav Dasa962a692014-10-17 14:52:38 -0700811 log.error("Error sending barrier request to switch {}",
812 sw13.getId(), e.getCause());
Sangho Shin5be3e532014-10-03 17:20:58 -0700813 }
Saurav Dasa962a692014-10-17 14:52:38 -0700814 OFBarrierReply br = null;
815 try {
816 br = replyFuture.get(2, TimeUnit.SECONDS);
817 } catch (TimeoutException | InterruptedException | ExecutionException e) {
818 // XXX for some reason these exceptions are not being thrown
819 }
820 if (br == null) {
821 log.warn("Did not receive barrier-reply from {}", sw13.getId());
822 // XXX take corrective action
823 }
824
Sangho Shinfbc572c2014-10-02 16:37:05 -0700825 }
826 }
827
828 }
829
Sangho Shinfbc572c2014-10-02 16:37:05 -0700830 /**
831 *
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700832 * Set routing rules in targetSw {forward packets to fwdToSw switches in
833 * order to send packets to destSw} - If the target switch is an edge router
834 * and final destnation switch is also an edge router, then set IP
835 * forwarding rules to subnets - If only the target switch is an edge
836 * router, then set IP forwarding rule to the transit router loopback IP
837 * address - If the target is a transit router, then just set the MPLS
838 * forwarding rule
Sangho Shinfbc572c2014-10-02 16:37:05 -0700839 *
Sangho Shin43cee112014-09-25 16:43:34 -0700840 * @param targetSw Switch to set the rules
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700841 * @param destSw Final destination switches
Sangho Shin43cee112014-09-25 16:43:34 -0700842 * @param fwdToSw next hop switches
843 */
Sangho Shin99918bd2014-10-08 15:52:35 -0700844 private void setRoutingRule(Switch targetSw, String destSw,
845 List<String> fwdToSw, boolean modified) {
Sangho Shin43cee112014-09-25 16:43:34 -0700846
Sangho Shin43cee112014-09-25 16:43:34 -0700847 if (fwdToSw.isEmpty()) {
848 fwdToSw.add(destSw);
849 }
850
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700851 // if both target SW and dest SW are an edge router, then set IP table
Sangho Shin43cee112014-09-25 16:43:34 -0700852 if (IsEdgeRouter(targetSw.getDpid().toString()) &&
853 IsEdgeRouter(destSw)) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700854 // We assume that there is at least one transit router b/w edge
855 // routers
Sangho Shin43cee112014-09-25 16:43:34 -0700856 Switch destSwitch = mutableTopology.getSwitch(new Dpid(destSw));
857 String subnets = destSwitch.getStringAttribute("subnets");
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700858 setIpTableRouterSubnet(targetSw, subnets, getMplsLabel(destSw)
Sangho Shin5be3e532014-10-03 17:20:58 -0700859 , fwdToSw, modified);
Sangho Shin43cee112014-09-25 16:43:34 -0700860
Sangho Shin43cee112014-09-25 16:43:34 -0700861 String routerIp = destSwitch.getStringAttribute("routerIp");
Sangho Shin5be3e532014-10-03 17:20:58 -0700862 setIpTableRouter(targetSw, routerIp, getMplsLabel(destSw), fwdToSw,
863 null, modified);
Sangho Shin721ca042014-10-09 13:03:40 -0700864 // Edge router can be a transit router
865 setMplsTable(targetSw, getMplsLabel(destSw), fwdToSw, modified);
Sangho Shin43cee112014-09-25 16:43:34 -0700866 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700867 // Only if the target switch is the edge router, then set the IP rules
Sangho Shin43cee112014-09-25 16:43:34 -0700868 else if (IsEdgeRouter(targetSw.getDpid().toString())) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700869 // We assume that there is at least one transit router b/w edge
870 // routers
Sangho Shin43cee112014-09-25 16:43:34 -0700871 Switch destSwitch = mutableTopology.getSwitch(new Dpid(destSw));
872 String routerIp = destSwitch.getStringAttribute("routerIp");
Sangho Shin5be3e532014-10-03 17:20:58 -0700873 setIpTableRouter(targetSw, routerIp, getMplsLabel(destSw), fwdToSw,
874 null, modified);
Sangho Shin721ca042014-10-09 13:03:40 -0700875 // Edge router can be a transit router
876 setMplsTable(targetSw, getMplsLabel(destSw), fwdToSw, modified);
Sangho Shin43cee112014-09-25 16:43:34 -0700877 }
878 // if it is a transit router, then set rules in the MPLS table
879 else {
Sangho Shin5be3e532014-10-03 17:20:58 -0700880 setMplsTable(targetSw, getMplsLabel(destSw), fwdToSw, modified);
Sangho Shin43cee112014-09-25 16:43:34 -0700881 }
882
883 }
884
Sangho Shinfbc572c2014-10-02 16:37:05 -0700885 /**
886 * Set IP forwarding rule to the gateway of each subnet of switches
887 *
888 * @param targetSw Switch to set rules
889 * @param subnets subnet information
890 * @param mplsLabel destination MPLS label
891 * @param fwdToSw router to forward packets to
892 */
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700893 private void setIpTableRouterSubnet(Switch targetSw, String subnets,
Sangho Shin5be3e532014-10-03 17:20:58 -0700894 String mplsLabel, List<String> fwdToSw, boolean modified) {
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700895
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700896 Collection<MatchActionOperationEntry> entries =
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700897 new ArrayList<MatchActionOperationEntry>();
898
899 try {
900 JSONArray arry = new JSONArray(subnets);
901 for (int i = 0; i < arry.length(); i++) {
902 String subnetIp = (String) arry.getJSONObject(i).get("subnetIp");
Sangho Shin5be3e532014-10-03 17:20:58 -0700903 setIpTableRouter(targetSw, subnetIp, mplsLabel, fwdToSw, entries,
904 modified);
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700905 }
906 } catch (JSONException e) {
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700907 e.printStackTrace();
908 }
909
910 if (!entries.isEmpty()) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700911 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700912 getSwId(targetSw.getDpid().toString()));
913
Sangho Shin721ca042014-10-09 13:03:40 -0700914 if (sw13 != null) {
915 try {
916 sw13.pushFlows(entries);
917 } catch (IOException e) {
918 e.printStackTrace();
919 }
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700920 }
921 }
922
923 }
924
Sangho Shin43cee112014-09-25 16:43:34 -0700925 /**
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700926 * Set IP forwarding rule - If the destination is the next hop, then do not
927 * push MPLS, just decrease the NW TTL - Otherwise, push MPLS label and set
928 * the MPLS ID
Sangho Shinfbc572c2014-10-02 16:37:05 -0700929 *
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700930 * @param sw target switch to set rules
Sangho Shin43cee112014-09-25 16:43:34 -0700931 * @param subnetIp Match IP address
932 * @param mplsLabel MPLS label of final destination router
933 * @param fwdToSws next hop routers
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700934 * @param entries
Sangho Shin43cee112014-09-25 16:43:34 -0700935 */
936 private void setIpTableRouter(Switch sw, String subnetIp, String mplsLabel,
Sangho Shin5be3e532014-10-03 17:20:58 -0700937 List<String> fwdToSws, Collection<MatchActionOperationEntry> entries,
938 boolean modified) {
Sangho Shin43cee112014-09-25 16:43:34 -0700939
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700940 Ipv4Match ipMatch = new Ipv4Match(subnetIp);
Sangho Shin43cee112014-09-25 16:43:34 -0700941 List<Action> actions = new ArrayList<>();
Sangho Shin721ca042014-10-09 13:03:40 -0700942 GroupAction groupAction = new GroupAction();
Sangho Shin43cee112014-09-25 16:43:34 -0700943
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700944 // If destination SW is the same as the fwd SW, then do not push MPLS
945 // label
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700946 if (fwdToSws.size() > 1) {
Sangho Shin43cee112014-09-25 16:43:34 -0700947 PushMplsAction pushMplsAction = new PushMplsAction();
948 SetMplsIdAction setIdAction = new SetMplsIdAction(Integer.parseInt(mplsLabel));
949 CopyTtlOutAction copyTtlOutAction = new CopyTtlOutAction();
Sangho Shin463bee52014-09-29 15:14:43 -0700950 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
Sangho Shin43cee112014-09-25 16:43:34 -0700951
Sangho Shin62ce5c12014-10-08 16:24:40 -0700952 //actions.add(pushMplsAction);
953 //actions.add(copyTtlOutAction);
954 //actions.add(decMplsTtlAction);
Saurav Das82e62972014-10-16 14:53:57 -0700955 // actions.add(setIdAction);
Sangho Shin721ca042014-10-09 13:03:40 -0700956 groupAction.setEdgeLabel(Integer.parseInt(mplsLabel));
Sangho Shin43cee112014-09-25 16:43:34 -0700957 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700958 else {
959 String fwdToSw = fwdToSws.get(0);
960 if (getMplsLabel(fwdToSw).equals(mplsLabel)) {
961 DecNwTtlAction decTtlAction = new DecNwTtlAction(1);
962 actions.add(decTtlAction);
963 }
964 else {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700965 SetMplsIdAction setIdAction = new SetMplsIdAction(
966 Integer.parseInt(mplsLabel));
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700967 CopyTtlOutAction copyTtlOutAction = new CopyTtlOutAction();
Sangho Shin463bee52014-09-29 15:14:43 -0700968 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700969
Sangho Shin62ce5c12014-10-08 16:24:40 -0700970 //actions.add(pushMplsAction);
971 //actions.add(copyTtlOutAction);
972 //actions.add(decMplsTtlAction);
Saurav Das82e62972014-10-16 14:53:57 -0700973 // actions.add(setIdAction);
Sangho Shin721ca042014-10-09 13:03:40 -0700974 groupAction.setEdgeLabel(Integer.parseInt(mplsLabel));
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700975 }
976 }
Sangho Shin43cee112014-09-25 16:43:34 -0700977
Sangho Shin43cee112014-09-25 16:43:34 -0700978 for (String fwdSw : fwdToSws) {
979 groupAction.addSwitch(new Dpid(fwdSw));
980 }
981 actions.add(groupAction);
982
Sangho Shin99918bd2014-10-08 15:52:35 -0700983 MatchAction matchAction = new MatchAction(new MatchActionId(matchActionId++),
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700984 new SwitchPort((long) 0, (short) 0), ipMatch, actions);
Sangho Shin43cee112014-09-25 16:43:34 -0700985
Sangho Shin5be3e532014-10-03 17:20:58 -0700986 Operator operator = null;
987 if (modified)
988 operator = Operator.MODIFY;
989 else
990 operator = Operator.ADD;
991
Sangho Shin43cee112014-09-25 16:43:34 -0700992 MatchActionOperationEntry maEntry =
Sangho Shin5be3e532014-10-03 17:20:58 -0700993 new MatchActionOperationEntry(operator, matchAction);
Sangho Shin43cee112014-09-25 16:43:34 -0700994
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700995 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700996 getSwId(sw.getDpid().toString()));
997
Sangho Shin5be3e532014-10-03 17:20:58 -0700998 if (sw13 != null) {
999 try {
Sangho Shinbce900e2014-10-07 17:13:23 -07001000 //printMatchActionOperationEntry(sw, maEntry);
Sangho Shin5be3e532014-10-03 17:20:58 -07001001 if (entries != null)
1002 entries.add(maEntry);
1003 else
1004 sw13.pushFlow(maEntry);
1005 } catch (IOException e) {
1006 e.printStackTrace();
1007 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -07001008 }
1009
Sangho Shin43cee112014-09-25 16:43:34 -07001010 }
1011
Sangho Shinac5ee2b2014-09-28 21:27:20 -07001012 /**
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001013 * Set MPLS forwarding rules to MPLS table
1014 * </p>
1015 * If the destination is the same as the next hop to forward packets then,
1016 * pop the MPLS label according to PHP rule. Here, if BoS is set, then
1017 * copy TTL In and decrement NW TTL. Otherwise, it just decrement the MPLS
1018 * TTL of the another MPLS header.
1019 * If the next hop is not the destination, just forward packets to next
1020 * hops using Group action.
Sangho Shinfbc572c2014-10-02 16:37:05 -07001021 *
Sangho Shin204b9972014-10-22 11:08:10 -07001022 * TODO: refactoring required
1023 *
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001024 * @param sw Switch to set the rules
Sangho Shin43cee112014-09-25 16:43:34 -07001025 * @param mplsLabel destination MPLS label
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001026 * @param fwdSws next hop switches
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001027 * */
Sangho Shin5be3e532014-10-03 17:20:58 -07001028 private void setMplsTable(Switch sw, String mplsLabel, List<String> fwdSws,
1029 boolean modified) {
Sangho Shin463bee52014-09-29 15:14:43 -07001030
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001031 if (fwdSws.isEmpty())
1032 return;
Sangho Shin43cee112014-09-25 16:43:34 -07001033
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001034 Collection<MatchActionOperationEntry> maEntries =
1035 new ArrayList<MatchActionOperationEntry>();
1036 String fwdSw1 = fwdSws.get(0);
Sangho Shin43cee112014-09-25 16:43:34 -07001037
Sangho Shine842cad2014-10-24 16:07:35 -07001038 //If the next hop is the destination router, do PHP
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001039 if (fwdSws.size() == 1 && mplsLabel.equals(getMplsLabel(fwdSw1))) {
Sangho Shine842cad2014-10-24 16:07:35 -07001040 maEntries.add(buildMAEntry(sw, mplsLabel, fwdSws, true, true));
1041 maEntries.add(buildMAEntry(sw, mplsLabel, fwdSws, true, false));
Sangho Shin9c0f4c32014-09-26 16:02:38 -07001042 }
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001043 else {
Sangho Shine842cad2014-10-24 16:07:35 -07001044 maEntries.add(buildMAEntry(sw, mplsLabel, fwdSws, false, true));
1045 maEntries.add(buildMAEntry(sw, mplsLabel, fwdSws, false, false));
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001046 }
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001047 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin9c0f4c32014-09-26 16:02:38 -07001048 getSwId(sw.getDpid().toString()));
1049
Sangho Shin5be3e532014-10-03 17:20:58 -07001050 if (sw13 != null) {
1051 try {
Sangho Shinbce900e2014-10-07 17:13:23 -07001052 //printMatchActionOperationEntry(sw, maEntry);
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001053 sw13.pushFlows(maEntries);
Sangho Shin5be3e532014-10-03 17:20:58 -07001054 } catch (IOException e) {
1055 e.printStackTrace();
1056 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -07001057 }
Sangho Shin43cee112014-09-25 16:43:34 -07001058 }
1059
Sangho Shin7330c032014-10-20 10:34:51 -07001060
1061 // ************************************
1062 // Policy routing classes and functions
1063 // ************************************
1064
Fahad Naeem Khan1e712ad2014-10-27 16:48:07 -07001065 /**
1066 * Enums for policy type
1067 *
1068 */
1069 public enum PolicyType{
1070 TUNNEL_FLOW,
1071 LOADBALANCE,
1072 AVOID,
1073 DENY
1074 }
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001075 public class PolicyInfo {
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001076 private String policyId;
1077 private PacketMatch match;
1078 private int priority;
1079 private String tunnelId;
Fahad Naeem Khan1e712ad2014-10-27 16:48:07 -07001080 private PolicyType type;
Sangho Shin5b8f5452014-10-20 11:46:01 -07001081
Fahad Naeem Khan1e712ad2014-10-27 16:48:07 -07001082 public PolicyInfo(String pid, PolicyType type, PacketMatch match, int priority,
Sangho Shin58182672014-10-21 13:23:38 -07001083 String tid) {
1084 this.policyId = pid;
1085 this.match = match;
1086 this.priority = priority;
1087 this.tunnelId = tid;
1088 this.type = type;
1089 }
Sangho Shin204b9972014-10-22 11:08:10 -07001090
Fahad Naeem Khan95aa4012014-10-21 14:07:00 -07001091 public PolicyInfo(String pid, PacketMatch match, int priority,
1092 String tid) {
1093 this.policyId = pid;
1094 this.match = match;
1095 this.priority = priority;
1096 this.tunnelId = tid;
Fahad Naeem Khan1e712ad2014-10-27 16:48:07 -07001097 this.type = PolicyType.TUNNEL_FLOW;
Fahad Naeem Khan95aa4012014-10-21 14:07:00 -07001098 }
1099 public String getPolicyId(){
1100 return this.policyId;
1101 }
1102 public PacketMatch getMatch(){
1103 return this.match;
1104 }
1105 public int getPriority(){
1106 return this.priority;
1107 }
1108 public String getTunnelId(){
1109 return this.tunnelId;
1110 }
Fahad Naeem Khan1e712ad2014-10-27 16:48:07 -07001111 public PolicyType getType(){
Fahad Naeem Khan95aa4012014-10-21 14:07:00 -07001112 return this.type;
1113 }
Sangho Shin5b8f5452014-10-20 11:46:01 -07001114 }
1115
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001116 public class TunnelInfo {
1117 private String tunnelId;
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001118 private List<Integer> labelIds;
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001119 private List<TunnelRouteInfo> routes;
Sangho Shin81655442014-10-20 14:22:46 -07001120
Sangho Shin6471d202014-10-23 10:59:36 -07001121 public TunnelInfo(String tid, List<Integer> labelIds,
1122 List<TunnelRouteInfo> routes) {
Sangho Shin81655442014-10-20 14:22:46 -07001123 this.tunnelId = tid;
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001124 this.labelIds = labelIds;
Sangho Shin81655442014-10-20 14:22:46 -07001125 this.routes = routes;
1126 }
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001127 public String getTunnelId(){
1128 return this.tunnelId;
1129 }
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001130
1131 public List<Integer> getLabelids() {
1132 return this.labelIds;
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001133 }
1134 public List<TunnelRouteInfo> getRoutes(){
1135 return this.routes;
1136 }
Sangho Shin81655442014-10-20 14:22:46 -07001137 }
1138
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001139 public class TunnelRouteInfo {
Sangho Shin7330c032014-10-20 10:34:51 -07001140
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001141 private String srcSwDpid;
1142 private List<Dpid> fwdSwDpids;
1143 private List<String> route;
Sangho Shin6471d202014-10-23 10:59:36 -07001144 private int gropuId;
Sangho Shin7330c032014-10-20 10:34:51 -07001145
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001146 public TunnelRouteInfo() {
Sangho Shin7330c032014-10-20 10:34:51 -07001147 fwdSwDpids = new ArrayList<Dpid>();
1148 route = new ArrayList<String>();
1149 }
1150
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001151 private void setSrcDpid(String dpid) {
Sangho Shin7330c032014-10-20 10:34:51 -07001152 this.srcSwDpid = dpid;
1153 }
1154
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001155 private void setFwdSwDpid(List<Dpid> dpid) {
Sangho Shin7330c032014-10-20 10:34:51 -07001156 this.fwdSwDpids = dpid;
1157 }
1158
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001159 private void addRoute(String id) {
Sangho Shin7330c032014-10-20 10:34:51 -07001160 route.add(id);
1161 }
1162
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001163 private void setRoute(List<String> r) {
Sangho Shin7330c032014-10-20 10:34:51 -07001164 this.route = r;
1165 }
1166
Sangho Shin6471d202014-10-23 10:59:36 -07001167 private void setGroupId(int groupId) {
1168 this.gropuId = groupId;
1169 }
1170
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001171 public String getSrcSwDpid() {
Sangho Shin7330c032014-10-20 10:34:51 -07001172 return this.srcSwDpid;
1173 }
1174
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001175 public List<Dpid> getFwdSwDpid() {
Sangho Shin7330c032014-10-20 10:34:51 -07001176 return this.fwdSwDpids;
1177 }
1178
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001179 public List<String> getRoute() {
Sangho Shin7330c032014-10-20 10:34:51 -07001180 return this.route;
1181 }
Sangho Shin6471d202014-10-23 10:59:36 -07001182
1183 public int getGroupId() {
1184 return this.gropuId;
1185 }
Sangho Shin7330c032014-10-20 10:34:51 -07001186 }
1187
Sangho Shin15273b62014-10-16 22:22:05 -07001188 /**
Sangho Shin81655442014-10-20 14:22:46 -07001189 * Return the Tunnel table
1190 *
1191 * @return collection of TunnelInfo
1192 */
1193 public Collection<TunnelInfo> getTunnelTable() {
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001194 return this.tunnelTable.values();
Sangho Shin81655442014-10-20 14:22:46 -07001195 }
Sangho Shin204b9972014-10-22 11:08:10 -07001196
Fahad Naeem Khan12fa63a2014-10-21 17:01:27 -07001197 public Collection<PolicyInfo> getPoclicyTable() {
1198 return this.policyTable.values();
1199 }
Sangho Shin81655442014-10-20 14:22:46 -07001200
1201 /**
Sangho Shin5671cbb2014-10-20 22:35:41 -07001202 * Return router DPIDs for the tunnel
1203 *
1204 * @param tid tunnel ID
1205 * @return List of DPID
1206 */
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001207 public List<Integer> getTunnelInfo(String tid) {
Sangho Shin5671cbb2014-10-20 22:35:41 -07001208 TunnelInfo tunnelInfo = tunnelTable.get(tid);
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001209 return tunnelInfo.labelIds;
Sangho Shin5671cbb2014-10-20 22:35:41 -07001210
1211 }
1212
1213 /**
1214 * Get the first group ID for the tunnel for specific source router
1215 * If Segment Stitching was required to create the tunnel, there are
1216 * mutiple source routers.
1217 *
1218 * @param tunnelId ID for the tunnel
1219 * @param dpid source router DPID
1220 * @return the first group ID of the tunnel
1221 */
1222 public int getTunnelGroupId(String tunnelId, String dpid) {
Sangho Shin6471d202014-10-23 10:59:36 -07001223 TunnelInfo tunnelInfo = tunnelTable.get(tunnelId);
1224 for (TunnelRouteInfo routeInfo: tunnelInfo.getRoutes()) {
1225 String tunnelSrcDpid = routeInfo.getSrcSwDpid();
1226 if (tunnelSrcDpid.equals(dpid))
1227 return routeInfo.getGroupId();
1228 }
Sangho Shin5671cbb2014-10-20 22:35:41 -07001229
Sangho Shin6471d202014-10-23 10:59:36 -07001230 return -1;
Sangho Shin5671cbb2014-10-20 22:35:41 -07001231 }
1232
1233 /**
Sangho Shin15273b62014-10-16 22:22:05 -07001234 * Create a tunnel for policy routing
1235 * It delivers the node IDs of tunnels to driver.
1236 * Split the node IDs if number of IDs exceeds the limit for stitching.
1237 *
1238 * @param tunnelId Node IDs for the tunnel
1239 * @param Ids tunnel ID
1240 */
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001241 public boolean createTunnel(String tunnelId, List<Integer> labelIds) {
Sangho Shin15273b62014-10-16 22:22:05 -07001242
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001243 if (labelIds.isEmpty() || labelIds.size() < 2) {
Sangho Shin15273b62014-10-16 22:22:05 -07001244 log.debug("Wrong tunnel information");
1245 return false;
1246 }
1247
Sangho Shin55d00e12014-10-20 12:13:07 -07001248 List<String> Ids = new ArrayList<String>();
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001249 for (Integer label : labelIds) {
1250 Ids.add(label.toString());
Sangho Shin55d00e12014-10-20 12:13:07 -07001251 }
1252
Sangho Shin81655442014-10-20 14:22:46 -07001253 List<TunnelRouteInfo> stitchingRule = getStitchingRule(Ids);
Sangho Shin15273b62014-10-16 22:22:05 -07001254 if (stitchingRule == null) {
Sangho Shin6471d202014-10-23 10:59:36 -07001255 log.debug("Failed to get a tunnel rule.");
Sangho Shin15273b62014-10-16 22:22:05 -07001256 return false;
1257 }
Sangho Shin55908712014-10-27 15:16:48 -07001258
Sangho Shin81655442014-10-20 14:22:46 -07001259 for (TunnelRouteInfo route: stitchingRule) {
Sangho Shin15273b62014-10-16 22:22:05 -07001260 NeighborSet ns = new NeighborSet();
1261 for (Dpid dpid: route.getFwdSwDpid())
1262 ns.addDpid(dpid);
1263
Sangho Shin6471d202014-10-23 10:59:36 -07001264 printTunnelInfo(route.srcSwDpid, tunnelId, route.getRoute(), ns);
1265 int groupId = -1;
1266 if ((groupId =createGroupsForTunnel(tunnelId, route, ns)) < 0) {
1267 log.debug("Failed to create a tunnel at driver.");
1268 return false;
1269 }
1270 route.setGroupId(groupId);
Sangho Shin15273b62014-10-16 22:22:05 -07001271 }
1272
Sangho Shin6471d202014-10-23 10:59:36 -07001273 TunnelInfo tunnelInfo = new TunnelInfo(tunnelId, labelIds,
1274 stitchingRule);
Sangho Shin81655442014-10-20 14:22:46 -07001275 tunnelTable.put(tunnelId, tunnelInfo);
Sangho Shin15273b62014-10-16 22:22:05 -07001276
1277 return true;
1278 }
1279
Sangho Shin1a692c02014-10-23 17:05:41 -07001280 /**
1281 * Create groups for the tunnel
1282 *
1283 * @param tunnelId tunnel ID
1284 * @param routeInfo label stacks for the tunnel
1285 * @param ns NeighborSet to forward packets
1286 * @return group ID, return -1 if it fails
1287 */
Sangho Shin6471d202014-10-23 10:59:36 -07001288 private int createGroupsForTunnel(String tunnelId, TunnelRouteInfo routeInfo,
1289 NeighborSet ns) {
1290
1291 IOF13Switch targetSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
1292 getSwId(routeInfo.srcSwDpid));
1293
1294 if (targetSw == null) {
1295 log.debug("Switch {} is gone.", routeInfo.srcSwDpid);
1296 return -1;
1297 }
1298
1299 List<Integer> Ids = new ArrayList<Integer>();
1300 for (String IdStr: routeInfo.route)
1301 Ids.add(Integer.parseInt(IdStr));
1302
1303 List<PortNumber> ports = getPortsFromNeighborSet(routeInfo.srcSwDpid, ns);
1304 int groupId = targetSw.createGroup(Ids, ports);
1305
1306 return groupId;
1307 }
1308
Sangho Shin15273b62014-10-16 22:22:05 -07001309 /**
1310 * Set policy table for policy routing
1311 *
1312 * @param sw
1313 * @param mplsLabel
Sangho Shin306633a2014-10-20 14:26:55 -07001314 * @return
Sangho Shin15273b62014-10-16 22:22:05 -07001315 */
Sangho Shin306633a2014-10-20 14:26:55 -07001316 public boolean createPolicy(String pid, MACAddress srcMac, MACAddress dstMac,
Sangho Shin15273b62014-10-16 22:22:05 -07001317 Short etherType, IPv4Net srcIp, IPv4Net dstIp, Byte ipProto,
Sangho Shine020cc32014-10-20 13:28:02 -07001318 Short srcTcpPort, Short dstTcpPort, int priority, String tid) {
Sangho Shin15273b62014-10-16 22:22:05 -07001319
Sangho Shin5b8f5452014-10-20 11:46:01 -07001320 PacketMatchBuilder packetBuilder = new PacketMatchBuilder();
1321
1322 if (srcMac != null)
1323 packetBuilder.setSrcMac(srcMac);
1324 if (dstMac != null)
1325 packetBuilder.setDstMac(dstMac);
Sangho Shin58182672014-10-21 13:23:38 -07001326 if (etherType == null) // Cqpd requires the type of IPV4
1327 packetBuilder.setEtherType(Ethernet.TYPE_IPV4);
1328 else
Sangho Shin5b8f5452014-10-20 11:46:01 -07001329 packetBuilder.setEtherType(etherType);
1330 if (srcIp != null)
1331 packetBuilder.setSrcIp(srcIp.address(), srcIp.prefixLen());
1332 if (dstIp != null)
1333 packetBuilder.setDstIp(dstIp.address(), dstIp.prefixLen());
1334 if (ipProto != null)
1335 packetBuilder.setIpProto(ipProto);
1336 if (srcTcpPort > 0)
1337 packetBuilder.setSrcTcpPort(srcTcpPort);
1338 if (dstTcpPort > 0)
1339 packetBuilder.setDstTcpPort(dstTcpPort);
1340 PacketMatch policyMatch = packetBuilder.build();
Sangho Shin81655442014-10-20 14:22:46 -07001341 TunnelInfo tunnelInfo = tunnelTable.get(tid);
Sangho Shin6471d202014-10-23 10:59:36 -07001342 if (tunnelInfo == null) {
1343 log.debug("Tunnel {} is not defined", tid);
1344 return false;
1345 }
Sangho Shin81655442014-10-20 14:22:46 -07001346 List<TunnelRouteInfo> routes = tunnelInfo.routes;
Sangho Shin5b8f5452014-10-20 11:46:01 -07001347
Sangho Shin81655442014-10-20 14:22:46 -07001348 for (TunnelRouteInfo route : routes) {
Sangho Shin15273b62014-10-16 22:22:05 -07001349 List<Action> actions = new ArrayList<>();
Sangho Shinc5a38a02014-10-28 16:09:38 -07001350
1351 // Check PHP was done by stitching
1352 // If no MPLS label is added, then NW TTL needs to be decremented
1353 if (route.getRoute().isEmpty()) {
1354 DecNwTtlAction decNwTtlAction = new DecNwTtlAction(1);
1355 actions.add(decNwTtlAction);
1356 }
1357
Sangho Shin15273b62014-10-16 22:22:05 -07001358 GroupAction groupAction = new GroupAction();
Sangho Shin6471d202014-10-23 10:59:36 -07001359 groupAction.setGroupId(route.getGroupId());
Sangho Shin15273b62014-10-16 22:22:05 -07001360 actions.add(groupAction);
1361
1362 MatchAction matchAction = new MatchAction(new MatchActionId(
1363 matchActionId++),
Sangho Shin5b8f5452014-10-20 11:46:01 -07001364 new SwitchPort((long) 0, (short) 0), policyMatch, priority,
1365 actions);
Sangho Shin15273b62014-10-16 22:22:05 -07001366 MatchActionOperationEntry maEntry =
1367 new MatchActionOperationEntry(Operator.ADD, matchAction);
1368
1369 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin81655442014-10-20 14:22:46 -07001370 getSwId(route.srcSwDpid));
Sangho Shin15273b62014-10-16 22:22:05 -07001371
1372 if (sw13 != null) {
1373 printMatchActionOperationEntry(sw13, maEntry);
1374 try {
1375 sw13.pushFlow(maEntry);
1376 } catch (IOException e) {
1377 e.printStackTrace();
Sangho Shin306633a2014-10-20 14:26:55 -07001378 return false;
Sangho Shin15273b62014-10-16 22:22:05 -07001379 }
1380 }
1381 }
Sangho Shin5b8f5452014-10-20 11:46:01 -07001382
1383 PolicyInfo policyInfo = new PolicyInfo(pid, policyMatch, priority, tid);
Sangho Shine020cc32014-10-20 13:28:02 -07001384 policyTable.put(pid, policyInfo);
Sangho Shin306633a2014-10-20 14:26:55 -07001385
1386 return true;
Sangho Shin15273b62014-10-16 22:22:05 -07001387 }
1388
1389 /**
Sangho Shin1ad7be02014-10-20 16:56:49 -07001390 * Split the nodes IDs into multiple tunnel if Segment Stitching is required.
1391 * We assume that the first node ID is the one of source router, and the last
1392 * node ID is that of the destination router.
Sangho Shin15273b62014-10-16 22:22:05 -07001393 *
Sangho Shin1ad7be02014-10-20 16:56:49 -07001394 * @param route list of node IDs
1395 * @return List of the TunnelRoutInfo
Sangho Shin15273b62014-10-16 22:22:05 -07001396 */
Sangho Shin81655442014-10-20 14:22:46 -07001397 private List<TunnelRouteInfo> getStitchingRule(List<String> route) {
Sangho Shin15273b62014-10-16 22:22:05 -07001398
Sangho Shin1a692c02014-10-23 17:05:41 -07001399 if (route.isEmpty() || route.size() < 3)
Sangho Shin15273b62014-10-16 22:22:05 -07001400 return null;
1401
Sangho Shin81655442014-10-20 14:22:46 -07001402 List<TunnelRouteInfo> rules = new ArrayList<TunnelRouteInfo>();
Sangho Shin15273b62014-10-16 22:22:05 -07001403
1404 Switch srcSw = this.getSwitchFromNodeId(route.get(0));
Sangho Shin6471d202014-10-23 10:59:36 -07001405 if (srcSw == null) {
1406 log.warn("Switch is not found for Node SID {}", route.get(0));
1407 return null;
1408 }
Sangho Shin15273b62014-10-16 22:22:05 -07001409 String srcDpid = srcSw.getDpid().toString();
1410
Sangho Shin15273b62014-10-16 22:22:05 -07001411 int i = 0;
Sangho Shine020cc32014-10-20 13:28:02 -07001412 TunnelRouteInfo routeInfo = new TunnelRouteInfo();
Sangho Shin1a692c02014-10-23 17:05:41 -07001413 boolean checkNeighbor = false;
Sangho Shin6471d202014-10-23 10:59:36 -07001414 String prevAdjacencySid = null;
1415 String prevNodeId = null;
Sangho Shin15273b62014-10-16 22:22:05 -07001416
1417 for (String nodeId: route) {
Sangho Shin6471d202014-10-23 10:59:36 -07001418 // The first node ID is always the source router.
1419 // We assume that the first ID cannot be an Adjacency SID.
Sangho Shin15273b62014-10-16 22:22:05 -07001420 if (i == 0) {
Sangho Shin15273b62014-10-16 22:22:05 -07001421 srcSw = getSwitchFromNodeId(nodeId);
Sangho Shin1a692c02014-10-23 17:05:41 -07001422 if (srcDpid == null)
1423 srcDpid = srcSw.getDpid().toString();
1424 routeInfo.setSrcDpid(srcDpid);
1425 checkNeighbor = true;
Sangho Shin15273b62014-10-16 22:22:05 -07001426 i++;
1427 }
Sangho Shin1a692c02014-10-23 17:05:41 -07001428 // if this is the first node ID to put the label stack..
Sangho Shin6471d202014-10-23 10:59:36 -07001429 else if (i == 1) {
Sangho Shin1a692c02014-10-23 17:05:41 -07001430 if (checkNeighbor) {
1431 List<Dpid> fwdSws = getDpidIfNeighborOf(nodeId, srcSw);
1432 // if nodeId is NOT the neighbor of srcSw..
1433 if (fwdSws.isEmpty()) {
1434 fwdSws = getForwardingSwitchForNodeId(srcSw,nodeId);
1435 if (fwdSws == null || fwdSws.isEmpty()) {
1436 log.warn("There is no route from node {} to node {}",
1437 srcSw.getDpid(), nodeId);
1438 return null;
Sangho Shin6471d202014-10-23 10:59:36 -07001439 }
Sangho Shin6471d202014-10-23 10:59:36 -07001440 routeInfo.addRoute(nodeId);
Sangho Shin6471d202014-10-23 10:59:36 -07001441 i++;
1442 }
Sangho Shin1a692c02014-10-23 17:05:41 -07001443 routeInfo.setFwdSwDpid(fwdSws);
Sangho Shin6471d202014-10-23 10:59:36 -07001444 // we check only the next node ID of the source router
1445 checkNeighbor = false;
Sangho Shin1a692c02014-10-23 17:05:41 -07001446 }
1447 // if neighbor check is already done, then just add it
1448 else {
Sangho Shin6471d202014-10-23 10:59:36 -07001449 routeInfo.addRoute(nodeId);
Sangho Shin15273b62014-10-16 22:22:05 -07001450 i++;
1451 }
1452 }
Sangho Shin6471d202014-10-23 10:59:36 -07001453 // if i > 1
Sangho Shin15273b62014-10-16 22:22:05 -07001454 else {
Sangho Shin6471d202014-10-23 10:59:36 -07001455 // If the adjacency SID is pushed and the next SID is the destination
1456 // of the adjacency SID, then do not add the SID.
1457 if (prevAdjacencySid != null) {
1458 if (isAdjacencySidNeighborOf(prevNodeId, prevAdjacencySid, nodeId)) {
1459 prevAdjacencySid = null;
Sangho Shind6d8a7e2014-10-28 14:51:03 -07001460 prevNodeId = nodeId;
Sangho Shin6471d202014-10-23 10:59:36 -07001461 continue;
1462 }
1463 prevAdjacencySid = null;
1464 }
Sangho Shin15273b62014-10-16 22:22:05 -07001465 routeInfo.addRoute(nodeId);
1466 i++;
1467 }
1468
Sangho Shin1a692c02014-10-23 17:05:41 -07001469 // If the adjacency ID is added the label stack,
1470 // then we need to check if the next node is the destination of the adjacency SID
1471 if (isAdjacencySid(nodeId))
1472 prevAdjacencySid = nodeId;
1473
Sangho Shin1ad7be02014-10-20 16:56:49 -07001474 // If the number of labels reaches the limit, start over the procedure
Sangho Shin15273b62014-10-16 22:22:05 -07001475 if (i == MAX_NUM_LABELS+1) {
Sangho Shin1a692c02014-10-23 17:05:41 -07001476
Sangho Shin81655442014-10-20 14:22:46 -07001477 rules.add(routeInfo);
Sangho Shine020cc32014-10-20 13:28:02 -07001478 routeInfo = new TunnelRouteInfo();
Sangho Shin1a692c02014-10-23 17:05:41 -07001479
Sangho Shin62325582014-10-24 10:36:09 -07001480 if (isAdjacencySid(nodeId)) {
1481 // If the previous sub tunnel finishes with adjacency SID,
1482 // then we need to start the procedure from the adjacency
1483 // destination ID.
1484 List<Switch> destNodeList =
1485 getAdjacencyDestinationNode(prevNodeId, nodeId);
1486 if (destNodeList == null || destNodeList.isEmpty()) {
1487 log.warn("Cannot find destination node for adjacencySID {}",
1488 nodeId);
1489 return null;
1490 }
1491 // If the previous sub tunnel finishes with adjacency SID with
1492 // multiple ports, then we need to remove the adjacency Sid
1493 // from the previous sub tunnel and start the new sub tunnel
1494 // with the adjacency Sid. Technically, the new subtunnel
1495 // forward packets to the port assigned to the adjacency Sid
1496 // and the label stack starts with the next ID.
1497 // This is to avoid to install new policy rule to multiple nodes for stitching when the
1498 // adjacency Sid that has more than one port.
1499 if (destNodeList.size() > 1) {
1500 rules.get(rules.size()-1).route.remove(nodeId);
1501 srcSw = getSwitchFromNodeId(prevNodeId);
1502 List<Dpid> fwdSws = getDpidIfNeighborOf(nodeId, srcSw);
1503 routeInfo.setFwdSwDpid(fwdSws);
1504 routeInfo.setSrcDpid(srcSw.getDpid().toString());
1505 i = 1;
1506 checkNeighbor = false;
1507 continue;
1508 }
1509 else {
Sangho Shin1a692c02014-10-23 17:05:41 -07001510 srcSw = destNodeList.get(0);
Sangho Shin62325582014-10-24 10:36:09 -07001511 }
1512 }
1513 else {
1514 srcSw = getSwitchFromNodeId(nodeId);
Sangho Shin1a692c02014-10-23 17:05:41 -07001515 }
1516 srcDpid = srcSw.getDpid().toString();
Sangho Shin15273b62014-10-16 22:22:05 -07001517 routeInfo.setSrcDpid(srcDpid);
1518 i = 1;
1519 checkNeighbor = true;
1520 }
Sangho Shin6471d202014-10-23 10:59:36 -07001521
1522 if (prevAdjacencySid == null)
1523 prevNodeId = nodeId;
Sangho Shin15273b62014-10-16 22:22:05 -07001524 }
1525
Sangho Shin1a692c02014-10-23 17:05:41 -07001526
Sangho Shineb148ea2014-10-24 12:44:15 -07001527 if (i < MAX_NUM_LABELS+1 && (routeInfo.getFwdSwDpid() != null &&
1528 !routeInfo.getFwdSwDpid().isEmpty())) {
Sangho Shin81655442014-10-20 14:22:46 -07001529 rules.add(routeInfo);
Sangho Shineb148ea2014-10-24 12:44:15 -07001530 // NOTE: empty label stack can happen, but forwarding destination should be set
Sangho Shin15273b62014-10-16 22:22:05 -07001531 }
1532
1533 return rules;
1534 }
1535
Sangho Shin5b8f5452014-10-20 11:46:01 -07001536 /**
1537 * Remove all policies applied to specific tunnel.
1538 *
1539 * @param srcMac
1540 * @param dstMac
1541 * @param etherType
1542 * @param srcIp
1543 * @param dstIp
1544 * @param ipProto
1545 * @param srcTcpPort
1546 * @param dstTcpPort
1547 * @param tid
Sangho Shin306633a2014-10-20 14:26:55 -07001548 * @return
Sangho Shin5b8f5452014-10-20 11:46:01 -07001549 */
Sangho Shin306633a2014-10-20 14:26:55 -07001550 public boolean removePolicy(String pid) {
Sangho Shine020cc32014-10-20 13:28:02 -07001551 PolicyInfo policyInfo = policyTable.get(pid);
Sangho Shin5671cbb2014-10-20 22:35:41 -07001552 if (policyInfo == null)
1553 return false;
Sangho Shin5b8f5452014-10-20 11:46:01 -07001554 PacketMatch policyMatch = policyInfo.match;
Sangho Shine020cc32014-10-20 13:28:02 -07001555 String tid = policyInfo.tunnelId;
Sangho Shin5b8f5452014-10-20 11:46:01 -07001556 int priority = policyInfo.priority;
1557
1558 List<Action> actions = new ArrayList<>();
1559 int gropuId = 0; // dummy group ID
1560 GroupAction groupAction = new GroupAction();
1561 groupAction.setGroupId(gropuId);
1562 actions.add(groupAction);
1563
1564 MatchAction matchAction = new MatchAction(new MatchActionId(
1565 matchActionId++),
1566 new SwitchPort((long) 0, (short) 0), policyMatch, priority,
1567 actions);
1568 MatchActionOperationEntry maEntry =
1569 new MatchActionOperationEntry(Operator.REMOVE, matchAction);
1570
Sangho Shin81655442014-10-20 14:22:46 -07001571 TunnelInfo tunnelInfo = tunnelTable.get(tid);
Sangho Shin5671cbb2014-10-20 22:35:41 -07001572 if (tunnelInfo == null)
1573 return false;
Sangho Shin81655442014-10-20 14:22:46 -07001574 List<TunnelRouteInfo> routes = tunnelInfo.routes;
1575
1576 for (TunnelRouteInfo route : routes) {
Sangho Shin5b8f5452014-10-20 11:46:01 -07001577 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin81655442014-10-20 14:22:46 -07001578 getSwId(route.srcSwDpid));
Sangho Shin5b8f5452014-10-20 11:46:01 -07001579
Sangho Shin5671cbb2014-10-20 22:35:41 -07001580 if (sw13 == null) {
1581 return false;
1582 }
1583 else {
Sangho Shin5b8f5452014-10-20 11:46:01 -07001584 printMatchActionOperationEntry(sw13, maEntry);
1585 try {
1586 sw13.pushFlow(maEntry);
1587 } catch (IOException e) {
1588 e.printStackTrace();
1589 log.debug("policy remove failed due to pushFlow() exception");
Sangho Shin306633a2014-10-20 14:26:55 -07001590 return false;
Sangho Shin5b8f5452014-10-20 11:46:01 -07001591 }
1592 }
1593 }
1594
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001595 policyTable.remove(pid);
Sangho Shin5b8f5452014-10-20 11:46:01 -07001596 log.debug("Policy {} is removed.", pid);
Sangho Shin306633a2014-10-20 14:26:55 -07001597 return true;
Sangho Shine020cc32014-10-20 13:28:02 -07001598 }
Sangho Shin5b8f5452014-10-20 11:46:01 -07001599
Fahad Naeem Khan4ff83d62014-10-28 16:18:07 -07001600 public enum removeTunnelMessages{
1601 SUCCESS(0, "Tunnel is removed successfully."),
1602 ERROR_REFERENCED(1, "Can't remove tunnel as its referenced by other policy(s)"),
1603 ERROR_SWITCH(2, "Switch not found in the tunnel route"),
1604 ERROR_DRIVER(3, "Can't remove tunnel at driver"),
1605 ERROR_TUNNEL(4, "Tunnel not found");
1606
1607 private final int code;
1608 private final String description;
1609
1610 private removeTunnelMessages(int code, String description) {
1611 this.code = code;
1612 this.description = description;
1613 }
1614
1615 public String getDescription() {
1616 return this.description;
1617 }
1618
1619 public int getCode() {
1620 return this.code;
1621 }
1622
1623 @Override
1624 public String toString() {
1625 return "[" + this.code + ": " + this.description + "]";
1626 }
1627
1628 }
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001629 /**
1630 * Remove a tunnel
1631 * It removes all groups for the tunnel if the tunnel is not used for any
1632 * policy.
1633 *
1634 * @param tunnelId tunnel ID to remove
1635 */
Fahad Naeem Khan4ff83d62014-10-28 16:18:07 -07001636 public removeTunnelMessages removeTunnel(String tunnelId) {
Sangho Shin55d00e12014-10-20 12:13:07 -07001637
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001638 // Check if the tunnel is used for any policy
1639 for (PolicyInfo policyInfo: policyTable.values()) {
Sangho Shina000c612014-10-21 14:17:59 -07001640 if (policyInfo.tunnelId.equals(tunnelId)) {
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001641 log.debug("Tunnel {} is still used for the policy {}.",
1642 policyInfo.policyId, tunnelId);
Fahad Naeem Khan4ff83d62014-10-28 16:18:07 -07001643 return removeTunnelMessages.ERROR_REFERENCED;
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001644 }
1645 }
1646
1647 TunnelInfo tunnelInfo = tunnelTable.get(tunnelId);
Sangho Shin5671cbb2014-10-20 22:35:41 -07001648 if (tunnelInfo == null)
Fahad Naeem Khan4ff83d62014-10-28 16:18:07 -07001649 return removeTunnelMessages.ERROR_TUNNEL;
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001650
1651 List<TunnelRouteInfo> routes = tunnelInfo.routes;
1652 for (TunnelRouteInfo route: routes) {
1653 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
1654 getSwId(route.srcSwDpid));
1655
Sangho Shin5671cbb2014-10-20 22:35:41 -07001656 if (sw13 == null) {
Fahad Naeem Khan4ff83d62014-10-28 16:18:07 -07001657 return removeTunnelMessages.ERROR_SWITCH;
Sangho Shin5671cbb2014-10-20 22:35:41 -07001658 }
1659 else {
Sangho Shin93f623c2014-10-24 12:59:53 -07001660 if (!sw13.removeGroup(route.getGroupId())) {
Sangho Shine842cad2014-10-24 16:07:35 -07001661 log.warn("Faied to remove the tunnel {} at driver",
1662 tunnelId);
Fahad Naeem Khan4ff83d62014-10-28 16:18:07 -07001663 return removeTunnelMessages.ERROR_DRIVER;
1664 }
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001665 }
1666 }
1667
1668 tunnelTable.remove(tunnelId);
Sangho Shine842cad2014-10-24 16:07:35 -07001669 log.debug("Tunnel {} was removed successfully.", tunnelId);
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001670
Fahad Naeem Khan4ff83d62014-10-28 16:18:07 -07001671 return removeTunnelMessages.SUCCESS;
Sangho Shin55d00e12014-10-20 12:13:07 -07001672 }
1673
Sangho Shin7330c032014-10-20 10:34:51 -07001674 // ************************************
1675 // Utility functions
1676 // ************************************
1677
Sangho Shin1a692c02014-10-23 17:05:41 -07001678 /**
1679 * Get the destination Nodes of the adjacency Sid
1680 *
1681 * @param nodeId node ID of the adjacency Sid
1682 * @param adjacencySid adjacency Sid
1683 * @return List of Switch, empty list if not found
1684 */
1685 private List<Switch> getAdjacencyDestinationNode(String nodeId, String adjacencySid) {
1686 List<Switch> dstSwList = new ArrayList<Switch>();
1687
1688 HashMap<Integer, List<Integer>> adjacencySidInfo =
1689 adjacencySidTable.get(Integer.valueOf(nodeId));
1690 List<Integer> ports = adjacencySidInfo.get(Integer.valueOf(adjacencySid));
1691 Switch srcSw = getSwitchFromNodeId(nodeId);
1692 for (Integer port: ports) {
1693 for (Link link: srcSw.getOutgoingLinks()) {
1694 if (link.getSrcPort().getPortNumber().value() == port) {
1695 dstSwList.add(link.getDstSwitch());
1696 }
1697 }
1698 }
1699
1700 return dstSwList;
1701
1702 }
1703
1704 /**
1705 * Get the DPID of the router with node ID IF the node ID is the neighbor of the
1706 * Switch srcSW.
1707 * If the nodeId is the adjacency Sid, then it returns the destination router DPIDs.
1708 *
1709 * @param nodeId Node ID to check
1710 * @param srcSw target Switch
1711 * @return List of DPID of nodeId, empty list if the nodeId is not the neighbor of srcSW
1712 */
1713 private List<Dpid> getDpidIfNeighborOf(String nodeId, Switch srcSw) {
1714 List<Dpid> fwdSws = new ArrayList<Dpid>();
1715 // if the nodeID is the adjacency ID, then we need to regard it as the
1716 // neighbor node ID and need to return the destination router DPID(s)
1717 if (isAdjacencySid(nodeId)) {
1718 String srcNodeId = this.getMplsLabel(srcSw.getDpid().toString());
1719 HashMap<Integer, List<Integer>> adjacencySidInfo =
1720 adjacencySidTable.get(Integer.valueOf(srcNodeId));
1721 List<Integer> ports = adjacencySidInfo.get(Integer.valueOf(nodeId));
1722
1723 for (Integer port: ports) {
1724 for (Link link: srcSw.getOutgoingLinks()) {
1725 if (link.getSrcPort().getPortNumber().value() == port) {
1726 fwdSws.add(link.getDstSwitch().getDpid());
1727 }
1728 }
1729 }
1730 }
1731 else {
1732 List<Dpid> fwdSwDpids = getForwardingSwitchForNodeId(srcSw,nodeId);
1733 if (fwdSwDpids == null || fwdSwDpids.isEmpty()) {
1734 log.warn("There is no route from node {} to node {}",
1735 srcSw.getDpid(), nodeId);
Sangho Shin55908712014-10-27 15:16:48 -07001736 return fwdSws;
Sangho Shin1a692c02014-10-23 17:05:41 -07001737 }
1738
1739 for (Dpid dpid: fwdSwDpids) {
1740 if (getMplsLabel(dpid.toString()).toString().equals(nodeId)) {
1741 fwdSws.add(dpid);
1742 break;
1743 }
1744 }
1745 }
1746
1747 return fwdSws;
1748 }
1749
1750 /**
Sangho Shin55908712014-10-27 15:16:48 -07001751 * Get port numbers of the neighbor set.
1752 * If ECMP in transit router is not supported, then only one port should be returned
1753 * regardless of number of nodes in neighbor set.
Sangho Shin1a692c02014-10-23 17:05:41 -07001754 *
1755 * @param srcSwDpid source switch
1756 * @param ns Neighbor set of the switch
1757 * @return List of PortNumber, null if not found
1758 */
Sangho Shin6471d202014-10-23 10:59:36 -07001759 private List<PortNumber> getPortsFromNeighborSet(String srcSwDpid, NeighborSet ns) {
1760
1761 List<PortNumber> portList = new ArrayList<PortNumber>();
1762 Switch srcSwitch = mutableTopology.getSwitch(new Dpid(srcSwDpid));
1763 if (srcSwitch == null)
1764 return null;
Sangho Shinf66aa262014-10-27 16:03:42 -07001765 IOF13Switch srcSwitch13 = (IOF13Switch)floodlightProvider.getMasterSwitch(
1766 getSwId(srcSwitch.getDpid().toString()));
1767
Sangho Shin6471d202014-10-23 10:59:36 -07001768 for (Dpid neighborDpid: ns.getDpids()) {
Sangho Shinf66aa262014-10-27 16:03:42 -07001769 if (srcSwitch13 instanceof OFSwitchImplDellOSR &&
1770 ns.getDpids().size() == 1) {
Sangho Shin55908712014-10-27 15:16:48 -07001771 Switch dstSwitch = mutableTopology.getSwitch(neighborDpid);
1772 if (isTransitRouter(srcSwitch) && isTransitRouter(dstSwitch)) {
1773 Link link = srcSwitch.getLinkToNeighbor(neighborDpid);
1774 portList.add(link.getSrcPort().getNumber());
1775 break;
1776 }
1777 }
1778 else {
1779 for (Link link: srcSwitch.getOutgoingLinks()) {
1780 if (link.getDstSwitch().getDpid().equals(neighborDpid)) {
1781 portList.add(link.getSrcPort().getNumber());
1782 }
1783 }
1784 }
Sangho Shin6471d202014-10-23 10:59:36 -07001785 }
1786
1787 return portList;
1788 }
1789
Sangho Shine842cad2014-10-24 16:07:35 -07001790 /**
1791 * Check whether the router with preNodeid is connected to the router
1792 * with nodeId via adjacencySid or not
1793 *
1794 * @param prevNodeId the router node ID of the adjacencySid
1795 * @param adjacencySid adjacency SID
1796 * @param nodeId the router node ID to check
1797 * @return
1798 */
1799 private boolean isAdjacencySidNeighborOf(String prevNodeId, String adjacencySid, String nodeId) {
Sangho Shin6471d202014-10-23 10:59:36 -07001800
1801 HashMap<Integer, List<Integer>> adjacencySidInfo = adjacencySidTable.get(Integer.valueOf(prevNodeId));
Sangho Shine842cad2014-10-24 16:07:35 -07001802 List<Integer> ports = adjacencySidInfo.get(Integer.valueOf(adjacencySid));
Sangho Shin6471d202014-10-23 10:59:36 -07001803
1804 for (Integer port: ports) {
1805 Switch sw = getSwitchFromNodeId(prevNodeId);
1806 for (Link link: sw.getOutgoingLinks()) {
1807 if (link.getSrcPort().getPortNumber().value() == port) {
1808 if (getMplsLabel(link.getDstPort().getDpid().toString()).equals(nodeId)) {
1809 return true;
1810 }
1811 }
1812 }
1813 }
1814
1815 return false;
1816 }
1817
Sangho Shine842cad2014-10-24 16:07:35 -07001818 /**
1819 * Check if the node ID is the adjacency ID or not
1820 *
1821 * @param nodeId to check
1822 * @return true if the node ID is the adjacency ID, false otherwise
1823 */
Sangho Shin6471d202014-10-23 10:59:36 -07001824 private boolean isAdjacencySid(String nodeId) {
1825 // XXX The rule might change
1826 if (Integer.parseInt(nodeId) > 10000)
1827 return true;
1828
1829 return false;
1830 }
1831
Sangho Shin15273b62014-10-16 22:22:05 -07001832 /**
Sangho Shinced05b62014-10-22 11:23:14 -07001833 * Returns the Adjacency IDs for the node
1834 *
1835 * @param nodeSid Node SID
Sangho Shincfef3922014-10-22 12:04:16 -07001836 * @return Collection of Adjacency ID
Sangho Shinced05b62014-10-22 11:23:14 -07001837 */
Sangho Shincfef3922014-10-22 12:04:16 -07001838 public Collection<Integer> getAdjacencyIds(int nodeSid) {
1839 HashMap<Integer, List<Integer>> adjecencyInfo =
Sangho Shin6471d202014-10-23 10:59:36 -07001840 adjacencySidTable.get(Integer.valueOf(nodeSid));
Sangho Shincfef3922014-10-22 12:04:16 -07001841
1842 return adjecencyInfo.keySet();
1843 }
1844
1845 /**
1846 * Returns the Adjacency Info for the node
1847 *
1848 * @param nodeSid Node SID
1849 * @return HashMap of <AdjacencyID, list of ports>
1850 */
1851 public HashMap<Integer, List<Integer>> getAdjacencyInfo(int nodeSid) {
Sangho Shin6471d202014-10-23 10:59:36 -07001852 return adjacencySidTable.get(Integer.valueOf(nodeSid));
Sangho Shincfef3922014-10-22 12:04:16 -07001853 }
1854
Sangho Shine842cad2014-10-24 16:07:35 -07001855 /**
1856 * Parse the adjacency jason string and build the adjacency Table
1857 *
1858 * @param adjInfo adjacency info jason string
1859 * @return HashMap<Adjacency ID, List of ports> object
1860 * @throws JSONException
1861 */
1862 private HashMap<Integer, List<Integer>> parseAdjacencySidInfo(String adjInfo)
1863 throws JSONException {
Sangho Shincfef3922014-10-22 12:04:16 -07001864 JSONArray arry = new JSONArray(adjInfo);
1865 HashMap<Integer, List<Integer>> AdjacencyInfo =
1866 new HashMap<Integer, List<Integer>>();
1867
1868 for (int i = 0; i < arry.length(); i++) {
1869 Integer adjId = (Integer) arry.getJSONObject(i).get("adjSid");
1870 JSONArray portNos = (JSONArray) arry.getJSONObject(i).get("ports");
1871 if (adjId == null || portNos == null)
1872 continue;
1873
1874 List<Integer> portNoList = new ArrayList<Integer>();
1875 for (int j = 0; j < portNos.length(); j++) {
Sangho Shin62325582014-10-24 10:36:09 -07001876 portNoList.add(Integer.valueOf(portNos.getInt(j)));
Sangho Shincfef3922014-10-22 12:04:16 -07001877 }
1878 AdjacencyInfo.put(adjId, portNoList);
1879 }
1880 return AdjacencyInfo;
Sangho Shinced05b62014-10-22 11:23:14 -07001881 }
1882
1883 /**
Sangho Shine842cad2014-10-24 16:07:35 -07001884 * Build the MatchActionOperationEntry according to the flag
1885 *
1886 * @param sw node ID to push for MPLS label
1887 * @param mplsLabel List of Switch DPIDs to forwards packets to
1888 * @param fwdSws PHP flag
1889 * @param Bos BoS flag
1890 * @param isTransitRouter
1891 * @return MatchiACtionOperationEntry object
1892 */
1893 private MatchActionOperationEntry buildMAEntry(Switch sw,
1894 String mplsLabel, List<String> fwdSws, boolean php,
1895 boolean Bos) {
1896 MplsMatch mplsMatch = new MplsMatch(Integer.parseInt(mplsLabel), Bos);
1897 List<Action> actions = new ArrayList<Action>();
1898
1899 PopMplsAction popActionBos = new PopMplsAction(EthType.IPv4);
1900 PopMplsAction popAction = new PopMplsAction(EthType.MPLS_UNICAST);
1901 CopyTtlInAction copyTtlInAction = new CopyTtlInAction();
1902 DecNwTtlAction decNwTtlAction = new DecNwTtlAction(1);
1903 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
1904
1905 if (php) {
1906 actions.add(copyTtlInAction);
1907 if (Bos) {
1908 actions.add(popActionBos);
1909 actions.add(decNwTtlAction);
1910 }
1911 else {
1912 actions.add(popAction);
1913 actions.add(decMplsTtlAction);
1914 }
1915 }
1916 else {
1917 actions.add(decMplsTtlAction);
1918 }
1919
Sangho Shin402354e2014-10-27 16:53:05 -07001920 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
1921 getSwId(sw.getDpid().toString()));
1922 if ((sw13 instanceof OFSwitchImplDellOSR) && isTransitRouter(sw) && !php) {
Sangho Shine842cad2014-10-24 16:07:35 -07001923 PortNumber port = pickOnePort(sw, fwdSws);
1924 if (port == null) {
1925 log.warn("Failed to get a port from NeightborSet");
1926 return null;
1927 }
1928 OutputAction outputAction = new OutputAction(port);
1929 Switch destSwitch =
1930 mutableTopology.getSwitch(new Dpid(fwdSws.get(0)));
1931 MacAddress srcMac =
1932 MacAddress.of(sw.getStringAttribute("routerMac"));
1933 MacAddress dstMac =
1934 MacAddress.of(destSwitch.getStringAttribute("routerMac"));
1935 SetSAAction setSAAction = new SetSAAction(srcMac);
1936 SetDAAction setDAAction = new SetDAAction(dstMac);
1937 actions.add(outputAction);
1938 actions.add(setSAAction);
1939 actions.add(setDAAction);
1940 }
1941 else {
1942 GroupAction groupAction = new GroupAction();
1943 for (String dpid: fwdSws)
1944 groupAction.addSwitch(new Dpid(dpid));
1945 actions.add(groupAction);
1946 }
1947
1948 MatchAction matchAction = new MatchAction(new MatchActionId(matchActionId++),
1949 new SwitchPort((long) 0, (short) 0), mplsMatch, actions);
1950 Operator operator = Operator.ADD;
1951 MatchActionOperationEntry maEntry =
1952 new MatchActionOperationEntry(operator, matchAction);
1953
1954 return maEntry;
1955 }
1956
1957 /**
1958 * Pick a router from the neighbor set and return the port
1959 * connected to the router.
1960 *
1961 * @param sw source switch
1962 * @param fwdSwDpids neighbor set of the switch
1963 * @return PortNumber connected to one of the neighbors
1964 */
1965 private PortNumber pickOnePort(Switch sw, List<String> fwdSwDpids) {
1966 for (Link link: sw.getOutgoingLinks()) {
1967 if (link.getDstSwitch().getDpid().toString().equals(fwdSwDpids.get(0)))
1968 return link.getSrcPort().getNumber();
1969 }
1970
1971 return null;
1972 }
1973
1974 /**
1975 * check if the router is the transit router or not
1976 *
1977 * @param sw router switch to check
1978 * @return true if the switch is the transit router, false otherwise
1979 */
1980 private boolean isTransitRouter(Switch sw) {
1981 int i = 0;
1982 for(Switch neighbor: sw.getNeighbors()) {
1983 i++;
1984 }
1985 if (i > 1)
1986 return true;
1987 else
1988 return false;
1989 }
1990
1991 /**
Sangho Shin55908712014-10-27 15:16:48 -07001992 * Get the forwarding Switch DPIDs to send packets to a node.
1993 * If ECMP in transit routers is not supported, only one switch needs to be
1994 * selected as the neighbor set to forward packets to.
Sangho Shin15273b62014-10-16 22:22:05 -07001995 *
Sangho Shin7330c032014-10-20 10:34:51 -07001996 * @param srcSw source switch
1997 * @param nodeId destination node Id
1998 * @return list of switch DPID to forward packets to
Sangho Shin15273b62014-10-16 22:22:05 -07001999 */
Sangho Shin7330c032014-10-20 10:34:51 -07002000 private List<Dpid> getForwardingSwitchForNodeId(Switch srcSw, String nodeId) {
Sangho Shin15273b62014-10-16 22:22:05 -07002001
Sangho Shin7330c032014-10-20 10:34:51 -07002002 List<Dpid> fwdSws = new ArrayList<Dpid>();
2003 Switch destSw = null;
Sangho Shin15273b62014-10-16 22:22:05 -07002004
Sangho Shin7330c032014-10-20 10:34:51 -07002005 destSw = getSwitchFromNodeId(nodeId);
2006
2007 if (destSw == null) {
2008 log.debug("Cannot find the switch with ID {}", nodeId);
2009 return null;
2010 }
2011
2012 ECMPShortestPathGraph ecmpSPG = new ECMPShortestPathGraph(srcSw);
2013
2014 HashMap<Integer, HashMap<Switch, ArrayList<ArrayList<Dpid>>>> switchVia =
2015 ecmpSPG.getAllLearnedSwitchesAndVia();
2016 for (Integer itrIdx : switchVia.keySet()) {
2017 HashMap<Switch, ArrayList<ArrayList<Dpid>>> swViaMap =
2018 switchVia.get(itrIdx);
2019 for (Switch targetSw : swViaMap.keySet()) {
2020 String destSwDpid = destSw.getDpid().toString();
2021 if (targetSw.getDpid().toString().equals(destSwDpid)) {
2022 for (ArrayList<Dpid> via : swViaMap.get(targetSw)) {
2023 if (via.isEmpty()) {
2024 fwdSws.add(destSw.getDpid());
2025 }
2026 else {
Sangho Shina000c612014-10-21 14:17:59 -07002027 Dpid firstVia = via.get(via.size()-1);
2028 fwdSws.add(firstVia);
Sangho Shinf66aa262014-10-27 16:03:42 -07002029 IOF13Switch targetSw13 = (IOF13Switch)floodlightProvider.getMasterSwitch(
2030 getSwId(targetSw.getDpid().toString()));
2031 if (targetSw13 instanceof OFSwitchImplDellOSR &&
Sangho Shin55908712014-10-27 15:16:48 -07002032 isTransitRouter(targetSw) &&
2033 isTransitRouter(mutableTopology.getSwitch(firstVia))) {
2034 return fwdSws;
2035 }
Sangho Shin7330c032014-10-20 10:34:51 -07002036 }
2037 }
2038 }
2039 }
2040 }
2041
2042 return fwdSws;
Sangho Shin15273b62014-10-16 22:22:05 -07002043 }
2044
Sangho Shin7330c032014-10-20 10:34:51 -07002045 /**
2046 * Get switch for the node Id specified
2047 *
2048 * @param nodeId node ID for switch
2049 * @return Switch
2050 */
2051 private Switch getSwitchFromNodeId(String nodeId) {
Fahad Naeem Khan4444b952014-10-18 22:30:50 -07002052
Sangho Shin7330c032014-10-20 10:34:51 -07002053 for (Switch sw : mutableTopology.getSwitches()) {
2054 String id = sw.getStringAttribute("nodeSid");
2055 if (id.equals(nodeId)) {
2056 return sw;
2057 }
2058 }
2059
2060 return null;
2061 }
Fahad Naeem Khan4444b952014-10-18 22:30:50 -07002062
Sangho Shin43cee112014-09-25 16:43:34 -07002063 /**
Sangho Shin7330c032014-10-20 10:34:51 -07002064 * Convert a string DPID to its Switch Id (integer)
Sangho Shinfbc572c2014-10-02 16:37:05 -07002065 *
Sangho Shin7330c032014-10-20 10:34:51 -07002066 * @param dpid
2067 * @return
Sangho Shin43cee112014-09-25 16:43:34 -07002068 */
Sangho Shin7330c032014-10-20 10:34:51 -07002069 private long getSwId(String dpid) {
Sangho Shin43cee112014-09-25 16:43:34 -07002070
Sangho Shin7330c032014-10-20 10:34:51 -07002071 long swId = 0;
Sangho Shin43cee112014-09-25 16:43:34 -07002072
Sangho Shin7330c032014-10-20 10:34:51 -07002073 String swIdHexStr = "0x"+dpid.substring(dpid.lastIndexOf(":") + 1);
2074 if (swIdHexStr != null)
2075 swId = Integer.decode(swIdHexStr);
Sangho Shin43cee112014-09-25 16:43:34 -07002076
Sangho Shin7330c032014-10-20 10:34:51 -07002077 return swId;
2078 }
Sangho Shin43cee112014-09-25 16:43:34 -07002079
Sangho Shin7330c032014-10-20 10:34:51 -07002080 /**
2081 * Check if the switch is the edge router or not.
2082 *
2083 * @param dpid Dpid of the switch to check
2084 * @return true if it is an edge router, otherwise false
2085 */
2086 private boolean IsEdgeRouter(String dpid) {
Sangho Shin0df01982014-09-25 17:11:18 -07002087
Sangho Shin7330c032014-10-20 10:34:51 -07002088 for (Switch sw : mutableTopology.getSwitches()) {
2089 String dpidStr = sw.getDpid().toString();
2090 if (dpid.equals(dpidStr)) {
2091 /*
2092 String subnetInfo = sw.getStringAttribute("subnets");
2093 if (subnetInfo == null || subnetInfo.equals("[]")) {
2094 return false;
2095 }
2096 else
2097 return true;
2098 */
2099 String isEdge = sw.getStringAttribute("isEdgeRouter");
2100 if (isEdge != null) {
2101 if (isEdge.equals("true"))
2102 return true;
2103 else
2104 return false;
2105 }
Sangho Shin43cee112014-09-25 16:43:34 -07002106 }
2107 }
2108
Sangho Shin7330c032014-10-20 10:34:51 -07002109 return false;
Sangho Shineb083032014-09-22 16:11:34 -07002110 }
2111
2112 /**
2113 * Get MPLS label reading the config file
Sangho Shinfbc572c2014-10-02 16:37:05 -07002114 *
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002115 * @param dipid DPID of the switch
Sangho Shineb083032014-09-22 16:11:34 -07002116 * @return MPLS label for the switch
2117 */
Sangho Shin43cee112014-09-25 16:43:34 -07002118 private String getMplsLabel(String dpid) {
Sangho Shineb083032014-09-22 16:11:34 -07002119
2120 String mplsLabel = null;
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002121 for (Switch sw : mutableTopology.getSwitches()) {
Sangho Shin43cee112014-09-25 16:43:34 -07002122 String dpidStr = sw.getDpid().toString();
2123 if (dpid.equals(dpidStr)) {
Sangho Shineb083032014-09-22 16:11:34 -07002124 mplsLabel = sw.getStringAttribute("nodeSid");
2125 break;
Sangho Shin1aa93542014-09-22 09:49:44 -07002126 }
2127 }
2128
Sangho Shineb083032014-09-22 16:11:34 -07002129 return mplsLabel;
Sangho Shin1aa93542014-09-22 09:49:44 -07002130 }
2131
Sangho Shineb083032014-09-22 16:11:34 -07002132 /**
Sangho Shin1aa93542014-09-22 09:49:44 -07002133 * The function checks if given IP matches to the given subnet mask
Sangho Shinfbc572c2014-10-02 16:37:05 -07002134 *
Sangho Shin1aa93542014-09-22 09:49:44 -07002135 * @param addr - subnet address to match
2136 * @param addr1 - IP address to check
2137 * @return true if the IP address matches to the subnet, otherwise false
2138 */
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002139 public boolean netMatch(String addr, String addr1) { // addr is subnet
2140 // address and addr1 is
2141 // ip address. Function
2142 // will return true, if
2143 // addr1 is within
2144 // addr(subnet)
Sangho Shin1aa93542014-09-22 09:49:44 -07002145
2146 String[] parts = addr.split("/");
2147 String ip = parts[0];
2148 int prefix;
2149
2150 if (parts.length < 2) {
2151 prefix = 0;
2152 } else {
2153 prefix = Integer.parseInt(parts[1]);
2154 }
2155
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002156 Inet4Address a = null;
2157 Inet4Address a1 = null;
Sangho Shin1aa93542014-09-22 09:49:44 -07002158 try {
2159 a = (Inet4Address) InetAddress.getByName(ip);
2160 a1 = (Inet4Address) InetAddress.getByName(addr1);
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002161 } catch (UnknownHostException e) {
2162 }
Sangho Shin1aa93542014-09-22 09:49:44 -07002163
2164 byte[] b = a.getAddress();
2165 int ipInt = ((b[0] & 0xFF) << 24) |
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002166 ((b[1] & 0xFF) << 16) |
2167 ((b[2] & 0xFF) << 8) |
2168 ((b[3] & 0xFF) << 0);
Sangho Shin1aa93542014-09-22 09:49:44 -07002169
2170 byte[] b1 = a1.getAddress();
2171 int ipInt1 = ((b1[0] & 0xFF) << 24) |
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002172 ((b1[1] & 0xFF) << 16) |
2173 ((b1[2] & 0xFF) << 8) |
2174 ((b1[3] & 0xFF) << 0);
Sangho Shin1aa93542014-09-22 09:49:44 -07002175
2176 int mask = ~((1 << (32 - prefix)) - 1);
2177
2178 if ((ipInt & mask) == (ipInt1 & mask)) {
2179 return true;
2180 }
2181 else {
2182 return false;
2183 }
2184 }
Sangho Shineb083032014-09-22 16:11:34 -07002185
Sangho Shinac5ee2b2014-09-28 21:27:20 -07002186 /**
2187 * Add a routing rule for the host
Sangho Shinfbc572c2014-10-02 16:37:05 -07002188 *
Sangho Shinac5ee2b2014-09-28 21:27:20 -07002189 * @param sw - Switch to add the rule
2190 * @param hostIpAddress Destination host IP address
2191 * @param hostMacAddress Destination host MAC address
2192 */
Sangho Shineb083032014-09-22 16:11:34 -07002193 public void addRouteToHost(Switch sw, int hostIpAddress, byte[] hostMacAddress) {
2194 ipHandler.addRouteToHost(sw, hostIpAddress, hostMacAddress);
Sangho Shineb083032014-09-22 16:11:34 -07002195 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -07002196
Sangho Shin463bee52014-09-29 15:14:43 -07002197 /**
2198 * Add IP packet to a buffer queue
Sangho Shinfbc572c2014-10-02 16:37:05 -07002199 *
Sangho Shin463bee52014-09-29 15:14:43 -07002200 * @param ipv4
2201 */
Sangho Shin7330c032014-10-20 10:34:51 -07002202 public void addPacketToPacketBuffer(IPv4 ipv4) {
Sangho Shin61535402014-10-01 11:37:14 -07002203 ipPacketQueue.add(ipv4);
Sangho Shin463bee52014-09-29 15:14:43 -07002204 }
2205
2206 /**
2207 * Retrieve all packets whose destination is the given address.
Sangho Shinfbc572c2014-10-02 16:37:05 -07002208 *
Sangho Shin463bee52014-09-29 15:14:43 -07002209 * @param destIp Destination address of packets to retrieve
2210 */
2211 public List<IPv4> getIpPacketFromQueue(byte[] destIp) {
2212
2213 List<IPv4> bufferedPackets = new ArrayList<IPv4>();
2214
Sangho Shin61535402014-10-01 11:37:14 -07002215 if (!ipPacketQueue.isEmpty()) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002216 for (IPv4 ip : ipPacketQueue) {
Sangho Shin61535402014-10-01 11:37:14 -07002217 int dest = ip.getDestinationAddress();
2218 IPv4Address ip1 = IPv4Address.of(dest);
2219 IPv4Address ip2 = IPv4Address.of(destIp);
2220 if (ip1.equals(ip2)) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002221 bufferedPackets.add((IPv4) (ipPacketQueue.poll()).clone());
Sangho Shin463bee52014-09-29 15:14:43 -07002222 }
2223 }
2224 }
2225
2226 return bufferedPackets;
2227 }
2228
Sangho Shin7330c032014-10-20 10:34:51 -07002229 /**
2230 * Get MAC address to known hosts
2231 *
2232 * @param destinationAddress IP address to get MAC address
2233 * @return MAC Address to given IP address
2234 */
2235 public byte[] getMacAddressFromIpAddress(int destinationAddress) {
2236
2237 // Can't we get the host IP address from the TopologyService ??
2238
2239 Iterator<ArpEntry> iterator = arpEntries.iterator();
2240
2241 IPv4Address ipAddress = IPv4Address.of(destinationAddress);
2242 byte[] ipAddressInByte = ipAddress.getBytes();
2243
2244 while (iterator.hasNext()) {
2245 ArpEntry arpEntry = iterator.next();
2246 byte[] address = arpEntry.targetIpAddress;
2247
2248 IPv4Address a = IPv4Address.of(address);
2249 IPv4Address b = IPv4Address.of(ipAddressInByte);
2250
2251 if (a.equals(b)) {
2252 log.debug("Found an arp entry");
2253 return arpEntry.targetMacAddress;
2254 }
2255 }
2256
2257 return null;
2258 }
2259
2260 /**
2261 * Send an ARP request via ArpHandler
2262 *
2263 * @param destinationAddress
2264 * @param sw
2265 * @param inPort
2266 *
2267 */
2268 public void sendArpRequest(Switch sw, int destinationAddress, Port inPort) {
2269 arpHandler.sendArpRequest(sw, destinationAddress, inPort);
2270 }
2271
Sangho Shin7330c032014-10-20 10:34:51 -07002272 // ************************************
2273 // Test functions
2274 // ************************************
2275
Sangho Shin55d00e12014-10-20 12:13:07 -07002276 private void runTest() {
2277
2278 if (testMode == POLICY_ADD1) {
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07002279 Integer[] routeArray = {101, 105, 110};
2280 /*List<Dpid> routeList = new ArrayList<Dpid>();
Sangho Shin55d00e12014-10-20 12:13:07 -07002281 for (int i = 0; i < routeArray.length; i++) {
2282 Dpid dpid = getSwitchFromNodeId(routeArray[i]).getDpid();
2283 routeList.add(dpid);
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07002284 }*/
Sangho Shin55d00e12014-10-20 12:13:07 -07002285
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07002286 if (createTunnel("1", Arrays.asList(routeArray))) {
Sangho Shin55d00e12014-10-20 12:13:07 -07002287 IPv4Net srcIp = new IPv4Net("10.0.1.1/24");
2288 IPv4Net dstIp = new IPv4Net("10.1.2.1/24");
2289
2290 log.debug("Set the policy 1");
Sangho Shine020cc32014-10-20 13:28:02 -07002291 this.createPolicy("1", null, null, Ethernet.TYPE_IPV4, srcIp,
Sangho Shin55d00e12014-10-20 12:13:07 -07002292 dstIp, IPv4.PROTOCOL_ICMP, (short)-1, (short)-1, 10000,
Sangho Shine020cc32014-10-20 13:28:02 -07002293 "1");
Sangho Shin55d00e12014-10-20 12:13:07 -07002294 testMode = POLICY_ADD2;
Sangho Shin4b46bcd2014-10-20 15:48:47 -07002295 testTask.reschedule(5, TimeUnit.SECONDS);
Sangho Shin55d00e12014-10-20 12:13:07 -07002296 }
2297 else {
2298 // retry it
2299 testTask.reschedule(5, TimeUnit.SECONDS);
2300 }
2301 }
2302 else if (testMode == POLICY_ADD2) {
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07002303 Integer[] routeArray = {101, 102, 103, 104, 105, 108, 110};
Sangho Shin55d00e12014-10-20 12:13:07 -07002304
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07002305 if (createTunnel("2", Arrays.asList(routeArray))) {
Sangho Shin55d00e12014-10-20 12:13:07 -07002306 IPv4Net srcIp = new IPv4Net("10.0.1.1/24");
2307 IPv4Net dstIp = new IPv4Net("10.1.2.1/24");
2308
2309 log.debug("Set the policy 2");
Sangho Shine020cc32014-10-20 13:28:02 -07002310 this.createPolicy("2", null, null, Ethernet.TYPE_IPV4, srcIp,
Sangho Shin55d00e12014-10-20 12:13:07 -07002311 dstIp, IPv4.PROTOCOL_ICMP, (short)-1, (short)-1, 20000,
Sangho Shine020cc32014-10-20 13:28:02 -07002312 "2");
Fahad Naeem Khan95aa4012014-10-21 14:07:00 -07002313 //testMode = POLICY_REMOVE2;
2314 //testTask.reschedule(5, TimeUnit.SECONDS);
Sangho Shin55d00e12014-10-20 12:13:07 -07002315 }
2316 else {
2317 log.debug("Retry it");
2318 testTask.reschedule(5, TimeUnit.SECONDS);
2319 }
2320 }
2321 else if (testMode == POLICY_REMOVE2){
2322 log.debug("Remove the policy 2");
Sangho Shine020cc32014-10-20 13:28:02 -07002323 this.removePolicy("2");
Sangho Shin55d00e12014-10-20 12:13:07 -07002324 testMode = POLICY_REMOVE1;
Sangho Shin4b46bcd2014-10-20 15:48:47 -07002325 testTask.reschedule(5, TimeUnit.SECONDS);
Sangho Shin55d00e12014-10-20 12:13:07 -07002326 }
2327 else if (testMode == POLICY_REMOVE1){
2328 log.debug("Remove the policy 1");
Sangho Shine020cc32014-10-20 13:28:02 -07002329 this.removePolicy("1");
Sangho Shin55d00e12014-10-20 12:13:07 -07002330
Sangho Shin4b46bcd2014-10-20 15:48:47 -07002331 testMode = TUNNEL_REMOVE1;
2332 testTask.reschedule(5, TimeUnit.SECONDS);
2333 }
2334 else if (testMode == TUNNEL_REMOVE1) {
2335 log.debug("Remove the tunnel 1");
2336 this.removeTunnel("1");
2337
2338 testMode = TUNNEL_REMOVE2;
2339 testTask.reschedule(5, TimeUnit.SECONDS);
2340 }
2341 else if (testMode == TUNNEL_REMOVE2) {
2342 log.debug("Remove the tunnel 2");
2343 this.removeTunnel("2");
2344 log.debug("The end of test");
2345 }
Sangho Shin55d00e12014-10-20 12:13:07 -07002346 }
Sangho Shin7330c032014-10-20 10:34:51 -07002347
2348 private void runTest1() {
2349
2350 String dpid1 = "00:00:00:00:00:00:00:01";
2351 String dpid2 = "00:00:00:00:00:00:00:0a";
2352 Switch srcSw = mutableTopology.getSwitch(new Dpid(dpid1));
2353 Switch dstSw = mutableTopology.getSwitch(new Dpid(dpid2));
2354
2355 if (srcSw == null || dstSw == null) {
2356 testTask.reschedule(1, TimeUnit.SECONDS);
2357 log.debug("Switch is gone. Reschedule the test");
2358 return;
2359 }
2360
2361 String[] routeArray = {"101", "102", "105", "108", "110"};
2362 List<String> routeList = new ArrayList<String>();
2363 for (int i = 0; i < routeArray.length; i++)
2364 routeList.add(routeArray[i]);
2365
2366 List<String> optimizedRoute = this.getOptimizedPath(srcSw, dstSw, routeList);
2367
2368 log.debug("Test set is {}", routeList.toString());
2369 log.debug("Result set is {}", optimizedRoute.toString());
2370
2371
2372 }
2373
2374 /**
2375 * print tunnel info - used only for debugging.
2376 * @param targetSw
2377 *
2378 * @param fwdSwDpids
2379 * @param ids
2380 * @param tunnelId
2381 */
Sangho Shin6471d202014-10-23 10:59:36 -07002382 private void printTunnelInfo(String targetSw, String tunnelId,
Sangho Shin7330c032014-10-20 10:34:51 -07002383 List<String> ids, NeighborSet ns) {
2384 StringBuilder logStr = new StringBuilder("In switch " +
Sangho Shin6471d202014-10-23 10:59:36 -07002385 targetSw + ", create a tunnel " + tunnelId + " " + " of push ");
Sangho Shin7330c032014-10-20 10:34:51 -07002386 for (String id: ids)
2387 logStr.append(id + "-");
2388 logStr.append(" output to ");
2389 for (Dpid dpid: ns.getDpids())
2390 logStr.append(dpid + " - ");
2391
2392 log.debug(logStr.toString());
2393
2394 }
2395
2396 /**
2397 * Debugging function to print out the Match Action Entry
2398 * @param sw13
2399 *
2400 * @param maEntry
2401 */
2402 private void printMatchActionOperationEntry(
2403 IOF13Switch sw13, MatchActionOperationEntry maEntry) {
2404
2405 StringBuilder logStr = new StringBuilder("In switch " + sw13.getId() + ", ");
2406
2407 MatchAction ma = maEntry.getTarget();
2408 Match m = ma.getMatch();
2409 List<Action> actions = ma.getActions();
2410
2411 if (m instanceof Ipv4Match) {
2412 logStr.append("If the IP matches with ");
2413 IPv4Net ip = ((Ipv4Match) m).getDestination();
2414 logStr.append(ip.toString());
2415 logStr.append(" then ");
2416 }
2417 else if (m instanceof MplsMatch) {
2418 logStr.append("If the MPLS label matches with ");
2419 int mplsLabel = ((MplsMatch) m).getMplsLabel();
2420 logStr.append(mplsLabel);
2421 logStr.append(" then ");
2422 }
2423 else if (m instanceof PacketMatch) {
Sangho Shinc5a38a02014-10-28 16:09:38 -07002424 logStr.append("if the policy match is XXX then ");
Sangho Shin7330c032014-10-20 10:34:51 -07002425 }
2426
2427 logStr.append(" do { ");
2428 for (Action action : actions) {
2429 if (action instanceof CopyTtlInAction) {
2430 logStr.append("copy ttl In, ");
2431 }
2432 else if (action instanceof CopyTtlOutAction) {
2433 logStr.append("copy ttl Out, ");
2434 }
2435 else if (action instanceof DecMplsTtlAction) {
2436 logStr.append("Dec MPLS TTL , ");
2437 }
2438 else if (action instanceof GroupAction) {
2439 logStr.append("Forward packet to < ");
2440 NeighborSet dpids = ((GroupAction) action).getDpids();
2441 logStr.append(dpids.toString() + ",");
Sangho Shin7330c032014-10-20 10:34:51 -07002442 }
2443 else if (action instanceof PopMplsAction) {
2444 logStr.append("Pop MPLS label, ");
2445 }
2446 else if (action instanceof PushMplsAction) {
2447 logStr.append("Push MPLS label, ");
2448 }
2449 else if (action instanceof SetMplsIdAction) {
2450 int id = ((SetMplsIdAction) action).getMplsId();
2451 logStr.append("Set MPLS ID as " + id + ", ");
2452 }
2453 }
2454
2455 log.debug(logStr.toString());
2456
2457 }
2458
Sangho Shin7330c032014-10-20 10:34:51 -07002459 // ************************************
2460 // Unused classes and functions
2461 // ************************************
2462
2463 /**
2464 * Temporary class to to keep ARP entry
2465 *
2466 */
2467 private class ArpEntry {
2468
2469 byte[] targetMacAddress;
2470 byte[] targetIpAddress;
2471
2472 private ArpEntry(byte[] macAddress, byte[] ipAddress) {
2473 this.targetMacAddress = macAddress;
2474 this.targetIpAddress = ipAddress;
2475 }
2476 }
2477
2478 /**
2479 * This class is used only for link recovery optimization in
2480 * modifyEcmpRoutingRules() function.
2481 * TODO: please remove if the optimization is not used at all
2482 */
2483 private class SwitchPair {
2484 private Switch src;
2485 private Switch dst;
2486
2487 public SwitchPair(Switch src, Switch dst) {
2488 this.src = src;
2489 this.dst = dst;
2490 }
2491
2492 public Switch getSource() {
2493 return src;
2494 }
2495
2496 public Switch getDestination() {
2497 return dst;
2498 }
2499 }
2500
2501 /**
2502 * Update ARP Cache using ARP packets It is used to set destination MAC
2503 * address to forward packets to known hosts. But, it will be replace with
2504 * Host information of Topology service later.
2505 *
2506 * @param arp APR packets to use for updating ARP entries
2507 */
2508 public void updateArpCache(ARP arp) {
2509
2510 ArpEntry arpEntry = new ArpEntry(arp.getSenderHardwareAddress(),
2511 arp.getSenderProtocolAddress());
2512 // TODO: Need to check the duplication
2513 arpEntries.add(arpEntry);
2514 }
2515
2516 /**
2517 * Modify the routing rules for the lost links
2518 * - Recompute the path if the link failed is included in the path
2519 * (including src and dest).
2520 *
2521 * @param newLink
2522 */
2523 private void modifyEcmpRoutingRules(LinkData linkRemoved) {
2524
2525 //HashMap<Switch, SwitchPair> linksToRecompute = new HashMap<Switch, SwitchPair>();
2526 Set<SwitchPair> linksToRecompute = new HashSet<SwitchPair>();
2527
2528 for (ECMPShortestPathGraph ecmpSPG : graphs.values()) {
2529 Switch rootSw = ecmpSPG.getRootSwitch();
2530 HashMap<Integer, HashMap<Switch, ArrayList<Path>>> paths =
2531 ecmpSPG.getCompleteLearnedSwitchesAndPaths();
2532 for (HashMap<Switch, ArrayList<Path>> p: paths.values()) {
2533 for (Switch destSw: p.keySet()) {
2534 ArrayList<Path> path = p.get(destSw);
2535 if (checkPath(path, linkRemoved)) {
2536 boolean found = false;
2537 for (SwitchPair pair: linksToRecompute) {
2538 if (pair.getSource().getDpid() == rootSw.getDpid() &&
2539 pair.getSource().getDpid() == destSw.getDpid()) {
2540 found = true;
2541 }
2542 }
2543 if (!found) {
2544 linksToRecompute.add(new SwitchPair(rootSw, destSw));
2545 }
2546 }
2547 }
2548 }
2549 }
2550
2551 // Recompute the path for the specific route
2552 for (SwitchPair pair: linksToRecompute) {
2553
2554 log.debug("Recompute path from {} to {}", pair.getSource(), pair.getDestination());
2555 // We need the following function for optimization
2556 //ECMPShortestPathGraph ecmpSPG =
2557 // new ECMPShortestPathGraph(pair.getSource(), pair.getDestination());
2558 ECMPShortestPathGraph ecmpSPG =
2559 new ECMPShortestPathGraph(pair.getSource());
2560 populateEcmpRoutingRulesForPath(pair.getSource(), ecmpSPG, true);
2561 }
2562 }
2563
2564 /**
2565 * Optimize the mpls label
2566 * The feature will be used only for policy of "avoid a specific switch".
2567 * Check route to each router in route backward.
2568 * If there is only one route to the router and the routers are included in
2569 * the route, remove the id from the path.
2570 * A-B-C-D-E => A-B-C-D-E -> A-E
2571 * | | => A-B-H-I -> A-I
Sangho Shin5b8f5452014-10-20 11:46:01 -07002572 * F-G-H-I => A-D-I > A-D-I
Sangho Shin7330c032014-10-20 10:34:51 -07002573 */
2574 private List<String> getOptimizedPath(Switch srcSw, Switch dstSw, List<String> route) {
2575
2576 List<String> optimizedPath = new ArrayList<String>();
2577 optimizedPath.addAll(route);
2578 ECMPShortestPathGraph ecmpSPG = new ECMPShortestPathGraph(srcSw);
2579
2580 HashMap<Integer, HashMap<Switch, ArrayList<Path>>> paths =
2581 ecmpSPG.getCompleteLearnedSwitchesAndPaths();
2582 for (HashMap<Switch, ArrayList<Path>> p: paths.values()) {
2583 for (Switch s: p.keySet()) {
2584 if (s.getDpid().toString().equals(dstSw.getDpid().toString())) {
2585 ArrayList<Path> ecmpPaths = p.get(s);
2586 if (ecmpPaths!= null && ecmpPaths.size() == 1) {
2587 for (Path path: ecmpPaths) {
2588 for (LinkData link: path) {
2589 String srcId = getMplsLabel(link.getSrc().getDpid().toString());
2590 String dstId = getMplsLabel(link.getSrc().getDpid().toString());
2591 if (optimizedPath.contains(srcId)) {
2592 optimizedPath.remove(srcId);
2593 }
2594 if (optimizedPath.contains(dstId)) {
2595 optimizedPath.remove(dstId);
2596 }
2597 }
2598 }
2599 }
2600 }
2601 }
2602 }
2603
2604 return optimizedPath;
2605
2606 }
2607
2608 /**
2609 * Check if the path is affected from the link removed
2610 *
2611 * @param path Path to check
2612 * @param linkRemoved link removed
2613 * @return true if the path contains the link removed
2614 */
2615 private boolean checkPath(ArrayList<Path> path, LinkData linkRemoved) {
2616
2617 for (Path ppp: path) {
2618 // TODO: need to check if this is a bidirectional or
2619 // unidirectional
2620 for (LinkData link: ppp) {
2621 if (link.getDst().getDpid().equals(linkRemoved.getDst().getDpid()) &&
2622 link.getSrc().getDpid().equals(linkRemoved.getSrc().getDpid()))
2623 return true;
2624 }
2625 }
2626
2627 return false;
2628 }
Sangho Shin15273b62014-10-16 22:22:05 -07002629
2630
Sangho Shin2f263692014-09-15 14:09:41 -07002631}