blob: f352e4381d89fe7a477f80a7ca55c6b5610a5d02 [file] [log] [blame]
Sangho Shin2f263692014-09-15 14:09:41 -07001package net.onrc.onos.apps.segmentrouting;
2
Sangho Shin9c0f4c32014-09-26 16:02:38 -07003import java.io.IOException;
Sangho Shin1aa93542014-09-22 09:49:44 -07004import java.net.Inet4Address;
5import java.net.InetAddress;
6import java.net.UnknownHostException;
Sangho Shin2f263692014-09-15 14:09:41 -07007import java.util.ArrayList;
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07008import java.util.Arrays;
Sangho Shin2f263692014-09-15 14:09:41 -07009import java.util.Collection;
Srikanth Vavilapalli363f1dc2014-09-22 14:30:23 -070010import java.util.HashMap;
Sangho Shin5be3e532014-10-03 17:20:58 -070011import java.util.HashSet;
Sangho Shin2f263692014-09-15 14:09:41 -070012import java.util.Iterator;
13import java.util.List;
14import java.util.Map;
Sangho Shin5be3e532014-10-03 17:20:58 -070015import java.util.Set;
Sangho Shin61535402014-10-01 11:37:14 -070016import java.util.concurrent.ConcurrentLinkedQueue;
Sangho Shin11d4e0f2014-09-30 12:00:33 -070017import java.util.concurrent.ExecutionException;
Sangho Shin43cee112014-09-25 16:43:34 -070018import java.util.concurrent.ScheduledExecutorService;
19import java.util.concurrent.TimeUnit;
Sangho Shin11d4e0f2014-09-30 12:00:33 -070020import java.util.concurrent.TimeoutException;
Sangho Shin2f263692014-09-15 14:09:41 -070021
22import net.floodlightcontroller.core.IFloodlightProviderService;
Sangho Shin9c0f4c32014-09-26 16:02:38 -070023import net.floodlightcontroller.core.IOF13Switch;
Sangho Shin0df01982014-09-25 17:11:18 -070024import net.floodlightcontroller.core.IOF13Switch.NeighborSet;
Sangho Shin11d4e0f2014-09-30 12:00:33 -070025import net.floodlightcontroller.core.internal.OFBarrierReplyFuture;
Sangho Shin2f263692014-09-15 14:09:41 -070026import net.floodlightcontroller.core.module.FloodlightModuleContext;
27import net.floodlightcontroller.core.module.FloodlightModuleException;
28import net.floodlightcontroller.core.module.IFloodlightModule;
29import net.floodlightcontroller.core.module.IFloodlightService;
Sangho Shin43cee112014-09-25 16:43:34 -070030import net.floodlightcontroller.core.util.SingletonTask;
Sangho Shin7330c032014-10-20 10:34:51 -070031import net.floodlightcontroller.restserver.IRestApiService;
Sangho Shin43cee112014-09-25 16:43:34 -070032import net.floodlightcontroller.threadpool.IThreadPoolService;
Sangho Shin15273b62014-10-16 22:22:05 -070033import net.floodlightcontroller.util.MACAddress;
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070034import net.onrc.onos.api.packet.IPacketListener;
Sangho Shin2f263692014-09-15 14:09:41 -070035import net.onrc.onos.api.packet.IPacketService;
Fahad Naeem Khan4444b952014-10-18 22:30:50 -070036import net.onrc.onos.apps.segmentrouting.web.SegmentRoutingWebRoutable;
Sangho Shin2f263692014-09-15 14:09:41 -070037import net.onrc.onos.core.flowprogrammer.IFlowPusherService;
Sangho Shinfbc572c2014-10-02 16:37:05 -070038import net.onrc.onos.core.intent.Path;
Sangho Shin2f263692014-09-15 14:09:41 -070039import net.onrc.onos.core.main.config.IConfigInfoService;
Sangho Shin43cee112014-09-25 16:43:34 -070040import net.onrc.onos.core.matchaction.MatchAction;
41import net.onrc.onos.core.matchaction.MatchActionId;
42import net.onrc.onos.core.matchaction.MatchActionOperationEntry;
Sangho Shin5be3e532014-10-03 17:20:58 -070043import net.onrc.onos.core.matchaction.MatchActionOperations.Operator;
Sangho Shin43cee112014-09-25 16:43:34 -070044import net.onrc.onos.core.matchaction.action.Action;
45import net.onrc.onos.core.matchaction.action.CopyTtlInAction;
46import net.onrc.onos.core.matchaction.action.CopyTtlOutAction;
47import net.onrc.onos.core.matchaction.action.DecMplsTtlAction;
48import net.onrc.onos.core.matchaction.action.DecNwTtlAction;
49import net.onrc.onos.core.matchaction.action.GroupAction;
Sangho Shin6d3c2f02014-10-22 10:10:55 -070050import net.onrc.onos.core.matchaction.action.ModifyDstMacAction;
51import net.onrc.onos.core.matchaction.action.ModifySrcMacAction;
52import net.onrc.onos.core.matchaction.action.OutputAction;
Sangho Shin43cee112014-09-25 16:43:34 -070053import net.onrc.onos.core.matchaction.action.PopMplsAction;
54import net.onrc.onos.core.matchaction.action.PushMplsAction;
55import net.onrc.onos.core.matchaction.action.SetMplsIdAction;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -070056import net.onrc.onos.core.matchaction.match.Ipv4Match;
Sangho Shin43cee112014-09-25 16:43:34 -070057import net.onrc.onos.core.matchaction.match.Match;
58import net.onrc.onos.core.matchaction.match.MplsMatch;
Sangho Shin15273b62014-10-16 22:22:05 -070059import net.onrc.onos.core.matchaction.match.PacketMatch;
60import net.onrc.onos.core.matchaction.match.PacketMatchBuilder;
Sangho Shin2f263692014-09-15 14:09:41 -070061import net.onrc.onos.core.packet.ARP;
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070062import net.onrc.onos.core.packet.Ethernet;
63import net.onrc.onos.core.packet.IPv4;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070064import net.onrc.onos.core.topology.ITopologyListener;
Sangho Shin1aa93542014-09-22 09:49:44 -070065import net.onrc.onos.core.topology.ITopologyService;
Sangho Shinbce900e2014-10-07 17:13:23 -070066import net.onrc.onos.core.topology.Link;
Sangho Shinc8d2f592014-09-30 16:53:57 -070067import net.onrc.onos.core.topology.LinkData;
Sangho Shinbce900e2014-10-07 17:13:23 -070068import net.onrc.onos.core.topology.MastershipData;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070069import net.onrc.onos.core.topology.MutableTopology;
Sangho Shineb083032014-09-22 16:11:34 -070070import net.onrc.onos.core.topology.Port;
Sangho Shinc8d2f592014-09-30 16:53:57 -070071import net.onrc.onos.core.topology.PortData;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070072import net.onrc.onos.core.topology.Switch;
Sangho Shin5be3e532014-10-03 17:20:58 -070073import net.onrc.onos.core.topology.SwitchData;
Sangho Shin1aa93542014-09-22 09:49:44 -070074import net.onrc.onos.core.topology.TopologyEvents;
Srikanth Vavilapalli363f1dc2014-09-22 14:30:23 -070075import net.onrc.onos.core.util.Dpid;
Sangho Shin43cee112014-09-25 16:43:34 -070076import net.onrc.onos.core.util.IPv4Net;
Sangho Shin6d3c2f02014-10-22 10:10:55 -070077import net.onrc.onos.core.util.PortNumber;
Sangho Shin43cee112014-09-25 16:43:34 -070078import net.onrc.onos.core.util.SwitchPort;
Sangho Shin2f263692014-09-15 14:09:41 -070079
Sangho Shin43cee112014-09-25 16:43:34 -070080import org.json.JSONArray;
81import org.json.JSONException;
Saurav Dasa962a692014-10-17 14:52:38 -070082import org.projectfloodlight.openflow.protocol.OFBarrierReply;
Saurav Dasbc594a42014-09-25 20:13:50 -070083import org.projectfloodlight.openflow.types.EthType;
Sangho Shin2f263692014-09-15 14:09:41 -070084import org.projectfloodlight.openflow.types.IPv4Address;
85import org.slf4j.Logger;
86import org.slf4j.LoggerFactory;
87
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070088public class SegmentRoutingManager implements IFloodlightModule,
Srikanth Vavilapalli8c49db72014-10-20 13:35:08 -070089 ITopologyListener, IPacketListener, ISegmentRoutingService {
Sangho Shin2f263692014-09-15 14:09:41 -070090
91 private static final Logger log = LoggerFactory
92 .getLogger(SegmentRoutingManager.class);
Sangho Shin23f898d2014-10-13 16:54:00 -070093
Fahad Naeem Khan5b558f22014-10-16 10:35:20 -070094 private ITopologyService topologyService;
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070095 private IPacketService packetService;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070096 private MutableTopology mutableTopology;
Sangho Shin61535402014-10-01 11:37:14 -070097 private ConcurrentLinkedQueue<IPv4> ipPacketQueue;
Fahad Naeem Khan4444b952014-10-18 22:30:50 -070098 private IRestApiService restApi;
Sangho Shin2f263692014-09-15 14:09:41 -070099 private List<ArpEntry> arpEntries;
Sangho Shineb083032014-09-22 16:11:34 -0700100 private ArpHandler arpHandler;
101 private GenericIpHandler ipHandler;
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700102 private IcmpHandler icmpHandler;
Sangho Shin43cee112014-09-25 16:43:34 -0700103 private IThreadPoolService threadPool;
104 private SingletonTask discoveryTask;
Sangho Shin23f898d2014-10-13 16:54:00 -0700105 private SingletonTask linkAddTask;
Sangho Shin15273b62014-10-16 22:22:05 -0700106 private SingletonTask testTask;
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700107 private IFloodlightProviderService floodlightProvider;
Sangho Shin2f263692014-09-15 14:09:41 -0700108
Sangho Shinfbc572c2014-10-02 16:37:05 -0700109 private HashMap<Switch, ECMPShortestPathGraph> graphs;
Sangho Shin23f898d2014-10-13 16:54:00 -0700110 private HashMap<String, LinkData> linksDown;
111 private HashMap<String, LinkData> linksToAdd;
Sangho Shin5be3e532014-10-03 17:20:58 -0700112 private ConcurrentLinkedQueue<TopologyEvents> topologyEventQueue;
Sangho Shine020cc32014-10-20 13:28:02 -0700113 private HashMap<String, PolicyInfo> policyTable;
Sangho Shin81655442014-10-20 14:22:46 -0700114 private HashMap<String, TunnelInfo> tunnelTable;
Sangho Shin6471d202014-10-23 10:59:36 -0700115 private HashMap<Integer, HashMap<Integer, List<Integer>>> adjacencySidTable;
Sangho Shin5b8f5452014-10-20 11:46:01 -0700116
117 private int testMode = 0;
118
Sangho Shinbce900e2014-10-07 17:13:23 -0700119
120 private int numOfEvents = 0;
121 private int numOfEventProcess = 0;
122 private int numOfPopulation = 0;
Sangho Shin99918bd2014-10-08 15:52:35 -0700123 private long matchActionId = 0L;
Sangho Shin58182672014-10-21 13:23:38 -0700124
Sangho Shin23f898d2014-10-13 16:54:00 -0700125 private final int DELAY_TO_ADD_LINK = 10;
Sangho Shin15273b62014-10-16 22:22:05 -0700126 private final int MAX_NUM_LABELS = 3;
Sangho Shinfbc572c2014-10-02 16:37:05 -0700127
Sangho Shin5b8f5452014-10-20 11:46:01 -0700128 private final int POLICY_ADD1 = 1;
129 private final int POLICY_ADD2 = 2;
130 private final int POLICY_REMOVE1 = 3;
131 private final int POLICY_REMOVE2 = 4;
Sangho Shin4b46bcd2014-10-20 15:48:47 -0700132 private final int TUNNEL_REMOVE1 = 5;
133 private final int TUNNEL_REMOVE2 = 6;
Sangho Shin5b8f5452014-10-20 11:46:01 -0700134
135
Sangho Shin7330c032014-10-20 10:34:51 -0700136 // ************************************
137 // IFloodlightModule implementation
138 // ************************************
139
Sangho Shin2f263692014-09-15 14:09:41 -0700140 @Override
141 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Srikanth Vavilapalli8c49db72014-10-20 13:35:08 -0700142 Collection<Class<? extends IFloodlightService>> l = new ArrayList<>();
143 l.add(ISegmentRoutingService.class);
144 return l;
Sangho Shin2f263692014-09-15 14:09:41 -0700145 }
146
147 @Override
148 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Srikanth Vavilapalli8c49db72014-10-20 13:35:08 -0700149 Map<Class<? extends IFloodlightService>, IFloodlightService> m = new HashMap<>();
150 m.put(ISegmentRoutingService.class, this);
151 return m;
Sangho Shin2f263692014-09-15 14:09:41 -0700152 }
153
154 @Override
155 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
156 Collection<Class<? extends IFloodlightService>> l = new ArrayList<Class<? extends IFloodlightService>>();
157
158 l.add(IFloodlightProviderService.class);
159 l.add(IConfigInfoService.class);
160 l.add(ITopologyService.class);
161 l.add(IPacketService.class);
162 l.add(IFlowPusherService.class);
163 l.add(ITopologyService.class);
Fahad Naeem Khan4444b952014-10-18 22:30:50 -0700164 l.add(IRestApiService.class);
Sangho Shin2f263692014-09-15 14:09:41 -0700165
166 return l;
167
168 }
169
170 @Override
171 public void init(FloodlightModuleContext context) throws FloodlightModuleException {
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700172 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Sangho Shineb083032014-09-22 16:11:34 -0700173 arpHandler = new ArpHandler(context, this);
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700174 icmpHandler = new IcmpHandler(context, this);
Sangho Shineb083032014-09-22 16:11:34 -0700175 ipHandler = new GenericIpHandler(context, this);
Sangho Shin2f263692014-09-15 14:09:41 -0700176 arpEntries = new ArrayList<ArpEntry>();
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700177 topologyService = context.getServiceImpl(ITopologyService.class);
Sangho Shin43cee112014-09-25 16:43:34 -0700178 threadPool = context.getServiceImpl(IThreadPoolService.class);
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700179 mutableTopology = topologyService.getTopology();
Sangho Shin61535402014-10-01 11:37:14 -0700180 ipPacketQueue = new ConcurrentLinkedQueue<IPv4>();
Sangho Shinfbc572c2014-10-02 16:37:05 -0700181 graphs = new HashMap<Switch, ECMPShortestPathGraph>();
Sangho Shin23f898d2014-10-13 16:54:00 -0700182 linksDown = new HashMap<String, LinkData>();
183 linksToAdd = new HashMap<String, LinkData>();
Sangho Shin5be3e532014-10-03 17:20:58 -0700184 topologyEventQueue = new ConcurrentLinkedQueue<TopologyEvents>();
Sangho Shin15273b62014-10-16 22:22:05 -0700185 packetService = context.getServiceImpl(IPacketService.class);
Fahad Naeem Khan4444b952014-10-18 22:30:50 -0700186 restApi = context.getServiceImpl(IRestApiService.class);
Sangho Shine020cc32014-10-20 13:28:02 -0700187 policyTable = new HashMap<String, PolicyInfo>();
Sangho Shin81655442014-10-20 14:22:46 -0700188 tunnelTable = new HashMap<String, TunnelInfo>();
Sangho Shin6471d202014-10-23 10:59:36 -0700189 adjacencySidTable = new HashMap<Integer,HashMap<Integer, List<Integer>>>();
Sangho Shin2f263692014-09-15 14:09:41 -0700190
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700191 packetService.registerPacketListener(this);
Sangho Shin15273b62014-10-16 22:22:05 -0700192 topologyService.addListener(this, false);
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700193
Sangho Shin99918bd2014-10-08 15:52:35 -0700194
Sangho Shin2f263692014-09-15 14:09:41 -0700195 }
196
197 @Override
198 public void startUp(FloodlightModuleContext context) throws FloodlightModuleException {
Sangho Shinc8d2f592014-09-30 16:53:57 -0700199 ScheduledExecutorService ses = threadPool.getScheduledExecutor();
Fahad Naeem Khan4444b952014-10-18 22:30:50 -0700200 restApi.addRestletRoutable(new SegmentRoutingWebRoutable());
Sangho Shin2f263692014-09-15 14:09:41 -0700201
Sangho Shinc8d2f592014-09-30 16:53:57 -0700202 discoveryTask = new SingletonTask(ses, new Runnable() {
203 @Override
204 public void run() {
Sangho Shin5be3e532014-10-03 17:20:58 -0700205 handleTopologyChangeEvents();
Sangho Shinc8d2f592014-09-30 16:53:57 -0700206 }
207 });
Sangho Shin23f898d2014-10-13 16:54:00 -0700208
209 linkAddTask = new SingletonTask(ses, new Runnable() {
210 @Override
211 public void run() {
212 delayedAddLink();
213 }
214 });
215
Sangho Shin15273b62014-10-16 22:22:05 -0700216 testTask = new SingletonTask(ses, new Runnable() {
217 @Override
218 public void run() {
219 runTest();
220 }
221 });
222
Sangho Shin5b8f5452014-10-20 11:46:01 -0700223 testMode = POLICY_ADD1;
Sangho Shin204b9972014-10-22 11:08:10 -0700224 //testTask.reschedule(20, TimeUnit.SECONDS);
Sangho Shin2f263692014-09-15 14:09:41 -0700225 }
226
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700227 @Override
228 public void receive(Switch sw, Port inPort, Ethernet payload) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700229 if (payload.getEtherType() == Ethernet.TYPE_ARP)
230 arpHandler.processPacketIn(sw, inPort, payload);
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700231 if (payload.getEtherType() == Ethernet.TYPE_IPV4) {
Sangho Shin7330c032014-10-20 10:34:51 -0700232 addPacketToPacketBuffer((IPv4) payload.getPayload());
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700233 if (((IPv4) payload.getPayload()).getProtocol() == IPv4.PROTOCOL_ICMP)
234 icmpHandler.processPacketIn(sw, inPort, payload);
235 else
236 ipHandler.processPacketIn(sw, inPort, payload);
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700237 }
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700238 else {
239 log.debug("{}", payload.toString());
240 }
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700241 }
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700242
Sangho Shin2f263692014-09-15 14:09:41 -0700243
Sangho Shin7330c032014-10-20 10:34:51 -0700244 // ************************************
245 // Topology event handlers
246 // ************************************
Sangho Shineb083032014-09-22 16:11:34 -0700247
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700248 /**
249 * Topology events that have been generated.
Sangho Shinfbc572c2014-10-02 16:37:05 -0700250 *
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700251 * @param topologyEvents the generated Topology Events
252 * @see TopologyEvents
253 */
254 public void topologyEvents(TopologyEvents topologyEvents)
255 {
Sangho Shin5be3e532014-10-03 17:20:58 -0700256 topologyEventQueue.add(topologyEvents);
Sangho Shinbce900e2014-10-07 17:13:23 -0700257 discoveryTask.reschedule(100, TimeUnit.MILLISECONDS);
Sangho Shin5be3e532014-10-03 17:20:58 -0700258 }
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700259
Sangho Shin23f898d2014-10-13 16:54:00 -0700260 /**
261 * Process the multiple topology events with some delay (100MS at most for now)
262 *
263 */
Sangho Shin5be3e532014-10-03 17:20:58 -0700264 private void handleTopologyChangeEvents() {
Sangho Shinbce900e2014-10-07 17:13:23 -0700265 numOfEventProcess ++;
266
Sangho Shin51625342014-10-17 09:30:48 -0700267 Collection<LinkData> linkEntriesAddedAll = new ArrayList<LinkData>();
268 Collection<PortData> portEntriesAddedAll = new ArrayList<PortData>();
269 Collection<PortData> portEntriesRemovedAll = new ArrayList<PortData>();
270 Collection<LinkData> linkEntriesRemovedAll = new ArrayList<LinkData>();
271 Collection<SwitchData> switchAddedAll = new ArrayList<SwitchData>();
272 Collection<SwitchData> switchRemovedAll = new ArrayList<SwitchData>();
273 Collection<MastershipData> mastershipRemovedAll = new ArrayList<MastershipData>();
Sangho Shinbce900e2014-10-07 17:13:23 -0700274
Sangho Shin5be3e532014-10-03 17:20:58 -0700275 while (!topologyEventQueue.isEmpty()) {
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700276 // We should handle the events in the order of when they happen
277 // TODO: We need to simulate the final results of multiple events
278 // and shoot only the final state.
279 // Ex: link s1-s2 down, link s1-s2 up --> Do nothing
280 // Ex: ink s1-s2 up, s1-p1,p2 down --> link s1-s2 down
Sangho Shin51625342014-10-17 09:30:48 -0700281
Sangho Shin5be3e532014-10-03 17:20:58 -0700282 TopologyEvents topologyEvents = topologyEventQueue.poll();
Sangho Shin51625342014-10-17 09:30:48 -0700283
284 Collection<LinkData> linkEntriesAdded = topologyEvents.getAddedLinkDataEntries();
285 Collection<PortData> portEntriesAdded = topologyEvents.getAddedPortDataEntries();
286 Collection<PortData> portEntriesRemoved = topologyEvents.getRemovedPortDataEntries();
287 Collection<LinkData> linkEntriesRemoved = topologyEvents.getRemovedLinkDataEntries();
288 Collection<SwitchData> switchAdded = topologyEvents.getAddedSwitchDataEntries();
289 Collection<SwitchData> switchRemoved = topologyEvents.getRemovedSwitchDataEntries();
290 Collection<MastershipData> mastershipRemoved = topologyEvents.getRemovedMastershipDataEntries();
291
292 linkEntriesAddedAll.addAll(linkEntriesAdded);
293 portEntriesAddedAll.addAll(portEntriesAdded);
294 portEntriesRemovedAll.addAll(portEntriesRemoved);
295 linkEntriesRemovedAll.addAll(linkEntriesRemoved);
296 switchAddedAll.addAll(switchAdded);
297 switchRemovedAll.addAll(switchRemoved);
298 mastershipRemovedAll.addAll(mastershipRemoved);
Sangho Shinbce900e2014-10-07 17:13:23 -0700299 numOfEvents++;
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700300
301 if (!portEntriesRemoved.isEmpty()) {
302 processPortRemoval(portEntriesRemoved);
303 }
304
305 if (!linkEntriesRemoved.isEmpty()) {
306 processLinkRemoval(linkEntriesRemoved);
307 }
308
309 if (!switchRemoved.isEmpty()) {
310 processSwitchRemoved(switchRemoved);
311 }
312
313 if (!mastershipRemoved.isEmpty()) {
Sangho Shin23f898d2014-10-13 16:54:00 -0700314 log.debug("Mastership is removed. Check if ports are down also.");
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700315 }
316
317 if (!linkEntriesAdded.isEmpty()) {
Sangho Shin23f898d2014-10-13 16:54:00 -0700318 processLinkAdd(linkEntriesAdded, false);
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700319 }
320
321 if (!portEntriesAdded.isEmpty()) {
322 processPortAdd(portEntriesAdded);
323 }
324
325 if (!switchAdded.isEmpty()) {
326 processSwitchAdd(switchAdded);
327 }
Sangho Shin51625342014-10-17 09:30:48 -0700328
Sangho Shinbce900e2014-10-07 17:13:23 -0700329 }
330
Sangho Shin23f898d2014-10-13 16:54:00 -0700331 // TODO: 100ms is enough to check both mastership removed events
332 // and the port removed events? What if the PORT_STATUS packets comes late?
Sangho Shin51625342014-10-17 09:30:48 -0700333 if (!mastershipRemovedAll.isEmpty()) {
334 if (portEntriesRemovedAll.isEmpty()) {
Saurav Das82e62972014-10-16 14:53:57 -0700335 log.debug("Just mastership is removed. Do not do anthing.");
Sangho Shin23f898d2014-10-13 16:54:00 -0700336 }
337 else {
338 HashMap<String, MastershipData> mastershipToRemove =
339 new HashMap<String, MastershipData>();
Sangho Shin51625342014-10-17 09:30:48 -0700340 for (MastershipData ms: mastershipRemovedAll) {
341 for (PortData port: portEntriesRemovedAll) {
Sangho Shin23f898d2014-10-13 16:54:00 -0700342 // TODO: check ALL ports of the switch are dead ..
343 if (port.getDpid().equals(ms.getDpid())) {
344 mastershipToRemove.put(ms.getDpid().toString(), ms);
345 }
346 }
347 log.debug("Swtich {} is really down.", ms.getDpid());
348 }
349 processMastershipRemoved(mastershipToRemove.values());
350 }
351 }
352
Sangho Shinbce900e2014-10-07 17:13:23 -0700353 log.debug("num events {}, num of process {}, "
354 + "num of Population {}", numOfEvents, numOfEventProcess,
355 numOfPopulation);
356 }
357
358 /**
Sangho Shin99918bd2014-10-08 15:52:35 -0700359 * Process the SwitchAdded events from topologyMananger.
360 * It does nothing. When a switch is added, then link will be added too.
361 * LinkAdded event will handle process all re-computation.
362 *
363 * @param switchAdded
364 */
365 private void processSwitchAdd(Collection<SwitchData> switchAdded) {
366
367 }
368
369 /**
Sangho Shinbce900e2014-10-07 17:13:23 -0700370 * Remove all ports connected to the switch removed
371 *
372 * @param mastershipRemoved master switch info removed
373 */
374 private void processMastershipRemoved(Collection<MastershipData>
375 mastershipRemoved) {
376 for (MastershipData mastership: mastershipRemoved) {
377 Switch sw = mutableTopology.getSwitch(mastership.getDpid());
378 for (Link link: sw.getOutgoingLinks()) {
379 Port dstPort = link.getDstPort();
380 IOF13Switch dstSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
381 getSwId(dstPort.getDpid().toString()));
Sangho Shinc1b8dea2014-10-13 12:03:28 -0700382 if (dstSw != null) {
383 dstSw.removePortFromGroups(dstPort.getNumber());
384 log.debug("MasterSwitch {} is gone: remove port {}", sw.getDpid(), dstPort);
385 }
Sangho Shinbce900e2014-10-07 17:13:23 -0700386 }
Sangho Shin61535402014-10-01 11:37:14 -0700387 }
Sangho Shin23f898d2014-10-13 16:54:00 -0700388
389 linksToAdd.clear();
390 linksDown.clear();
Sangho Shin61535402014-10-01 11:37:14 -0700391 }
Sangho Shinc8d2f592014-09-30 16:53:57 -0700392
Sangho Shinbce900e2014-10-07 17:13:23 -0700393 /**
394 * Remove all ports connected to the switch removed
395 *
396 * @param switchRemoved Switch removed
397 */
Sangho Shin5be3e532014-10-03 17:20:58 -0700398 private void processSwitchRemoved(Collection<SwitchData> switchRemoved) {
Sangho Shin23f898d2014-10-13 16:54:00 -0700399 log.debug("SwitchRemoved event occurred !!!");
Sangho Shin5be3e532014-10-03 17:20:58 -0700400 }
401
Sangho Shin61535402014-10-01 11:37:14 -0700402 /**
Sangho Shin99918bd2014-10-08 15:52:35 -0700403 * Report ports added to driver
Sangho Shinfbc572c2014-10-02 16:37:05 -0700404 *
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700405 * @param portEntries
406 */
407 private void processPortAdd(Collection<PortData> portEntries) {
Sangho Shin99918bd2014-10-08 15:52:35 -0700408 // TODO: do we need to add ports with delay?
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700409 for (PortData port : portEntries) {
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700410 Dpid dpid = port.getDpid();
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700411
Sangho Shinfbc572c2014-10-02 16:37:05 -0700412 IOF13Switch sw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700413 getSwId(port.getDpid().toString()));
Sangho Shin815af0c2014-10-10 13:05:45 -0700414 if (sw != null) {
Sangho Shin721ca042014-10-09 13:03:40 -0700415 sw.addPortToGroups(port.getPortNumber());
Sangho Shin15273b62014-10-16 22:22:05 -0700416 //log.debug("Add port {} to switch {}", port, dpid);
Sangho Shin815af0c2014-10-10 13:05:45 -0700417 }
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700418 }
419 }
420
421 /**
422 * Reports ports of new links to driver and recalculate ECMP SPG
Sangho Shin23f898d2014-10-13 16:54:00 -0700423 * If the link to add was removed before, then we just schedule the add link
424 * event and do not recompute the path now.
Sangho Shinfbc572c2014-10-02 16:37:05 -0700425 *
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700426 * @param linkEntries
427 */
Sangho Shin23f898d2014-10-13 16:54:00 -0700428 private void processLinkAdd(Collection<LinkData> linkEntries, boolean delayed) {
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700429
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700430 for (LinkData link : linkEntries) {
Sangho Shin5be3e532014-10-03 17:20:58 -0700431
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700432 SwitchPort srcPort = link.getSrc();
433 SwitchPort dstPort = link.getDst();
434
Sangho Shin23f898d2014-10-13 16:54:00 -0700435 String key = srcPort.getDpid().toString() +
436 dstPort.getDpid().toString();
437 if (!delayed) {
438 if (linksDown.containsKey(key)) {
439 linksToAdd.put(key, link);
440 linksDown.remove(key);
441 linkAddTask.reschedule(DELAY_TO_ADD_LINK, TimeUnit.SECONDS);
442 log.debug("Add link {} with 5 sec delay", link);
443 // TODO: What if we have multiple events of add link:
444 // one is new link add, the other one is link up for
445 // broken link? ECMPSPG function cannot deal with it for now
446 return;
447 }
448 }
449 else {
450 if (linksDown.containsKey(key)) {
451 linksToAdd.remove(key);
452 log.debug("Do not add the link {}: it is down again!", link);
453 return;
454 }
455 }
456
Sangho Shinfbc572c2014-10-02 16:37:05 -0700457 IOF13Switch srcSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700458 getSwId(srcPort.getDpid().toString()));
Sangho Shinfbc572c2014-10-02 16:37:05 -0700459 IOF13Switch dstSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700460 getSwId(dstPort.getDpid().toString()));
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700461
Sangho Shin815af0c2014-10-10 13:05:45 -0700462 if ((srcSw == null) || (dstSw == null))
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700463 continue;
464
465 srcSw.addPortToGroups(srcPort.getPortNumber());
466 dstSw.addPortToGroups(dstPort.getPortNumber());
Sangho Shin5be3e532014-10-03 17:20:58 -0700467
Sangho Shin15273b62014-10-16 22:22:05 -0700468 //log.debug("Add a link port {} to switch {} to add link {}", srcPort, srcSw,
469 // link);
470 //log.debug("Add a link port {} to switch {} to add link {}", dstPort, dstSw,
471 // link);
Sangho Shin815af0c2014-10-10 13:05:45 -0700472
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700473 }
Sangho Shinbce900e2014-10-07 17:13:23 -0700474 populateEcmpRoutingRules(false);
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700475 }
476
477 /**
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700478 * Check if all links are gone b/w the two switches. If all links are gone,
479 * then we need to recalculate the path. Otherwise, just report link failure
480 * to the driver.
Sangho Shinfbc572c2014-10-02 16:37:05 -0700481 *
Sangho Shin61535402014-10-01 11:37:14 -0700482 * @param linkEntries
483 */
484 private void processLinkRemoval(Collection<LinkData> linkEntries) {
Sangho Shinbce900e2014-10-07 17:13:23 -0700485 boolean recomputationRequired = false;
486
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700487 for (LinkData link : linkEntries) {
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700488 SwitchPort srcPort = link.getSrc();
489 SwitchPort dstPort = link.getDst();
Sangho Shinc8d2f592014-09-30 16:53:57 -0700490
Sangho Shinfbc572c2014-10-02 16:37:05 -0700491 IOF13Switch srcSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700492 getSwId(srcPort.getDpid().toString()));
Sangho Shinfbc572c2014-10-02 16:37:05 -0700493 IOF13Switch dstSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700494 getSwId(dstPort.getDpid().toString()));
Sangho Shin815af0c2014-10-10 13:05:45 -0700495 if ((srcSw == null) || (dstSw == null))
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700496 /* If this link is not between two switches, ignore it */
497 continue;
Sangho Shin23f898d2014-10-13 16:54:00 -0700498
Srikanth Vavilapallibb47e782014-10-09 18:16:35 -0700499 srcSw.removePortFromGroups(srcPort.getPortNumber());
500 dstSw.removePortFromGroups(dstPort.getPortNumber());
Sangho Shin815af0c2014-10-10 13:05:45 -0700501 log.debug("Remove port {} from switch {}", srcPort, srcSw);
502 log.debug("Remove port {} from switch {}", dstPort, dstSw);
503
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700504 Switch srcSwitch = mutableTopology.getSwitch(srcPort.getDpid());
505 if (srcSwitch.getLinkToNeighbor(dstPort.getDpid()) == null) {
Sangho Shinbce900e2014-10-07 17:13:23 -0700506 // TODO: it is only for debugging purpose.
Sangho Shin99918bd2014-10-08 15:52:35 -0700507 // We just need to call populateEcmpRoutingRules() and return;
Sangho Shinbce900e2014-10-07 17:13:23 -0700508 recomputationRequired = true;
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700509 log.debug("All links are gone b/w {} and {}", srcPort.getDpid(),
Sangho Shin5be3e532014-10-03 17:20:58 -0700510 dstPort.getDpid());
Sangho Shinc8d2f592014-09-30 16:53:57 -0700511 }
Sangho Shin23f898d2014-10-13 16:54:00 -0700512
513 String key = link.getSrc().getDpid().toString()+
514 link.getDst().getDpid().toString();
515 if (!linksDown.containsKey(key)) {
516 linksDown.put(key, link);
517 }
Sangho Shinc8d2f592014-09-30 16:53:57 -0700518 }
Sangho Shinbce900e2014-10-07 17:13:23 -0700519
520 if (recomputationRequired)
521 populateEcmpRoutingRules(false);
Sangho Shin61535402014-10-01 11:37:14 -0700522 }
Sangho Shinc8d2f592014-09-30 16:53:57 -0700523
Sangho Shin61535402014-10-01 11:37:14 -0700524 /**
Sangho Shin3a5fcad2014-10-01 14:14:49 -0700525 * report ports removed to the driver immediately
Sangho Shinfbc572c2014-10-02 16:37:05 -0700526 *
Sangho Shin61535402014-10-01 11:37:14 -0700527 * @param portEntries
528 */
529 private void processPortRemoval(Collection<PortData> portEntries) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700530 for (PortData port : portEntries) {
Sangho Shin61535402014-10-01 11:37:14 -0700531 Dpid dpid = port.getDpid();
Sangho Shin61535402014-10-01 11:37:14 -0700532
Sangho Shinfbc572c2014-10-02 16:37:05 -0700533 IOF13Switch sw = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin61535402014-10-01 11:37:14 -0700534 getSwId(port.getDpid().toString()));
Sangho Shin815af0c2014-10-10 13:05:45 -0700535 if (sw != null) {
Sangho Shinfbc572c2014-10-02 16:37:05 -0700536 sw.removePortFromGroups(port.getPortNumber());
Sangho Shin815af0c2014-10-10 13:05:45 -0700537 log.debug("Remove port {} from switch {}", port, dpid);
538 }
Sangho Shin61535402014-10-01 11:37:14 -0700539 }
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700540 }
Sangho Shin1aa93542014-09-22 09:49:44 -0700541
542 /**
Sangho Shin7330c032014-10-20 10:34:51 -0700543 * Add the link immediately
544 * The function is scheduled when link add event happens and called
545 * DELAY_TO_ADD_LINK seconds after the event to avoid link flip-flop.
546 */
547 private void delayedAddLink() {
548
549 processLinkAdd(linksToAdd.values(), true);
550
551 }
552
553
554 // ************************************
555 // ECMP shorted path routing functions
556 // ************************************
557
558 /**
Sangho Shin43cee112014-09-25 16:43:34 -0700559 * Populate routing rules walking through the ECMP shortest paths
Sangho Shinfbc572c2014-10-02 16:37:05 -0700560 *
Sangho Shin99918bd2014-10-08 15:52:35 -0700561 * @param modified if true, it "modifies" the rules
Sangho Shin1aa93542014-09-22 09:49:44 -0700562 */
Sangho Shin5be3e532014-10-03 17:20:58 -0700563 private void populateEcmpRoutingRules(boolean modified) {
564 graphs.clear();
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700565 Iterable<Switch> switches = mutableTopology.getSwitches();
Sangho Shin43cee112014-09-25 16:43:34 -0700566 for (Switch sw : switches) {
567 ECMPShortestPathGraph ecmpSPG = new ECMPShortestPathGraph(sw);
Sangho Shinfbc572c2014-10-02 16:37:05 -0700568 graphs.put(sw, ecmpSPG);
569 //log.debug("ECMPShortestPathGraph is computed for switch {}",
570 // HexString.toHexString(sw.getDpid().value()));
Sangho Shin5be3e532014-10-03 17:20:58 -0700571 populateEcmpRoutingRulesForPath(sw, ecmpSPG, modified);
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700572
573 // Set adjacency routing rule for all switches
574 try {
575 populateAdjacencyncyRule(sw);
576 } catch (JSONException e) {
577 // TODO Auto-generated catch block
578 e.printStackTrace();
579 }
Sangho Shinfbc572c2014-10-02 16:37:05 -0700580 }
Sangho Shinbce900e2014-10-07 17:13:23 -0700581 numOfPopulation++;
Sangho Shinfbc572c2014-10-02 16:37:05 -0700582 }
Sangho Shin1aa93542014-09-22 09:49:44 -0700583
Sangho Shin204b9972014-10-22 11:08:10 -0700584 /**
585 * populate the MPLS rules to handle Adjacency IDs
586 *
587 * @param sw Switch
588 * @throws JSONException
589 */
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700590 private void populateAdjacencyncyRule(Switch sw) throws JSONException {
591 String adjInfo = sw.getStringAttribute("adjacencySids");
Sangho Shin204b9972014-10-22 11:08:10 -0700592 String nodeSidStr = sw.getStringAttribute("nodeSid");
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700593 String srcMac = sw.getStringAttribute("routerMac");
Sangho Shin204b9972014-10-22 11:08:10 -0700594 String autoAdjInfo = sw.getStringAttribute("autogenAdjSids");
595
Sangho Shinced05b62014-10-22 11:23:14 -0700596 if (autoAdjInfo == null || srcMac == null || nodeSidStr == null)
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700597 return;
598
Sangho Shinced05b62014-10-22 11:23:14 -0700599 // parse adjacency Id
Sangho Shincfef3922014-10-22 12:04:16 -0700600 HashMap<Integer, List<Integer>> adjacencyInfo = null;
Sangho Shinced05b62014-10-22 11:23:14 -0700601 if (adjInfo != null) {
Sangho Shincfef3922014-10-22 12:04:16 -0700602 adjacencyInfo = parseAdjacencySidInfo(adjInfo);
Sangho Shinced05b62014-10-22 11:23:14 -0700603 }
Sangho Shincfef3922014-10-22 12:04:16 -0700604 // parse auto generated adjacency Id
605 adjacencyInfo.putAll(parseAdjacencySidInfo(autoAdjInfo));
Sangho Shinced05b62014-10-22 11:23:14 -0700606
Sangho Shin6471d202014-10-23 10:59:36 -0700607 adjacencySidTable.put(Integer.parseInt(nodeSidStr), adjacencyInfo);
Sangho Shin204b9972014-10-22 11:08:10 -0700608
Sangho Shin6471d202014-10-23 10:59:36 -0700609 for (Integer adjId: adjacencyInfo.keySet()) {
610 List<Integer> ports = adjacencyInfo.get(adjId);
611 if (ports.size() == 1) {
612 setAdjacencyRuleOfOutput(sw, adjId, srcMac, ports.get(0));
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700613 }
614 else {
Sangho Shin6471d202014-10-23 10:59:36 -0700615 setAdjacencyRuleOfGroup(sw, adjId, ports);
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700616 }
Sangho Shin6471d202014-10-23 10:59:36 -0700617 }
618 }
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700619
Sangho Shin6471d202014-10-23 10:59:36 -0700620 /**
621 * Set Adjacency Rule to MPLS table for adjacency Ids attached to multiple
622 * ports
623 *
624 * @param sw Switch
625 * @param adjId Adjacency ID
626 * @param ports List of ports assigned to the Adjacency ID
627 */
628 private void setAdjacencyRuleOfGroup(Switch sw, Integer adjId, List<Integer> ports) {
629
630 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
631 getSwId(sw.getDpid().toString()));
632
633 int groupId = -1;
634 if (sw13 != null) {
635 List<PortNumber> portList = new ArrayList<PortNumber>();
636 for (Integer port: ports)
637 portList.add(PortNumber.uint32(port));
638 groupId = sw13.createGroup(new ArrayList<Integer>(), portList);
639 }
640
641 if (groupId < 0) {
642 log.debug("Failed to create a group at driver for adj ID {}", adjId);
643 }
644
645 pushAdjRule(sw, adjId, null, null, groupId, true);
646 pushAdjRule(sw, adjId, null, null, groupId, false);
647 }
648
649 /**
650 * Set Adjacency Rule to MPLS table for adjacency Ids attached to single port
651 *
652 * @param sw Switch
653 * @param adjId Adjacency ID
654 * @param ports List of ports assigned to the Adjacency ID
655 */
656 private void setAdjacencyRuleOfOutput(Switch sw, Integer adjId, String srcMac, Integer portNo) {
657
658 Dpid dstDpid = null;
659 for (Link link: sw.getOutgoingLinks()) {
660 if (link.getSrcPort().getPortNumber().value() == portNo) {
661 dstDpid = link.getDstPort().getDpid();
662 break;
663 }
664 }
665 if (dstDpid == null) {
666 log.debug("Cannot find the destination switch for the adjacency ID {}", adjId);
667 return;
668 }
669 Switch dstSw = mutableTopology.getSwitch(dstDpid);
670 String dstMac = null;
671 if (dstSw == null) {
672 log.debug("Cannot find SW {}", dstDpid.toString());
673 return;
674 }
675 else {
676 dstMac = dstSw.getStringAttribute("routerMac");
677 }
678
679 pushAdjRule(sw, adjId, srcMac, dstMac, portNo, true); // BoS = 1
680 pushAdjRule(sw, adjId, srcMac, dstMac, portNo, false); // BoS = 0
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700681
682 }
683
Sangho Shin204b9972014-10-22 11:08:10 -0700684 /**
685 * Push the MPLS rule for Adjacency ID
686 *
687 * @param sw Switch to push the rule
688 * @param id Adjacency ID
689 * @param srcMac source MAC address
690 * @param dstMac destination MAC address
691 * @param portNo port number assigned to the ID
692 * @param bos BoS option
693 */
Sangho Shin6471d202014-10-23 10:59:36 -0700694 private void pushAdjRule(Switch sw, int id, String srcMac, String dstMac,
695 int num, boolean bos) {
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700696
697 MplsMatch mplsMatch = new MplsMatch(id, bos);
698 List<Action> actions = new ArrayList<Action>();
699
700 if (bos) {
701 PopMplsAction popAction = new PopMplsAction(EthType.IPv4);
702 CopyTtlInAction copyTtlInAction = new CopyTtlInAction();
703 DecNwTtlAction decNwTtlAction = new DecNwTtlAction(1);
704 actions.add(copyTtlInAction);
705 actions.add(popAction);
706 actions.add(decNwTtlAction);
707 }
708 else {
709 PopMplsAction popAction = new PopMplsAction(EthType.MPLS_UNICAST);
710 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
711 actions.add(popAction);
712 actions.add(decMplsTtlAction);
713 }
714
Sangho Shin6471d202014-10-23 10:59:36 -0700715 // Output action
716 if (srcMac != null && dstMac != null) {
717 ModifyDstMacAction setDstAction = new ModifyDstMacAction(MACAddress.valueOf(srcMac));
718 ModifySrcMacAction setSrcAction = new ModifySrcMacAction(MACAddress.valueOf(dstMac));
719 OutputAction outportAction = new OutputAction(PortNumber.uint32(num));
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700720
Sangho Shin6471d202014-10-23 10:59:36 -0700721 actions.add(setDstAction);
722 actions.add(setSrcAction);
723 actions.add(outportAction);
724 }
725 // Group Action
726 else {
727 GroupAction groupAction = new GroupAction();
728 groupAction.setGroupId(num);
729 actions.add(groupAction);
730 }
Sangho Shin6d3c2f02014-10-22 10:10:55 -0700731
732 MatchAction matchAction = new MatchAction(new MatchActionId(matchActionId++),
733 new SwitchPort((long) 0, (short) 0), mplsMatch, actions);
734 Operator operator = Operator.ADD;
735 MatchActionOperationEntry maEntry =
736 new MatchActionOperationEntry(operator, matchAction);
737
738 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
739 getSwId(sw.getDpid().toString()));
740
741 if (sw13 != null) {
742 try {
743 //printMatchActionOperationEntry(sw, maEntry);
744 sw13.pushFlow(maEntry);
745 } catch (IOException e) {
746 e.printStackTrace();
747 }
748 }
749 }
750
Sangho Shin99918bd2014-10-08 15:52:35 -0700751 /**
752 * populate routing rules to forward packets from the switch given to
753 * all other switches.
754 *
755 * @param sw source switch
756 * @param ecmpSPG shortest path from the the source switch to all others
757 * @param modified modification flag
758 */
Sangho Shinfbc572c2014-10-02 16:37:05 -0700759 private void populateEcmpRoutingRulesForPath(Switch sw,
Sangho Shin5be3e532014-10-03 17:20:58 -0700760 ECMPShortestPathGraph ecmpSPG, boolean modified) {
Sangho Shin43cee112014-09-25 16:43:34 -0700761
Sangho Shinfbc572c2014-10-02 16:37:05 -0700762 HashMap<Integer, HashMap<Switch, ArrayList<ArrayList<Dpid>>>> switchVia =
763 ecmpSPG.getAllLearnedSwitchesAndVia();
764 for (Integer itrIdx : switchVia.keySet()) {
765 //log.debug("ECMPShortestPathGraph:Switches learned in "
766 // + "Iteration{} from switch {}:",
767 // itrIdx,
768 // HexString.toHexString(sw.getDpid().value()));
769 HashMap<Switch, ArrayList<ArrayList<Dpid>>> swViaMap =
770 switchVia.get(itrIdx);
771 for (Switch targetSw : swViaMap.keySet()) {
Sangho Shin5be3e532014-10-03 17:20:58 -0700772 //log.debug("ECMPShortestPathGraph:****switch {} via:",
773 // HexString.toHexString(targetSw.getDpid().value()));
Sangho Shinfbc572c2014-10-02 16:37:05 -0700774 String destSw = sw.getDpid().toString();
775 List<String> fwdToSw = new ArrayList<String>();
776
Sangho Shinfbc572c2014-10-02 16:37:05 -0700777 for (ArrayList<Dpid> via : swViaMap.get(targetSw)) {
Sangho Shin5be3e532014-10-03 17:20:58 -0700778 //log.debug("ECMPShortestPathGraph:******{}) {}", ++i, via);
Sangho Shinfbc572c2014-10-02 16:37:05 -0700779 if (via.isEmpty()) {
780 fwdToSw.add(destSw);
Sangho Shin43cee112014-09-25 16:43:34 -0700781 }
Sangho Shinfbc572c2014-10-02 16:37:05 -0700782 else {
783 fwdToSw.add(via.get(0).toString());
784 }
Sangho Shin43cee112014-09-25 16:43:34 -0700785 }
Sangho Shin5be3e532014-10-03 17:20:58 -0700786 setRoutingRule(targetSw, destSw, fwdToSw, modified);
Sangho Shineb083032014-09-22 16:11:34 -0700787 }
Sangho Shinfbc572c2014-10-02 16:37:05 -0700788
789 // Send Barrier Message and make sure all rules are set
790 // before we set the rules to next routers
Saurav Dasa962a692014-10-17 14:52:38 -0700791 // TODO: barriers to all switches in this update stage
Sangho Shinfbc572c2014-10-02 16:37:05 -0700792 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
793 getSwId(sw.getDpid().toString()));
Sangho Shin5be3e532014-10-03 17:20:58 -0700794 if (sw13 != null) {
Saurav Dasa962a692014-10-17 14:52:38 -0700795 OFBarrierReplyFuture replyFuture = null;
Sangho Shin5be3e532014-10-03 17:20:58 -0700796 try {
Saurav Dasa962a692014-10-17 14:52:38 -0700797 replyFuture = sw13.sendBarrier();
Sangho Shin5be3e532014-10-03 17:20:58 -0700798 } catch (IOException e) {
Saurav Dasa962a692014-10-17 14:52:38 -0700799 log.error("Error sending barrier request to switch {}",
800 sw13.getId(), e.getCause());
Sangho Shin5be3e532014-10-03 17:20:58 -0700801 }
Saurav Dasa962a692014-10-17 14:52:38 -0700802 OFBarrierReply br = null;
803 try {
804 br = replyFuture.get(2, TimeUnit.SECONDS);
805 } catch (TimeoutException | InterruptedException | ExecutionException e) {
806 // XXX for some reason these exceptions are not being thrown
807 }
808 if (br == null) {
809 log.warn("Did not receive barrier-reply from {}", sw13.getId());
810 // XXX take corrective action
811 }
812
Sangho Shinfbc572c2014-10-02 16:37:05 -0700813 }
814 }
815
816 }
817
Sangho Shinfbc572c2014-10-02 16:37:05 -0700818 /**
819 *
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700820 * Set routing rules in targetSw {forward packets to fwdToSw switches in
821 * order to send packets to destSw} - If the target switch is an edge router
822 * and final destnation switch is also an edge router, then set IP
823 * forwarding rules to subnets - If only the target switch is an edge
824 * router, then set IP forwarding rule to the transit router loopback IP
825 * address - If the target is a transit router, then just set the MPLS
826 * forwarding rule
Sangho Shinfbc572c2014-10-02 16:37:05 -0700827 *
Sangho Shin43cee112014-09-25 16:43:34 -0700828 * @param targetSw Switch to set the rules
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700829 * @param destSw Final destination switches
Sangho Shin43cee112014-09-25 16:43:34 -0700830 * @param fwdToSw next hop switches
831 */
Sangho Shin99918bd2014-10-08 15:52:35 -0700832 private void setRoutingRule(Switch targetSw, String destSw,
833 List<String> fwdToSw, boolean modified) {
Sangho Shin43cee112014-09-25 16:43:34 -0700834
Sangho Shin43cee112014-09-25 16:43:34 -0700835 if (fwdToSw.isEmpty()) {
836 fwdToSw.add(destSw);
837 }
838
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700839 // if both target SW and dest SW are an edge router, then set IP table
Sangho Shin43cee112014-09-25 16:43:34 -0700840 if (IsEdgeRouter(targetSw.getDpid().toString()) &&
841 IsEdgeRouter(destSw)) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700842 // We assume that there is at least one transit router b/w edge
843 // routers
Sangho Shin43cee112014-09-25 16:43:34 -0700844 Switch destSwitch = mutableTopology.getSwitch(new Dpid(destSw));
845 String subnets = destSwitch.getStringAttribute("subnets");
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700846 setIpTableRouterSubnet(targetSw, subnets, getMplsLabel(destSw)
Sangho Shin5be3e532014-10-03 17:20:58 -0700847 , fwdToSw, modified);
Sangho Shin43cee112014-09-25 16:43:34 -0700848
Sangho Shin43cee112014-09-25 16:43:34 -0700849 String routerIp = destSwitch.getStringAttribute("routerIp");
Sangho Shin5be3e532014-10-03 17:20:58 -0700850 setIpTableRouter(targetSw, routerIp, getMplsLabel(destSw), fwdToSw,
851 null, modified);
Sangho Shin721ca042014-10-09 13:03:40 -0700852 // Edge router can be a transit router
853 setMplsTable(targetSw, getMplsLabel(destSw), fwdToSw, modified);
Sangho Shin43cee112014-09-25 16:43:34 -0700854 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700855 // Only if the target switch is the edge router, then set the IP rules
Sangho Shin43cee112014-09-25 16:43:34 -0700856 else if (IsEdgeRouter(targetSw.getDpid().toString())) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700857 // We assume that there is at least one transit router b/w edge
858 // routers
Sangho Shin43cee112014-09-25 16:43:34 -0700859 Switch destSwitch = mutableTopology.getSwitch(new Dpid(destSw));
860 String routerIp = destSwitch.getStringAttribute("routerIp");
Sangho Shin5be3e532014-10-03 17:20:58 -0700861 setIpTableRouter(targetSw, routerIp, getMplsLabel(destSw), fwdToSw,
862 null, modified);
Sangho Shin721ca042014-10-09 13:03:40 -0700863 // Edge router can be a transit router
864 setMplsTable(targetSw, getMplsLabel(destSw), fwdToSw, modified);
Sangho Shin43cee112014-09-25 16:43:34 -0700865 }
866 // if it is a transit router, then set rules in the MPLS table
867 else {
Sangho Shin5be3e532014-10-03 17:20:58 -0700868 setMplsTable(targetSw, getMplsLabel(destSw), fwdToSw, modified);
Sangho Shin43cee112014-09-25 16:43:34 -0700869 }
870
871 }
872
Sangho Shinfbc572c2014-10-02 16:37:05 -0700873 /**
874 * Set IP forwarding rule to the gateway of each subnet of switches
875 *
876 * @param targetSw Switch to set rules
877 * @param subnets subnet information
878 * @param mplsLabel destination MPLS label
879 * @param fwdToSw router to forward packets to
880 */
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700881 private void setIpTableRouterSubnet(Switch targetSw, String subnets,
Sangho Shin5be3e532014-10-03 17:20:58 -0700882 String mplsLabel, List<String> fwdToSw, boolean modified) {
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700883
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700884 Collection<MatchActionOperationEntry> entries =
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700885 new ArrayList<MatchActionOperationEntry>();
886
887 try {
888 JSONArray arry = new JSONArray(subnets);
889 for (int i = 0; i < arry.length(); i++) {
890 String subnetIp = (String) arry.getJSONObject(i).get("subnetIp");
Sangho Shin5be3e532014-10-03 17:20:58 -0700891 setIpTableRouter(targetSw, subnetIp, mplsLabel, fwdToSw, entries,
892 modified);
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700893 }
894 } catch (JSONException e) {
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700895 e.printStackTrace();
896 }
897
898 if (!entries.isEmpty()) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700899 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700900 getSwId(targetSw.getDpid().toString()));
901
Sangho Shin721ca042014-10-09 13:03:40 -0700902 if (sw13 != null) {
903 try {
904 sw13.pushFlows(entries);
905 } catch (IOException e) {
906 e.printStackTrace();
907 }
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700908 }
909 }
910
911 }
912
Sangho Shin43cee112014-09-25 16:43:34 -0700913 /**
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700914 * Set IP forwarding rule - If the destination is the next hop, then do not
915 * push MPLS, just decrease the NW TTL - Otherwise, push MPLS label and set
916 * the MPLS ID
Sangho Shinfbc572c2014-10-02 16:37:05 -0700917 *
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700918 * @param sw target switch to set rules
Sangho Shin43cee112014-09-25 16:43:34 -0700919 * @param subnetIp Match IP address
920 * @param mplsLabel MPLS label of final destination router
921 * @param fwdToSws next hop routers
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700922 * @param entries
Sangho Shin43cee112014-09-25 16:43:34 -0700923 */
924 private void setIpTableRouter(Switch sw, String subnetIp, String mplsLabel,
Sangho Shin5be3e532014-10-03 17:20:58 -0700925 List<String> fwdToSws, Collection<MatchActionOperationEntry> entries,
926 boolean modified) {
Sangho Shin43cee112014-09-25 16:43:34 -0700927
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700928 Ipv4Match ipMatch = new Ipv4Match(subnetIp);
Sangho Shin43cee112014-09-25 16:43:34 -0700929 List<Action> actions = new ArrayList<>();
Sangho Shin721ca042014-10-09 13:03:40 -0700930 GroupAction groupAction = new GroupAction();
Sangho Shin43cee112014-09-25 16:43:34 -0700931
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700932 // If destination SW is the same as the fwd SW, then do not push MPLS
933 // label
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700934 if (fwdToSws.size() > 1) {
Sangho Shin43cee112014-09-25 16:43:34 -0700935 PushMplsAction pushMplsAction = new PushMplsAction();
936 SetMplsIdAction setIdAction = new SetMplsIdAction(Integer.parseInt(mplsLabel));
937 CopyTtlOutAction copyTtlOutAction = new CopyTtlOutAction();
Sangho Shin463bee52014-09-29 15:14:43 -0700938 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
Sangho Shin43cee112014-09-25 16:43:34 -0700939
Sangho Shin62ce5c12014-10-08 16:24:40 -0700940 //actions.add(pushMplsAction);
941 //actions.add(copyTtlOutAction);
942 //actions.add(decMplsTtlAction);
Saurav Das82e62972014-10-16 14:53:57 -0700943 // actions.add(setIdAction);
Sangho Shin721ca042014-10-09 13:03:40 -0700944 groupAction.setEdgeLabel(Integer.parseInt(mplsLabel));
Sangho Shin43cee112014-09-25 16:43:34 -0700945 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700946 else {
947 String fwdToSw = fwdToSws.get(0);
948 if (getMplsLabel(fwdToSw).equals(mplsLabel)) {
949 DecNwTtlAction decTtlAction = new DecNwTtlAction(1);
950 actions.add(decTtlAction);
951 }
952 else {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700953 SetMplsIdAction setIdAction = new SetMplsIdAction(
954 Integer.parseInt(mplsLabel));
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700955 CopyTtlOutAction copyTtlOutAction = new CopyTtlOutAction();
Sangho Shin463bee52014-09-29 15:14:43 -0700956 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700957
Sangho Shin62ce5c12014-10-08 16:24:40 -0700958 //actions.add(pushMplsAction);
959 //actions.add(copyTtlOutAction);
960 //actions.add(decMplsTtlAction);
Saurav Das82e62972014-10-16 14:53:57 -0700961 // actions.add(setIdAction);
Sangho Shin721ca042014-10-09 13:03:40 -0700962 groupAction.setEdgeLabel(Integer.parseInt(mplsLabel));
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700963 }
964 }
Sangho Shin43cee112014-09-25 16:43:34 -0700965
Sangho Shin43cee112014-09-25 16:43:34 -0700966 for (String fwdSw : fwdToSws) {
967 groupAction.addSwitch(new Dpid(fwdSw));
968 }
969 actions.add(groupAction);
970
Sangho Shin99918bd2014-10-08 15:52:35 -0700971 MatchAction matchAction = new MatchAction(new MatchActionId(matchActionId++),
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700972 new SwitchPort((long) 0, (short) 0), ipMatch, actions);
Sangho Shin43cee112014-09-25 16:43:34 -0700973
Sangho Shin5be3e532014-10-03 17:20:58 -0700974 Operator operator = null;
975 if (modified)
976 operator = Operator.MODIFY;
977 else
978 operator = Operator.ADD;
979
Sangho Shin43cee112014-09-25 16:43:34 -0700980 MatchActionOperationEntry maEntry =
Sangho Shin5be3e532014-10-03 17:20:58 -0700981 new MatchActionOperationEntry(operator, matchAction);
Sangho Shin43cee112014-09-25 16:43:34 -0700982
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -0700983 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700984 getSwId(sw.getDpid().toString()));
985
Sangho Shin5be3e532014-10-03 17:20:58 -0700986 if (sw13 != null) {
987 try {
Sangho Shinbce900e2014-10-07 17:13:23 -0700988 //printMatchActionOperationEntry(sw, maEntry);
Sangho Shin5be3e532014-10-03 17:20:58 -0700989 if (entries != null)
990 entries.add(maEntry);
991 else
992 sw13.pushFlow(maEntry);
993 } catch (IOException e) {
994 e.printStackTrace();
995 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700996 }
997
Sangho Shin43cee112014-09-25 16:43:34 -0700998 }
999
Sangho Shinac5ee2b2014-09-28 21:27:20 -07001000 /**
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001001 * Set MPLS forwarding rules to MPLS table
1002 * </p>
1003 * If the destination is the same as the next hop to forward packets then,
1004 * pop the MPLS label according to PHP rule. Here, if BoS is set, then
1005 * copy TTL In and decrement NW TTL. Otherwise, it just decrement the MPLS
1006 * TTL of the another MPLS header.
1007 * If the next hop is not the destination, just forward packets to next
1008 * hops using Group action.
Sangho Shinfbc572c2014-10-02 16:37:05 -07001009 *
Sangho Shin204b9972014-10-22 11:08:10 -07001010 * TODO: refactoring required
1011 *
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001012 * @param sw Switch to set the rules
Sangho Shin43cee112014-09-25 16:43:34 -07001013 * @param mplsLabel destination MPLS label
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001014 * @param fwdSws next hop switches
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001015 * */
Sangho Shin5be3e532014-10-03 17:20:58 -07001016 private void setMplsTable(Switch sw, String mplsLabel, List<String> fwdSws,
1017 boolean modified) {
Sangho Shin463bee52014-09-29 15:14:43 -07001018
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001019 if (fwdSws.isEmpty())
1020 return;
Sangho Shin43cee112014-09-25 16:43:34 -07001021
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001022 Collection<MatchActionOperationEntry> maEntries =
1023 new ArrayList<MatchActionOperationEntry>();
1024 String fwdSw1 = fwdSws.get(0);
Sangho Shin43cee112014-09-25 16:43:34 -07001025
Sangho Shin204b9972014-10-22 11:08:10 -07001026 //If the next hop is the destination router
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001027 if (fwdSws.size() == 1 && mplsLabel.equals(getMplsLabel(fwdSw1))) {
1028 // One rule for Bos = 1
1029 MplsMatch mplsMatch = new MplsMatch(Integer.parseInt(mplsLabel), true);
1030 List<Action> actions = new ArrayList<Action>();
Sangho Shin9c0f4c32014-09-26 16:02:38 -07001031
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001032 PopMplsAction popAction = new PopMplsAction(EthType.IPv4);
1033 CopyTtlInAction copyTtlInAction = new CopyTtlInAction();
1034 DecNwTtlAction decNwTtlAction = new DecNwTtlAction(1);
1035
1036 actions.add(copyTtlInAction);
1037 actions.add(popAction);
1038 actions.add(decNwTtlAction);
1039
1040 GroupAction groupAction = new GroupAction();
1041 groupAction.addSwitch(new Dpid(fwdSw1));
1042 actions.add(groupAction);
1043
1044 MatchAction matchAction = new MatchAction(new MatchActionId(matchActionId++),
1045 new SwitchPort((long) 0, (short) 0), mplsMatch, actions);
1046 Operator operator = Operator.ADD;
1047 MatchActionOperationEntry maEntry =
1048 new MatchActionOperationEntry(operator, matchAction);
1049 maEntries.add(maEntry);
1050
1051 // One rule for Bos = 0
Sangho Shin23f898d2014-10-13 16:54:00 -07001052 MplsMatch mplsMatchBos = new MplsMatch(Integer.parseInt(mplsLabel), false);
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001053 List<Action> actionsBos = new ArrayList<Action>();
Sangho Shin15273b62014-10-16 22:22:05 -07001054 PopMplsAction popActionBos = new PopMplsAction(EthType.MPLS_UNICAST);
1055 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
1056
1057 actionsBos.add(copyTtlInAction);
1058 actionsBos.add(popActionBos);
1059 actionsBos.add(decMplsTtlAction);
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001060 actionsBos.add(groupAction);
1061
1062 MatchAction matchActionBos = new MatchAction(new MatchActionId(matchActionId++),
1063 new SwitchPort((long) 0, (short) 0), mplsMatchBos, actionsBos);
1064 MatchActionOperationEntry maEntryBos =
1065 new MatchActionOperationEntry(operator, matchActionBos);
1066 maEntries.add(maEntryBos);
Sangho Shin9c0f4c32014-09-26 16:02:38 -07001067 }
Sangho Shin204b9972014-10-22 11:08:10 -07001068 // If the next hop is NOT the destination router
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001069 else {
Sangho Shin204b9972014-10-22 11:08:10 -07001070 // BoS = 0
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001071 MplsMatch mplsMatch = new MplsMatch(Integer.parseInt(mplsLabel), false);
1072 List<Action> actions = new ArrayList<Action>();
Sangho Shin43cee112014-09-25 16:43:34 -07001073
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001074 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
1075 actions.add(decMplsTtlAction);
Sangho Shin43cee112014-09-25 16:43:34 -07001076
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001077 GroupAction groupAction = new GroupAction();
1078 for (String fwdSw : fwdSws)
1079 groupAction.addSwitch(new Dpid(fwdSw));
1080 actions.add(groupAction);
Sangho Shin5be3e532014-10-03 17:20:58 -07001081
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001082 MatchAction matchAction = new MatchAction(new MatchActionId(
1083 matchActionId++),
1084 new SwitchPort((long) 0, (short) 0), mplsMatch, actions);
1085 Operator operator = Operator.ADD;
1086 MatchActionOperationEntry maEntry =
1087 new MatchActionOperationEntry(operator, matchAction);
1088 maEntries.add(maEntry);
Sangho Shine2e9bcd2014-10-13 15:14:18 -07001089
1090 // BoS = 1
1091 MplsMatch mplsMatchBoS = new MplsMatch(Integer.parseInt(mplsLabel), true);
1092 List<Action> actionsBoS = new ArrayList<Action>();
1093
1094 DecMplsTtlAction decMplsTtlActionBoS = new DecMplsTtlAction(1);
1095 actionsBoS.add(decMplsTtlActionBoS);
1096
1097 GroupAction groupActionBoS = new GroupAction();
1098 for (String fwdSw : fwdSws)
1099 groupActionBoS.addSwitch(new Dpid(fwdSw));
1100 actionsBoS.add(groupActionBoS);
1101
1102 MatchAction matchActionBos = new MatchAction(new MatchActionId(
1103 matchActionId++),
1104 new SwitchPort((long) 0, (short) 0), mplsMatchBoS, actionsBoS);
1105 MatchActionOperationEntry maEntryBoS =
1106 new MatchActionOperationEntry(operator, matchActionBos);
1107 maEntries.add(maEntryBoS);
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001108 }
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001109 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin9c0f4c32014-09-26 16:02:38 -07001110 getSwId(sw.getDpid().toString()));
1111
Sangho Shin5be3e532014-10-03 17:20:58 -07001112 if (sw13 != null) {
1113 try {
Sangho Shinbce900e2014-10-07 17:13:23 -07001114 //printMatchActionOperationEntry(sw, maEntry);
Sangho Shinc1b8dea2014-10-13 12:03:28 -07001115 sw13.pushFlows(maEntries);
Sangho Shin5be3e532014-10-03 17:20:58 -07001116 } catch (IOException e) {
1117 e.printStackTrace();
1118 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -07001119 }
Sangho Shin43cee112014-09-25 16:43:34 -07001120 }
1121
Sangho Shin7330c032014-10-20 10:34:51 -07001122
1123 // ************************************
1124 // Policy routing classes and functions
1125 // ************************************
1126
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001127 public class PolicyInfo {
Sangho Shin5b8f5452014-10-20 11:46:01 -07001128
Sangho Shin58182672014-10-21 13:23:38 -07001129 public final int TYPE_EXPLICIT = 1;
1130 public final int TYPE_AVOID = 2;
1131
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001132 private String policyId;
1133 private PacketMatch match;
1134 private int priority;
1135 private String tunnelId;
Sangho Shin58182672014-10-21 13:23:38 -07001136 private int type;
Sangho Shin5b8f5452014-10-20 11:46:01 -07001137
Sangho Shin58182672014-10-21 13:23:38 -07001138 public PolicyInfo(String pid, int type, PacketMatch match, int priority,
1139 String tid) {
1140 this.policyId = pid;
1141 this.match = match;
1142 this.priority = priority;
1143 this.tunnelId = tid;
1144 this.type = type;
1145 }
Sangho Shin204b9972014-10-22 11:08:10 -07001146
Fahad Naeem Khan95aa4012014-10-21 14:07:00 -07001147 public PolicyInfo(String pid, PacketMatch match, int priority,
1148 String tid) {
1149 this.policyId = pid;
1150 this.match = match;
1151 this.priority = priority;
1152 this.tunnelId = tid;
Fahad Naeem Khan788895c2014-10-21 19:00:24 -07001153 this.type = 0;
Fahad Naeem Khan95aa4012014-10-21 14:07:00 -07001154 }
1155 public String getPolicyId(){
1156 return this.policyId;
1157 }
1158 public PacketMatch getMatch(){
1159 return this.match;
1160 }
1161 public int getPriority(){
1162 return this.priority;
1163 }
1164 public String getTunnelId(){
1165 return this.tunnelId;
1166 }
1167 public int getType(){
1168 return this.type;
1169 }
Sangho Shin5b8f5452014-10-20 11:46:01 -07001170 }
1171
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001172 public class TunnelInfo {
1173 private String tunnelId;
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001174 private List<Integer> labelIds;
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001175 private List<TunnelRouteInfo> routes;
Sangho Shin81655442014-10-20 14:22:46 -07001176
Sangho Shin6471d202014-10-23 10:59:36 -07001177 public TunnelInfo(String tid, List<Integer> labelIds,
1178 List<TunnelRouteInfo> routes) {
Sangho Shin81655442014-10-20 14:22:46 -07001179 this.tunnelId = tid;
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001180 this.labelIds = labelIds;
Sangho Shin81655442014-10-20 14:22:46 -07001181 this.routes = routes;
1182 }
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001183 public String getTunnelId(){
1184 return this.tunnelId;
1185 }
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001186
1187 public List<Integer> getLabelids() {
1188 return this.labelIds;
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001189 }
1190 public List<TunnelRouteInfo> getRoutes(){
1191 return this.routes;
1192 }
Sangho Shin81655442014-10-20 14:22:46 -07001193 }
1194
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001195 public class TunnelRouteInfo {
Sangho Shin7330c032014-10-20 10:34:51 -07001196
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001197 private String srcSwDpid;
1198 private List<Dpid> fwdSwDpids;
1199 private List<String> route;
Sangho Shin6471d202014-10-23 10:59:36 -07001200 private int gropuId;
Sangho Shin7330c032014-10-20 10:34:51 -07001201
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001202 public TunnelRouteInfo() {
Sangho Shin7330c032014-10-20 10:34:51 -07001203 fwdSwDpids = new ArrayList<Dpid>();
1204 route = new ArrayList<String>();
1205 }
1206
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001207 private void setSrcDpid(String dpid) {
Sangho Shin7330c032014-10-20 10:34:51 -07001208 this.srcSwDpid = dpid;
1209 }
1210
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001211 private void setFwdSwDpid(List<Dpid> dpid) {
Sangho Shin7330c032014-10-20 10:34:51 -07001212 this.fwdSwDpids = dpid;
1213 }
1214
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001215 private void addRoute(String id) {
Sangho Shin7330c032014-10-20 10:34:51 -07001216 route.add(id);
1217 }
1218
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001219 private void setRoute(List<String> r) {
Sangho Shin7330c032014-10-20 10:34:51 -07001220 this.route = r;
1221 }
1222
Sangho Shin6471d202014-10-23 10:59:36 -07001223 private void setGroupId(int groupId) {
1224 this.gropuId = groupId;
1225 }
1226
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001227 public String getSrcSwDpid() {
Sangho Shin7330c032014-10-20 10:34:51 -07001228 return this.srcSwDpid;
1229 }
1230
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001231 public List<Dpid> getFwdSwDpid() {
Sangho Shin7330c032014-10-20 10:34:51 -07001232 return this.fwdSwDpids;
1233 }
1234
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001235 public List<String> getRoute() {
Sangho Shin7330c032014-10-20 10:34:51 -07001236 return this.route;
1237 }
Sangho Shin6471d202014-10-23 10:59:36 -07001238
1239 public int getGroupId() {
1240 return this.gropuId;
1241 }
Sangho Shin7330c032014-10-20 10:34:51 -07001242 }
1243
Sangho Shin15273b62014-10-16 22:22:05 -07001244 /**
Sangho Shin81655442014-10-20 14:22:46 -07001245 * Return the Tunnel table
1246 *
1247 * @return collection of TunnelInfo
1248 */
1249 public Collection<TunnelInfo> getTunnelTable() {
Fahad Naeem Khana40f9b62014-10-20 18:33:45 -07001250 return this.tunnelTable.values();
Sangho Shin81655442014-10-20 14:22:46 -07001251 }
Sangho Shin204b9972014-10-22 11:08:10 -07001252
Fahad Naeem Khan12fa63a2014-10-21 17:01:27 -07001253 public Collection<PolicyInfo> getPoclicyTable() {
1254 return this.policyTable.values();
1255 }
Sangho Shin81655442014-10-20 14:22:46 -07001256
1257 /**
Sangho Shin5671cbb2014-10-20 22:35:41 -07001258 * Return router DPIDs for the tunnel
1259 *
1260 * @param tid tunnel ID
1261 * @return List of DPID
1262 */
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001263 public List<Integer> getTunnelInfo(String tid) {
Sangho Shin5671cbb2014-10-20 22:35:41 -07001264 TunnelInfo tunnelInfo = tunnelTable.get(tid);
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001265 return tunnelInfo.labelIds;
Sangho Shin5671cbb2014-10-20 22:35:41 -07001266
1267 }
1268
1269 /**
1270 * Get the first group ID for the tunnel for specific source router
1271 * If Segment Stitching was required to create the tunnel, there are
1272 * mutiple source routers.
1273 *
1274 * @param tunnelId ID for the tunnel
1275 * @param dpid source router DPID
1276 * @return the first group ID of the tunnel
1277 */
1278 public int getTunnelGroupId(String tunnelId, String dpid) {
Sangho Shin6471d202014-10-23 10:59:36 -07001279 TunnelInfo tunnelInfo = tunnelTable.get(tunnelId);
1280 for (TunnelRouteInfo routeInfo: tunnelInfo.getRoutes()) {
1281 String tunnelSrcDpid = routeInfo.getSrcSwDpid();
1282 if (tunnelSrcDpid.equals(dpid))
1283 return routeInfo.getGroupId();
1284 }
Sangho Shin5671cbb2014-10-20 22:35:41 -07001285
Sangho Shin6471d202014-10-23 10:59:36 -07001286 return -1;
Sangho Shin5671cbb2014-10-20 22:35:41 -07001287 }
1288
1289 /**
Sangho Shin15273b62014-10-16 22:22:05 -07001290 * Create a tunnel for policy routing
1291 * It delivers the node IDs of tunnels to driver.
1292 * Split the node IDs if number of IDs exceeds the limit for stitching.
1293 *
1294 * @param tunnelId Node IDs for the tunnel
1295 * @param Ids tunnel ID
1296 */
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001297 public boolean createTunnel(String tunnelId, List<Integer> labelIds) {
Sangho Shin15273b62014-10-16 22:22:05 -07001298
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001299 if (labelIds.isEmpty() || labelIds.size() < 2) {
Sangho Shin15273b62014-10-16 22:22:05 -07001300 log.debug("Wrong tunnel information");
1301 return false;
1302 }
1303
Sangho Shin55d00e12014-10-20 12:13:07 -07001304 List<String> Ids = new ArrayList<String>();
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07001305 for (Integer label : labelIds) {
1306 Ids.add(label.toString());
Sangho Shin55d00e12014-10-20 12:13:07 -07001307 }
1308
Sangho Shin81655442014-10-20 14:22:46 -07001309 List<TunnelRouteInfo> stitchingRule = getStitchingRule(Ids);
Sangho Shin15273b62014-10-16 22:22:05 -07001310 if (stitchingRule == null) {
Sangho Shin6471d202014-10-23 10:59:36 -07001311 log.debug("Failed to get a tunnel rule.");
Sangho Shin15273b62014-10-16 22:22:05 -07001312 return false;
1313 }
Sangho Shin81655442014-10-20 14:22:46 -07001314 for (TunnelRouteInfo route: stitchingRule) {
Sangho Shin15273b62014-10-16 22:22:05 -07001315 NeighborSet ns = new NeighborSet();
1316 for (Dpid dpid: route.getFwdSwDpid())
1317 ns.addDpid(dpid);
1318
Sangho Shin6471d202014-10-23 10:59:36 -07001319 printTunnelInfo(route.srcSwDpid, tunnelId, route.getRoute(), ns);
1320 int groupId = -1;
1321 if ((groupId =createGroupsForTunnel(tunnelId, route, ns)) < 0) {
1322 log.debug("Failed to create a tunnel at driver.");
1323 return false;
1324 }
1325 route.setGroupId(groupId);
Sangho Shin15273b62014-10-16 22:22:05 -07001326 }
1327
Sangho Shin6471d202014-10-23 10:59:36 -07001328 TunnelInfo tunnelInfo = new TunnelInfo(tunnelId, labelIds,
1329 stitchingRule);
Sangho Shin81655442014-10-20 14:22:46 -07001330 tunnelTable.put(tunnelId, tunnelInfo);
Sangho Shin15273b62014-10-16 22:22:05 -07001331
1332 return true;
1333 }
1334
Sangho Shin6471d202014-10-23 10:59:36 -07001335 private int createGroupsForTunnel(String tunnelId, TunnelRouteInfo routeInfo,
1336 NeighborSet ns) {
1337
1338 IOF13Switch targetSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
1339 getSwId(routeInfo.srcSwDpid));
1340
1341 if (targetSw == null) {
1342 log.debug("Switch {} is gone.", routeInfo.srcSwDpid);
1343 return -1;
1344 }
1345
1346 List<Integer> Ids = new ArrayList<Integer>();
1347 for (String IdStr: routeInfo.route)
1348 Ids.add(Integer.parseInt(IdStr));
1349
1350 List<PortNumber> ports = getPortsFromNeighborSet(routeInfo.srcSwDpid, ns);
1351 int groupId = targetSw.createGroup(Ids, ports);
1352
1353 return groupId;
1354 }
1355
Sangho Shin15273b62014-10-16 22:22:05 -07001356 /**
1357 * Set policy table for policy routing
1358 *
1359 * @param sw
1360 * @param mplsLabel
Sangho Shin306633a2014-10-20 14:26:55 -07001361 * @return
Sangho Shin15273b62014-10-16 22:22:05 -07001362 */
Sangho Shin306633a2014-10-20 14:26:55 -07001363 public boolean createPolicy(String pid, MACAddress srcMac, MACAddress dstMac,
Sangho Shin15273b62014-10-16 22:22:05 -07001364 Short etherType, IPv4Net srcIp, IPv4Net dstIp, Byte ipProto,
Sangho Shine020cc32014-10-20 13:28:02 -07001365 Short srcTcpPort, Short dstTcpPort, int priority, String tid) {
Sangho Shin15273b62014-10-16 22:22:05 -07001366
Sangho Shin5b8f5452014-10-20 11:46:01 -07001367 PacketMatchBuilder packetBuilder = new PacketMatchBuilder();
1368
1369 if (srcMac != null)
1370 packetBuilder.setSrcMac(srcMac);
1371 if (dstMac != null)
1372 packetBuilder.setDstMac(dstMac);
Sangho Shin58182672014-10-21 13:23:38 -07001373 if (etherType == null) // Cqpd requires the type of IPV4
1374 packetBuilder.setEtherType(Ethernet.TYPE_IPV4);
1375 else
Sangho Shin5b8f5452014-10-20 11:46:01 -07001376 packetBuilder.setEtherType(etherType);
1377 if (srcIp != null)
1378 packetBuilder.setSrcIp(srcIp.address(), srcIp.prefixLen());
1379 if (dstIp != null)
1380 packetBuilder.setDstIp(dstIp.address(), dstIp.prefixLen());
1381 if (ipProto != null)
1382 packetBuilder.setIpProto(ipProto);
1383 if (srcTcpPort > 0)
1384 packetBuilder.setSrcTcpPort(srcTcpPort);
1385 if (dstTcpPort > 0)
1386 packetBuilder.setDstTcpPort(dstTcpPort);
1387 PacketMatch policyMatch = packetBuilder.build();
Sangho Shin81655442014-10-20 14:22:46 -07001388 TunnelInfo tunnelInfo = tunnelTable.get(tid);
Sangho Shin6471d202014-10-23 10:59:36 -07001389 if (tunnelInfo == null) {
1390 log.debug("Tunnel {} is not defined", tid);
1391 return false;
1392 }
Sangho Shin81655442014-10-20 14:22:46 -07001393 List<TunnelRouteInfo> routes = tunnelInfo.routes;
Sangho Shin5b8f5452014-10-20 11:46:01 -07001394
Sangho Shin81655442014-10-20 14:22:46 -07001395 for (TunnelRouteInfo route : routes) {
Sangho Shin15273b62014-10-16 22:22:05 -07001396 List<Action> actions = new ArrayList<>();
1397 GroupAction groupAction = new GroupAction();
Sangho Shin6471d202014-10-23 10:59:36 -07001398 groupAction.setGroupId(route.getGroupId());
Sangho Shin15273b62014-10-16 22:22:05 -07001399 actions.add(groupAction);
1400
1401 MatchAction matchAction = new MatchAction(new MatchActionId(
1402 matchActionId++),
Sangho Shin5b8f5452014-10-20 11:46:01 -07001403 new SwitchPort((long) 0, (short) 0), policyMatch, priority,
1404 actions);
Sangho Shin15273b62014-10-16 22:22:05 -07001405 MatchActionOperationEntry maEntry =
1406 new MatchActionOperationEntry(Operator.ADD, matchAction);
1407
1408 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin81655442014-10-20 14:22:46 -07001409 getSwId(route.srcSwDpid));
Sangho Shin15273b62014-10-16 22:22:05 -07001410
1411 if (sw13 != null) {
1412 printMatchActionOperationEntry(sw13, maEntry);
1413 try {
1414 sw13.pushFlow(maEntry);
1415 } catch (IOException e) {
1416 e.printStackTrace();
Sangho Shin306633a2014-10-20 14:26:55 -07001417 return false;
Sangho Shin15273b62014-10-16 22:22:05 -07001418 }
1419 }
1420 }
Sangho Shin5b8f5452014-10-20 11:46:01 -07001421
1422 PolicyInfo policyInfo = new PolicyInfo(pid, policyMatch, priority, tid);
Sangho Shine020cc32014-10-20 13:28:02 -07001423 policyTable.put(pid, policyInfo);
Sangho Shin306633a2014-10-20 14:26:55 -07001424
1425 return true;
Sangho Shin15273b62014-10-16 22:22:05 -07001426 }
1427
1428 /**
Sangho Shin1ad7be02014-10-20 16:56:49 -07001429 * Split the nodes IDs into multiple tunnel if Segment Stitching is required.
1430 * We assume that the first node ID is the one of source router, and the last
1431 * node ID is that of the destination router.
Sangho Shin15273b62014-10-16 22:22:05 -07001432 *
Sangho Shin1ad7be02014-10-20 16:56:49 -07001433 * @param route list of node IDs
1434 * @return List of the TunnelRoutInfo
Sangho Shin15273b62014-10-16 22:22:05 -07001435 */
Sangho Shin81655442014-10-20 14:22:46 -07001436 private List<TunnelRouteInfo> getStitchingRule(List<String> route) {
Sangho Shin15273b62014-10-16 22:22:05 -07001437
1438 if (route.isEmpty() || route.size() < 2)
1439 return null;
1440
Sangho Shin81655442014-10-20 14:22:46 -07001441 List<TunnelRouteInfo> rules = new ArrayList<TunnelRouteInfo>();
Sangho Shin15273b62014-10-16 22:22:05 -07001442
1443 Switch srcSw = this.getSwitchFromNodeId(route.get(0));
Sangho Shin6471d202014-10-23 10:59:36 -07001444 if (srcSw == null) {
1445 log.warn("Switch is not found for Node SID {}", route.get(0));
1446 return null;
1447 }
Sangho Shin15273b62014-10-16 22:22:05 -07001448 String srcDpid = srcSw.getDpid().toString();
1449
Sangho Shin6471d202014-10-23 10:59:36 -07001450 /*
Sangho Shin15273b62014-10-16 22:22:05 -07001451 if (route.size() <= MAX_NUM_LABELS+1) {
Sangho Shin58182672014-10-21 13:23:38 -07001452 boolean match =false;
1453 TunnelRouteInfo routeInfo = new TunnelRouteInfo();
1454 routeInfo.setSrcDpid(srcSw.getDpid().toString());
1455 String nodeId = route.get(1);
Sangho Shina000c612014-10-21 14:17:59 -07001456 List<Dpid> fwdSwDpids = getForwardingSwitchForNodeId(srcSw, nodeId);
Fahad Naeem Khan95aa4012014-10-21 14:07:00 -07001457 if (fwdSwDpids == null){
1458 return null;
1459 }
Sangho Shin58182672014-10-21 13:23:38 -07001460 for (Dpid dpid: fwdSwDpids) {
1461 if (getMplsLabel(dpid.toString()).toString().equals(nodeId)) {
1462 List<Dpid> fwdSws = new ArrayList<Dpid>();
1463 fwdSws.add(dpid);
1464 routeInfo.setFwdSwDpid(fwdSws);
1465 match = true;
1466 break;
1467 }
1468 }
1469 route.remove(0); // remove source router from the list
1470 if (match) {
1471 route.remove(0);
1472 }
1473 else {
1474 routeInfo.setFwdSwDpid(fwdSwDpids);
1475 }
1476 routeInfo.setRoute(route);
1477 rules.add(routeInfo);
Sangho Shin15273b62014-10-16 22:22:05 -07001478 return rules;
1479 }
Sangho Shin6471d202014-10-23 10:59:36 -07001480 */
Sangho Shin15273b62014-10-16 22:22:05 -07001481
1482 int i = 0;
Sangho Shine020cc32014-10-20 13:28:02 -07001483 TunnelRouteInfo routeInfo = new TunnelRouteInfo();
Sangho Shin15273b62014-10-16 22:22:05 -07001484 boolean checkNeighbor = true;
Sangho Shin6471d202014-10-23 10:59:36 -07001485 String prevAdjacencySid = null;
1486 String prevNodeId = null;
Sangho Shin15273b62014-10-16 22:22:05 -07001487
1488 for (String nodeId: route) {
Sangho Shin6471d202014-10-23 10:59:36 -07001489 // The first node ID is always the source router.
1490 // We assume that the first ID cannot be an Adjacency SID.
Sangho Shin15273b62014-10-16 22:22:05 -07001491 if (i == 0) {
1492 routeInfo.setSrcDpid(srcDpid);
1493 srcSw = getSwitchFromNodeId(nodeId);
1494 i++;
1495 }
Sangho Shin6471d202014-10-23 10:59:36 -07001496 else if (i == 1) {
1497 if (isAdjacencySid(nodeId)) {
Sangho Shin15273b62014-10-16 22:22:05 -07001498 routeInfo.addRoute(nodeId);
Sangho Shin6471d202014-10-23 10:59:36 -07001499 i++;
1500 prevAdjacencySid = nodeId;
1501 }
1502 else if (checkNeighbor) {
1503 // Check if next node is the neighbor SW of the source SW
1504 List<Dpid> fwdSwDpids = getForwardingSwitchForNodeId(srcSw,
1505 nodeId);
1506 if (fwdSwDpids == null || fwdSwDpids.isEmpty()) {
1507 log.debug("There is no route from node {} to node {}",
1508 srcSw.getDpid(), nodeId);
1509 return null;
1510 }
1511 // If first Id is one of the neighbors, do not include it to route, but set it as a fwd SW.
1512 boolean match = false;
1513 for (Dpid dpid: fwdSwDpids) {
1514 if (getMplsLabel(dpid.toString()).toString().equals(nodeId)) {
1515 List<Dpid> fwdSws = new ArrayList<Dpid>();
1516 fwdSws.add(dpid);
1517 routeInfo.setFwdSwDpid(fwdSws);
1518 match = true;
1519 break;
1520 }
1521 }
1522 if (!match) {
1523 routeInfo.addRoute(nodeId);
1524 routeInfo.setFwdSwDpid(fwdSwDpids);
1525 i++;
1526 }
1527 // we check only the next node ID of the source router
1528 checkNeighbor = false;
1529
1530 // if we don't need to check neighbor
1531 }else {
1532 routeInfo.addRoute(nodeId);
Sangho Shin15273b62014-10-16 22:22:05 -07001533 i++;
1534 }
1535 }
Sangho Shin6471d202014-10-23 10:59:36 -07001536 // if i > 1
Sangho Shin15273b62014-10-16 22:22:05 -07001537 else {
Sangho Shin6471d202014-10-23 10:59:36 -07001538 // If the adjacency SID is pushed and the next SID is the destination
1539 // of the adjacency SID, then do not add the SID.
1540 if (prevAdjacencySid != null) {
1541 if (isAdjacencySidNeighborOf(prevNodeId, prevAdjacencySid, nodeId)) {
1542 prevAdjacencySid = null;
1543 continue;
1544 }
1545 prevAdjacencySid = null;
1546 }
Sangho Shin15273b62014-10-16 22:22:05 -07001547 routeInfo.addRoute(nodeId);
1548 i++;
1549 }
1550
Sangho Shin1ad7be02014-10-20 16:56:49 -07001551 // If the number of labels reaches the limit, start over the procedure
Sangho Shin15273b62014-10-16 22:22:05 -07001552 if (i == MAX_NUM_LABELS+1) {
Sangho Shin81655442014-10-20 14:22:46 -07001553 rules.add(routeInfo);
Sangho Shine020cc32014-10-20 13:28:02 -07001554 routeInfo = new TunnelRouteInfo();
Sangho Shin15273b62014-10-16 22:22:05 -07001555 srcSw = getSwitchFromNodeId(nodeId);
1556 srcDpid = getSwitchFromNodeId(nodeId).getDpid().toString();
1557 routeInfo.setSrcDpid(srcDpid);
1558 i = 1;
1559 checkNeighbor = true;
1560 }
Sangho Shin6471d202014-10-23 10:59:36 -07001561
1562 if (prevAdjacencySid == null)
1563 prevNodeId = nodeId;
Sangho Shin15273b62014-10-16 22:22:05 -07001564 }
1565
1566 if (i < MAX_NUM_LABELS+1) {
Sangho Shin81655442014-10-20 14:22:46 -07001567 rules.add(routeInfo);
Sangho Shin15273b62014-10-16 22:22:05 -07001568 }
1569
1570 return rules;
1571 }
1572
Sangho Shin5b8f5452014-10-20 11:46:01 -07001573 /**
1574 * Remove all policies applied to specific tunnel.
1575 *
1576 * @param srcMac
1577 * @param dstMac
1578 * @param etherType
1579 * @param srcIp
1580 * @param dstIp
1581 * @param ipProto
1582 * @param srcTcpPort
1583 * @param dstTcpPort
1584 * @param tid
Sangho Shin306633a2014-10-20 14:26:55 -07001585 * @return
Sangho Shin5b8f5452014-10-20 11:46:01 -07001586 */
Sangho Shin306633a2014-10-20 14:26:55 -07001587 public boolean removePolicy(String pid) {
Sangho Shine020cc32014-10-20 13:28:02 -07001588 PolicyInfo policyInfo = policyTable.get(pid);
Sangho Shin5671cbb2014-10-20 22:35:41 -07001589 if (policyInfo == null)
1590 return false;
Sangho Shin5b8f5452014-10-20 11:46:01 -07001591 PacketMatch policyMatch = policyInfo.match;
Sangho Shine020cc32014-10-20 13:28:02 -07001592 String tid = policyInfo.tunnelId;
Sangho Shin5b8f5452014-10-20 11:46:01 -07001593 int priority = policyInfo.priority;
1594
1595 List<Action> actions = new ArrayList<>();
1596 int gropuId = 0; // dummy group ID
1597 GroupAction groupAction = new GroupAction();
1598 groupAction.setGroupId(gropuId);
1599 actions.add(groupAction);
1600
1601 MatchAction matchAction = new MatchAction(new MatchActionId(
1602 matchActionId++),
1603 new SwitchPort((long) 0, (short) 0), policyMatch, priority,
1604 actions);
1605 MatchActionOperationEntry maEntry =
1606 new MatchActionOperationEntry(Operator.REMOVE, matchAction);
1607
Sangho Shin81655442014-10-20 14:22:46 -07001608 TunnelInfo tunnelInfo = tunnelTable.get(tid);
Sangho Shin5671cbb2014-10-20 22:35:41 -07001609 if (tunnelInfo == null)
1610 return false;
Sangho Shin81655442014-10-20 14:22:46 -07001611 List<TunnelRouteInfo> routes = tunnelInfo.routes;
1612
1613 for (TunnelRouteInfo route : routes) {
Sangho Shin5b8f5452014-10-20 11:46:01 -07001614 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin81655442014-10-20 14:22:46 -07001615 getSwId(route.srcSwDpid));
Sangho Shin5b8f5452014-10-20 11:46:01 -07001616
Sangho Shin5671cbb2014-10-20 22:35:41 -07001617 if (sw13 == null) {
1618 return false;
1619 }
1620 else {
Sangho Shin5b8f5452014-10-20 11:46:01 -07001621 printMatchActionOperationEntry(sw13, maEntry);
1622 try {
1623 sw13.pushFlow(maEntry);
1624 } catch (IOException e) {
1625 e.printStackTrace();
1626 log.debug("policy remove failed due to pushFlow() exception");
Sangho Shin306633a2014-10-20 14:26:55 -07001627 return false;
Sangho Shin5b8f5452014-10-20 11:46:01 -07001628 }
1629 }
1630 }
1631
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001632 policyTable.remove(pid);
Sangho Shin5b8f5452014-10-20 11:46:01 -07001633 log.debug("Policy {} is removed.", pid);
Sangho Shin306633a2014-10-20 14:26:55 -07001634 return true;
Sangho Shine020cc32014-10-20 13:28:02 -07001635 }
Sangho Shin5b8f5452014-10-20 11:46:01 -07001636
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001637 /**
1638 * Remove a tunnel
1639 * It removes all groups for the tunnel if the tunnel is not used for any
1640 * policy.
1641 *
1642 * @param tunnelId tunnel ID to remove
1643 */
Sangho Shin306633a2014-10-20 14:26:55 -07001644 public boolean removeTunnel(String tunnelId) {
Sangho Shin55d00e12014-10-20 12:13:07 -07001645
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001646 // Check if the tunnel is used for any policy
1647 for (PolicyInfo policyInfo: policyTable.values()) {
Sangho Shina000c612014-10-21 14:17:59 -07001648 if (policyInfo.tunnelId.equals(tunnelId)) {
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001649 log.debug("Tunnel {} is still used for the policy {}.",
1650 policyInfo.policyId, tunnelId);
1651 return false;
1652 }
1653 }
1654
1655 TunnelInfo tunnelInfo = tunnelTable.get(tunnelId);
Sangho Shin5671cbb2014-10-20 22:35:41 -07001656 if (tunnelInfo == null)
1657 return false;
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001658
1659 List<TunnelRouteInfo> routes = tunnelInfo.routes;
1660 for (TunnelRouteInfo route: routes) {
1661 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
1662 getSwId(route.srcSwDpid));
1663
Sangho Shin5671cbb2014-10-20 22:35:41 -07001664 if (sw13 == null) {
1665 return false;
1666 }
1667 else {
Sangho Shin79dc5172014-10-23 11:15:12 -07001668 sw13.removeGroup(route.getGroupId());
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001669 }
1670 }
1671
1672 tunnelTable.remove(tunnelId);
1673 log.debug("Tunnel {} was removed ", tunnelId);
1674
Sangho Shin306633a2014-10-20 14:26:55 -07001675 return true;
Sangho Shin55d00e12014-10-20 12:13:07 -07001676 }
1677
Sangho Shin7330c032014-10-20 10:34:51 -07001678 // ************************************
1679 // Utility functions
1680 // ************************************
1681
Sangho Shin6471d202014-10-23 10:59:36 -07001682 private List<PortNumber> getPortsFromNeighborSet(String srcSwDpid, NeighborSet ns) {
1683
1684 List<PortNumber> portList = new ArrayList<PortNumber>();
1685 Switch srcSwitch = mutableTopology.getSwitch(new Dpid(srcSwDpid));
1686 if (srcSwitch == null)
1687 return null;
1688 for (Dpid neighborDpid: ns.getDpids()) {
1689 Link link = srcSwitch.getLinkToNeighbor(neighborDpid);
1690 portList.add(link.getSrcPort().getNumber());
1691 }
1692
1693 return portList;
1694 }
1695
1696 private boolean isAdjacencySidNeighborOf(String prevNodeId, String prevAdjacencySid, String nodeId) {
1697
1698 HashMap<Integer, List<Integer>> adjacencySidInfo = adjacencySidTable.get(Integer.valueOf(prevNodeId));
1699 List<Integer> ports = adjacencySidInfo.get(Integer.valueOf(prevAdjacencySid));
1700
1701 for (Integer port: ports) {
1702 Switch sw = getSwitchFromNodeId(prevNodeId);
1703 for (Link link: sw.getOutgoingLinks()) {
1704 if (link.getSrcPort().getPortNumber().value() == port) {
1705 if (getMplsLabel(link.getDstPort().getDpid().toString()).equals(nodeId)) {
1706 return true;
1707 }
1708 }
1709 }
1710 }
1711
1712 return false;
1713 }
1714
1715 private boolean isAdjacencySid(String nodeId) {
1716 // XXX The rule might change
1717 if (Integer.parseInt(nodeId) > 10000)
1718 return true;
1719
1720 return false;
1721 }
1722
Sangho Shin15273b62014-10-16 22:22:05 -07001723 /**
Sangho Shinced05b62014-10-22 11:23:14 -07001724 * Returns the Adjacency IDs for the node
1725 *
1726 * @param nodeSid Node SID
Sangho Shincfef3922014-10-22 12:04:16 -07001727 * @return Collection of Adjacency ID
Sangho Shinced05b62014-10-22 11:23:14 -07001728 */
Sangho Shincfef3922014-10-22 12:04:16 -07001729 public Collection<Integer> getAdjacencyIds(int nodeSid) {
1730 HashMap<Integer, List<Integer>> adjecencyInfo =
Sangho Shin6471d202014-10-23 10:59:36 -07001731 adjacencySidTable.get(Integer.valueOf(nodeSid));
Sangho Shincfef3922014-10-22 12:04:16 -07001732
1733 return adjecencyInfo.keySet();
1734 }
1735
1736 /**
1737 * Returns the Adjacency Info for the node
1738 *
1739 * @param nodeSid Node SID
1740 * @return HashMap of <AdjacencyID, list of ports>
1741 */
1742 public HashMap<Integer, List<Integer>> getAdjacencyInfo(int nodeSid) {
Sangho Shin6471d202014-10-23 10:59:36 -07001743 return adjacencySidTable.get(Integer.valueOf(nodeSid));
Sangho Shincfef3922014-10-22 12:04:16 -07001744 }
1745
1746 private HashMap<Integer, List<Integer>> parseAdjacencySidInfo(String adjInfo) throws JSONException {
1747 JSONArray arry = new JSONArray(adjInfo);
1748 HashMap<Integer, List<Integer>> AdjacencyInfo =
1749 new HashMap<Integer, List<Integer>>();
1750
1751 for (int i = 0; i < arry.length(); i++) {
1752 Integer adjId = (Integer) arry.getJSONObject(i).get("adjSid");
1753 JSONArray portNos = (JSONArray) arry.getJSONObject(i).get("ports");
1754 if (adjId == null || portNos == null)
1755 continue;
1756
1757 List<Integer> portNoList = new ArrayList<Integer>();
1758 for (int j = 0; j < portNos.length(); j++) {
1759 portNoList.add(Integer.valueOf(portNos.getInt(0)));
1760 }
1761 AdjacencyInfo.put(adjId, portNoList);
1762 }
1763 return AdjacencyInfo;
Sangho Shinced05b62014-10-22 11:23:14 -07001764 }
1765
1766 /**
Sangho Shin7330c032014-10-20 10:34:51 -07001767 * Get the forwarding Switch DPIDs to send packets to a node
Sangho Shin15273b62014-10-16 22:22:05 -07001768 *
Sangho Shin7330c032014-10-20 10:34:51 -07001769 * @param srcSw source switch
1770 * @param nodeId destination node Id
1771 * @return list of switch DPID to forward packets to
Sangho Shin15273b62014-10-16 22:22:05 -07001772 */
Sangho Shin7330c032014-10-20 10:34:51 -07001773 private List<Dpid> getForwardingSwitchForNodeId(Switch srcSw, String nodeId) {
Sangho Shin15273b62014-10-16 22:22:05 -07001774
Sangho Shin7330c032014-10-20 10:34:51 -07001775 List<Dpid> fwdSws = new ArrayList<Dpid>();
1776 Switch destSw = null;
Sangho Shin15273b62014-10-16 22:22:05 -07001777
Sangho Shin7330c032014-10-20 10:34:51 -07001778 destSw = getSwitchFromNodeId(nodeId);
1779
1780 if (destSw == null) {
1781 log.debug("Cannot find the switch with ID {}", nodeId);
1782 return null;
1783 }
1784
1785 ECMPShortestPathGraph ecmpSPG = new ECMPShortestPathGraph(srcSw);
1786
1787 HashMap<Integer, HashMap<Switch, ArrayList<ArrayList<Dpid>>>> switchVia =
1788 ecmpSPG.getAllLearnedSwitchesAndVia();
1789 for (Integer itrIdx : switchVia.keySet()) {
1790 HashMap<Switch, ArrayList<ArrayList<Dpid>>> swViaMap =
1791 switchVia.get(itrIdx);
1792 for (Switch targetSw : swViaMap.keySet()) {
1793 String destSwDpid = destSw.getDpid().toString();
1794 if (targetSw.getDpid().toString().equals(destSwDpid)) {
1795 for (ArrayList<Dpid> via : swViaMap.get(targetSw)) {
1796 if (via.isEmpty()) {
1797 fwdSws.add(destSw.getDpid());
1798 }
1799 else {
Sangho Shina000c612014-10-21 14:17:59 -07001800 Dpid firstVia = via.get(via.size()-1);
1801 fwdSws.add(firstVia);
Sangho Shin7330c032014-10-20 10:34:51 -07001802 }
1803 }
1804 }
1805 }
1806 }
1807
1808 return fwdSws;
Sangho Shin15273b62014-10-16 22:22:05 -07001809 }
1810
Sangho Shin7330c032014-10-20 10:34:51 -07001811 /**
1812 * Get switch for the node Id specified
1813 *
1814 * @param nodeId node ID for switch
1815 * @return Switch
1816 */
1817 private Switch getSwitchFromNodeId(String nodeId) {
Fahad Naeem Khan4444b952014-10-18 22:30:50 -07001818
Sangho Shin7330c032014-10-20 10:34:51 -07001819 for (Switch sw : mutableTopology.getSwitches()) {
1820 String id = sw.getStringAttribute("nodeSid");
1821 if (id.equals(nodeId)) {
1822 return sw;
1823 }
1824 }
1825
1826 return null;
1827 }
Fahad Naeem Khan4444b952014-10-18 22:30:50 -07001828
Sangho Shin43cee112014-09-25 16:43:34 -07001829 /**
Sangho Shin7330c032014-10-20 10:34:51 -07001830 * Convert a string DPID to its Switch Id (integer)
Sangho Shinfbc572c2014-10-02 16:37:05 -07001831 *
Sangho Shin7330c032014-10-20 10:34:51 -07001832 * @param dpid
1833 * @return
Sangho Shin43cee112014-09-25 16:43:34 -07001834 */
Sangho Shin7330c032014-10-20 10:34:51 -07001835 private long getSwId(String dpid) {
Sangho Shin43cee112014-09-25 16:43:34 -07001836
Sangho Shin7330c032014-10-20 10:34:51 -07001837 long swId = 0;
Sangho Shin43cee112014-09-25 16:43:34 -07001838
Sangho Shin7330c032014-10-20 10:34:51 -07001839 String swIdHexStr = "0x"+dpid.substring(dpid.lastIndexOf(":") + 1);
1840 if (swIdHexStr != null)
1841 swId = Integer.decode(swIdHexStr);
Sangho Shin43cee112014-09-25 16:43:34 -07001842
Sangho Shin7330c032014-10-20 10:34:51 -07001843 return swId;
1844 }
Sangho Shin43cee112014-09-25 16:43:34 -07001845
Sangho Shin7330c032014-10-20 10:34:51 -07001846 /**
1847 * Check if the switch is the edge router or not.
1848 *
1849 * @param dpid Dpid of the switch to check
1850 * @return true if it is an edge router, otherwise false
1851 */
1852 private boolean IsEdgeRouter(String dpid) {
Sangho Shin0df01982014-09-25 17:11:18 -07001853
Sangho Shin7330c032014-10-20 10:34:51 -07001854 for (Switch sw : mutableTopology.getSwitches()) {
1855 String dpidStr = sw.getDpid().toString();
1856 if (dpid.equals(dpidStr)) {
1857 /*
1858 String subnetInfo = sw.getStringAttribute("subnets");
1859 if (subnetInfo == null || subnetInfo.equals("[]")) {
1860 return false;
1861 }
1862 else
1863 return true;
1864 */
1865 String isEdge = sw.getStringAttribute("isEdgeRouter");
1866 if (isEdge != null) {
1867 if (isEdge.equals("true"))
1868 return true;
1869 else
1870 return false;
1871 }
Sangho Shin43cee112014-09-25 16:43:34 -07001872 }
1873 }
1874
Sangho Shin7330c032014-10-20 10:34:51 -07001875 return false;
Sangho Shineb083032014-09-22 16:11:34 -07001876 }
1877
1878 /**
1879 * Get MPLS label reading the config file
Sangho Shinfbc572c2014-10-02 16:37:05 -07001880 *
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001881 * @param dipid DPID of the switch
Sangho Shineb083032014-09-22 16:11:34 -07001882 * @return MPLS label for the switch
1883 */
Sangho Shin43cee112014-09-25 16:43:34 -07001884 private String getMplsLabel(String dpid) {
Sangho Shineb083032014-09-22 16:11:34 -07001885
1886 String mplsLabel = null;
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001887 for (Switch sw : mutableTopology.getSwitches()) {
Sangho Shin43cee112014-09-25 16:43:34 -07001888 String dpidStr = sw.getDpid().toString();
1889 if (dpid.equals(dpidStr)) {
Sangho Shineb083032014-09-22 16:11:34 -07001890 mplsLabel = sw.getStringAttribute("nodeSid");
1891 break;
Sangho Shin1aa93542014-09-22 09:49:44 -07001892 }
1893 }
1894
Sangho Shineb083032014-09-22 16:11:34 -07001895 return mplsLabel;
Sangho Shin1aa93542014-09-22 09:49:44 -07001896 }
1897
Sangho Shineb083032014-09-22 16:11:34 -07001898 /**
Sangho Shin1aa93542014-09-22 09:49:44 -07001899 * The function checks if given IP matches to the given subnet mask
Sangho Shinfbc572c2014-10-02 16:37:05 -07001900 *
Sangho Shin1aa93542014-09-22 09:49:44 -07001901 * @param addr - subnet address to match
1902 * @param addr1 - IP address to check
1903 * @return true if the IP address matches to the subnet, otherwise false
1904 */
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001905 public boolean netMatch(String addr, String addr1) { // addr is subnet
1906 // address and addr1 is
1907 // ip address. Function
1908 // will return true, if
1909 // addr1 is within
1910 // addr(subnet)
Sangho Shin1aa93542014-09-22 09:49:44 -07001911
1912 String[] parts = addr.split("/");
1913 String ip = parts[0];
1914 int prefix;
1915
1916 if (parts.length < 2) {
1917 prefix = 0;
1918 } else {
1919 prefix = Integer.parseInt(parts[1]);
1920 }
1921
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001922 Inet4Address a = null;
1923 Inet4Address a1 = null;
Sangho Shin1aa93542014-09-22 09:49:44 -07001924 try {
1925 a = (Inet4Address) InetAddress.getByName(ip);
1926 a1 = (Inet4Address) InetAddress.getByName(addr1);
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001927 } catch (UnknownHostException e) {
1928 }
Sangho Shin1aa93542014-09-22 09:49:44 -07001929
1930 byte[] b = a.getAddress();
1931 int ipInt = ((b[0] & 0xFF) << 24) |
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001932 ((b[1] & 0xFF) << 16) |
1933 ((b[2] & 0xFF) << 8) |
1934 ((b[3] & 0xFF) << 0);
Sangho Shin1aa93542014-09-22 09:49:44 -07001935
1936 byte[] b1 = a1.getAddress();
1937 int ipInt1 = ((b1[0] & 0xFF) << 24) |
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001938 ((b1[1] & 0xFF) << 16) |
1939 ((b1[2] & 0xFF) << 8) |
1940 ((b1[3] & 0xFF) << 0);
Sangho Shin1aa93542014-09-22 09:49:44 -07001941
1942 int mask = ~((1 << (32 - prefix)) - 1);
1943
1944 if ((ipInt & mask) == (ipInt1 & mask)) {
1945 return true;
1946 }
1947 else {
1948 return false;
1949 }
1950 }
Sangho Shineb083032014-09-22 16:11:34 -07001951
Sangho Shinac5ee2b2014-09-28 21:27:20 -07001952 /**
1953 * Add a routing rule for the host
Sangho Shinfbc572c2014-10-02 16:37:05 -07001954 *
Sangho Shinac5ee2b2014-09-28 21:27:20 -07001955 * @param sw - Switch to add the rule
1956 * @param hostIpAddress Destination host IP address
1957 * @param hostMacAddress Destination host MAC address
1958 */
Sangho Shineb083032014-09-22 16:11:34 -07001959 public void addRouteToHost(Switch sw, int hostIpAddress, byte[] hostMacAddress) {
1960 ipHandler.addRouteToHost(sw, hostIpAddress, hostMacAddress);
Sangho Shineb083032014-09-22 16:11:34 -07001961 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -07001962
Sangho Shin463bee52014-09-29 15:14:43 -07001963 /**
1964 * Add IP packet to a buffer queue
Sangho Shinfbc572c2014-10-02 16:37:05 -07001965 *
Sangho Shin463bee52014-09-29 15:14:43 -07001966 * @param ipv4
1967 */
Sangho Shin7330c032014-10-20 10:34:51 -07001968 public void addPacketToPacketBuffer(IPv4 ipv4) {
Sangho Shin61535402014-10-01 11:37:14 -07001969 ipPacketQueue.add(ipv4);
Sangho Shin463bee52014-09-29 15:14:43 -07001970 }
1971
1972 /**
1973 * Retrieve all packets whose destination is the given address.
Sangho Shinfbc572c2014-10-02 16:37:05 -07001974 *
Sangho Shin463bee52014-09-29 15:14:43 -07001975 * @param destIp Destination address of packets to retrieve
1976 */
1977 public List<IPv4> getIpPacketFromQueue(byte[] destIp) {
1978
1979 List<IPv4> bufferedPackets = new ArrayList<IPv4>();
1980
Sangho Shin61535402014-10-01 11:37:14 -07001981 if (!ipPacketQueue.isEmpty()) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001982 for (IPv4 ip : ipPacketQueue) {
Sangho Shin61535402014-10-01 11:37:14 -07001983 int dest = ip.getDestinationAddress();
1984 IPv4Address ip1 = IPv4Address.of(dest);
1985 IPv4Address ip2 = IPv4Address.of(destIp);
1986 if (ip1.equals(ip2)) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001987 bufferedPackets.add((IPv4) (ipPacketQueue.poll()).clone());
Sangho Shin463bee52014-09-29 15:14:43 -07001988 }
1989 }
1990 }
1991
1992 return bufferedPackets;
1993 }
1994
Sangho Shin7330c032014-10-20 10:34:51 -07001995 /**
1996 * Get MAC address to known hosts
1997 *
1998 * @param destinationAddress IP address to get MAC address
1999 * @return MAC Address to given IP address
2000 */
2001 public byte[] getMacAddressFromIpAddress(int destinationAddress) {
2002
2003 // Can't we get the host IP address from the TopologyService ??
2004
2005 Iterator<ArpEntry> iterator = arpEntries.iterator();
2006
2007 IPv4Address ipAddress = IPv4Address.of(destinationAddress);
2008 byte[] ipAddressInByte = ipAddress.getBytes();
2009
2010 while (iterator.hasNext()) {
2011 ArpEntry arpEntry = iterator.next();
2012 byte[] address = arpEntry.targetIpAddress;
2013
2014 IPv4Address a = IPv4Address.of(address);
2015 IPv4Address b = IPv4Address.of(ipAddressInByte);
2016
2017 if (a.equals(b)) {
2018 log.debug("Found an arp entry");
2019 return arpEntry.targetMacAddress;
2020 }
2021 }
2022
2023 return null;
2024 }
2025
2026 /**
2027 * Send an ARP request via ArpHandler
2028 *
2029 * @param destinationAddress
2030 * @param sw
2031 * @param inPort
2032 *
2033 */
2034 public void sendArpRequest(Switch sw, int destinationAddress, Port inPort) {
2035 arpHandler.sendArpRequest(sw, destinationAddress, inPort);
2036 }
2037
2038
2039 // ************************************
2040 // Test functions
2041 // ************************************
2042
Sangho Shin55d00e12014-10-20 12:13:07 -07002043 private void runTest() {
2044
2045 if (testMode == POLICY_ADD1) {
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07002046 Integer[] routeArray = {101, 105, 110};
2047 /*List<Dpid> routeList = new ArrayList<Dpid>();
Sangho Shin55d00e12014-10-20 12:13:07 -07002048 for (int i = 0; i < routeArray.length; i++) {
2049 Dpid dpid = getSwitchFromNodeId(routeArray[i]).getDpid();
2050 routeList.add(dpid);
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07002051 }*/
Sangho Shin55d00e12014-10-20 12:13:07 -07002052
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07002053 if (createTunnel("1", Arrays.asList(routeArray))) {
Sangho Shin55d00e12014-10-20 12:13:07 -07002054 IPv4Net srcIp = new IPv4Net("10.0.1.1/24");
2055 IPv4Net dstIp = new IPv4Net("10.1.2.1/24");
2056
2057 log.debug("Set the policy 1");
Sangho Shine020cc32014-10-20 13:28:02 -07002058 this.createPolicy("1", null, null, Ethernet.TYPE_IPV4, srcIp,
Sangho Shin55d00e12014-10-20 12:13:07 -07002059 dstIp, IPv4.PROTOCOL_ICMP, (short)-1, (short)-1, 10000,
Sangho Shine020cc32014-10-20 13:28:02 -07002060 "1");
Sangho Shin55d00e12014-10-20 12:13:07 -07002061 testMode = POLICY_ADD2;
Sangho Shin4b46bcd2014-10-20 15:48:47 -07002062 testTask.reschedule(5, TimeUnit.SECONDS);
Sangho Shin55d00e12014-10-20 12:13:07 -07002063 }
2064 else {
2065 // retry it
2066 testTask.reschedule(5, TimeUnit.SECONDS);
2067 }
2068 }
2069 else if (testMode == POLICY_ADD2) {
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07002070 Integer[] routeArray = {101, 102, 103, 104, 105, 108, 110};
Sangho Shin55d00e12014-10-20 12:13:07 -07002071
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07002072 if (createTunnel("2", Arrays.asList(routeArray))) {
Sangho Shin55d00e12014-10-20 12:13:07 -07002073 IPv4Net srcIp = new IPv4Net("10.0.1.1/24");
2074 IPv4Net dstIp = new IPv4Net("10.1.2.1/24");
2075
2076 log.debug("Set the policy 2");
Sangho Shine020cc32014-10-20 13:28:02 -07002077 this.createPolicy("2", null, null, Ethernet.TYPE_IPV4, srcIp,
Sangho Shin55d00e12014-10-20 12:13:07 -07002078 dstIp, IPv4.PROTOCOL_ICMP, (short)-1, (short)-1, 20000,
Sangho Shine020cc32014-10-20 13:28:02 -07002079 "2");
Fahad Naeem Khan95aa4012014-10-21 14:07:00 -07002080 //testMode = POLICY_REMOVE2;
2081 //testTask.reschedule(5, TimeUnit.SECONDS);
Sangho Shin55d00e12014-10-20 12:13:07 -07002082 }
2083 else {
2084 log.debug("Retry it");
2085 testTask.reschedule(5, TimeUnit.SECONDS);
2086 }
2087 }
2088 else if (testMode == POLICY_REMOVE2){
2089 log.debug("Remove the policy 2");
Sangho Shine020cc32014-10-20 13:28:02 -07002090 this.removePolicy("2");
Sangho Shin55d00e12014-10-20 12:13:07 -07002091 testMode = POLICY_REMOVE1;
Sangho Shin4b46bcd2014-10-20 15:48:47 -07002092 testTask.reschedule(5, TimeUnit.SECONDS);
Sangho Shin55d00e12014-10-20 12:13:07 -07002093 }
2094 else if (testMode == POLICY_REMOVE1){
2095 log.debug("Remove the policy 1");
Sangho Shine020cc32014-10-20 13:28:02 -07002096 this.removePolicy("1");
Sangho Shin55d00e12014-10-20 12:13:07 -07002097
Sangho Shin4b46bcd2014-10-20 15:48:47 -07002098 testMode = TUNNEL_REMOVE1;
2099 testTask.reschedule(5, TimeUnit.SECONDS);
2100 }
2101 else if (testMode == TUNNEL_REMOVE1) {
2102 log.debug("Remove the tunnel 1");
2103 this.removeTunnel("1");
2104
2105 testMode = TUNNEL_REMOVE2;
2106 testTask.reschedule(5, TimeUnit.SECONDS);
2107 }
2108 else if (testMode == TUNNEL_REMOVE2) {
2109 log.debug("Remove the tunnel 2");
2110 this.removeTunnel("2");
2111 log.debug("The end of test");
2112 }
Sangho Shin55d00e12014-10-20 12:13:07 -07002113 }
Sangho Shin7330c032014-10-20 10:34:51 -07002114
2115 private void runTest1() {
2116
2117 String dpid1 = "00:00:00:00:00:00:00:01";
2118 String dpid2 = "00:00:00:00:00:00:00:0a";
2119 Switch srcSw = mutableTopology.getSwitch(new Dpid(dpid1));
2120 Switch dstSw = mutableTopology.getSwitch(new Dpid(dpid2));
2121
2122 if (srcSw == null || dstSw == null) {
2123 testTask.reschedule(1, TimeUnit.SECONDS);
2124 log.debug("Switch is gone. Reschedule the test");
2125 return;
2126 }
2127
2128 String[] routeArray = {"101", "102", "105", "108", "110"};
2129 List<String> routeList = new ArrayList<String>();
2130 for (int i = 0; i < routeArray.length; i++)
2131 routeList.add(routeArray[i]);
2132
2133 List<String> optimizedRoute = this.getOptimizedPath(srcSw, dstSw, routeList);
2134
2135 log.debug("Test set is {}", routeList.toString());
2136 log.debug("Result set is {}", optimizedRoute.toString());
2137
2138
2139 }
2140
2141 /**
2142 * print tunnel info - used only for debugging.
2143 * @param targetSw
2144 *
2145 * @param fwdSwDpids
2146 * @param ids
2147 * @param tunnelId
2148 */
Sangho Shin6471d202014-10-23 10:59:36 -07002149 private void printTunnelInfo(String targetSw, String tunnelId,
Sangho Shin7330c032014-10-20 10:34:51 -07002150 List<String> ids, NeighborSet ns) {
2151 StringBuilder logStr = new StringBuilder("In switch " +
Sangho Shin6471d202014-10-23 10:59:36 -07002152 targetSw + ", create a tunnel " + tunnelId + " " + " of push ");
Sangho Shin7330c032014-10-20 10:34:51 -07002153 for (String id: ids)
2154 logStr.append(id + "-");
2155 logStr.append(" output to ");
2156 for (Dpid dpid: ns.getDpids())
2157 logStr.append(dpid + " - ");
2158
2159 log.debug(logStr.toString());
2160
2161 }
2162
2163 /**
2164 * Debugging function to print out the Match Action Entry
2165 * @param sw13
2166 *
2167 * @param maEntry
2168 */
2169 private void printMatchActionOperationEntry(
2170 IOF13Switch sw13, MatchActionOperationEntry maEntry) {
2171
2172 StringBuilder logStr = new StringBuilder("In switch " + sw13.getId() + ", ");
2173
2174 MatchAction ma = maEntry.getTarget();
2175 Match m = ma.getMatch();
2176 List<Action> actions = ma.getActions();
2177
2178 if (m instanceof Ipv4Match) {
2179 logStr.append("If the IP matches with ");
2180 IPv4Net ip = ((Ipv4Match) m).getDestination();
2181 logStr.append(ip.toString());
2182 logStr.append(" then ");
2183 }
2184 else if (m instanceof MplsMatch) {
2185 logStr.append("If the MPLS label matches with ");
2186 int mplsLabel = ((MplsMatch) m).getMplsLabel();
2187 logStr.append(mplsLabel);
2188 logStr.append(" then ");
2189 }
2190 else if (m instanceof PacketMatch) {
2191 GroupAction ga = (GroupAction)actions.get(0);
2192 logStr.append("if the policy match is XXX then go to group " +
2193 ga.getGroupId());
2194 log.debug(logStr.toString());
2195 return;
2196 }
2197
2198 logStr.append(" do { ");
2199 for (Action action : actions) {
2200 if (action instanceof CopyTtlInAction) {
2201 logStr.append("copy ttl In, ");
2202 }
2203 else if (action instanceof CopyTtlOutAction) {
2204 logStr.append("copy ttl Out, ");
2205 }
2206 else if (action instanceof DecMplsTtlAction) {
2207 logStr.append("Dec MPLS TTL , ");
2208 }
2209 else if (action instanceof GroupAction) {
2210 logStr.append("Forward packet to < ");
2211 NeighborSet dpids = ((GroupAction) action).getDpids();
2212 logStr.append(dpids.toString() + ",");
2213
2214 }
2215 else if (action instanceof PopMplsAction) {
2216 logStr.append("Pop MPLS label, ");
2217 }
2218 else if (action instanceof PushMplsAction) {
2219 logStr.append("Push MPLS label, ");
2220 }
2221 else if (action instanceof SetMplsIdAction) {
2222 int id = ((SetMplsIdAction) action).getMplsId();
2223 logStr.append("Set MPLS ID as " + id + ", ");
2224 }
2225 }
2226
2227 log.debug(logStr.toString());
2228
2229 }
2230
2231
2232 // ************************************
2233 // Unused classes and functions
2234 // ************************************
2235
2236 /**
2237 * Temporary class to to keep ARP entry
2238 *
2239 */
2240 private class ArpEntry {
2241
2242 byte[] targetMacAddress;
2243 byte[] targetIpAddress;
2244
2245 private ArpEntry(byte[] macAddress, byte[] ipAddress) {
2246 this.targetMacAddress = macAddress;
2247 this.targetIpAddress = ipAddress;
2248 }
2249 }
2250
2251 /**
2252 * This class is used only for link recovery optimization in
2253 * modifyEcmpRoutingRules() function.
2254 * TODO: please remove if the optimization is not used at all
2255 */
2256 private class SwitchPair {
2257 private Switch src;
2258 private Switch dst;
2259
2260 public SwitchPair(Switch src, Switch dst) {
2261 this.src = src;
2262 this.dst = dst;
2263 }
2264
2265 public Switch getSource() {
2266 return src;
2267 }
2268
2269 public Switch getDestination() {
2270 return dst;
2271 }
2272 }
2273
2274 /**
2275 * Update ARP Cache using ARP packets It is used to set destination MAC
2276 * address to forward packets to known hosts. But, it will be replace with
2277 * Host information of Topology service later.
2278 *
2279 * @param arp APR packets to use for updating ARP entries
2280 */
2281 public void updateArpCache(ARP arp) {
2282
2283 ArpEntry arpEntry = new ArpEntry(arp.getSenderHardwareAddress(),
2284 arp.getSenderProtocolAddress());
2285 // TODO: Need to check the duplication
2286 arpEntries.add(arpEntry);
2287 }
2288
2289 /**
2290 * Modify the routing rules for the lost links
2291 * - Recompute the path if the link failed is included in the path
2292 * (including src and dest).
2293 *
2294 * @param newLink
2295 */
2296 private void modifyEcmpRoutingRules(LinkData linkRemoved) {
2297
2298 //HashMap<Switch, SwitchPair> linksToRecompute = new HashMap<Switch, SwitchPair>();
2299 Set<SwitchPair> linksToRecompute = new HashSet<SwitchPair>();
2300
2301 for (ECMPShortestPathGraph ecmpSPG : graphs.values()) {
2302 Switch rootSw = ecmpSPG.getRootSwitch();
2303 HashMap<Integer, HashMap<Switch, ArrayList<Path>>> paths =
2304 ecmpSPG.getCompleteLearnedSwitchesAndPaths();
2305 for (HashMap<Switch, ArrayList<Path>> p: paths.values()) {
2306 for (Switch destSw: p.keySet()) {
2307 ArrayList<Path> path = p.get(destSw);
2308 if (checkPath(path, linkRemoved)) {
2309 boolean found = false;
2310 for (SwitchPair pair: linksToRecompute) {
2311 if (pair.getSource().getDpid() == rootSw.getDpid() &&
2312 pair.getSource().getDpid() == destSw.getDpid()) {
2313 found = true;
2314 }
2315 }
2316 if (!found) {
2317 linksToRecompute.add(new SwitchPair(rootSw, destSw));
2318 }
2319 }
2320 }
2321 }
2322 }
2323
2324 // Recompute the path for the specific route
2325 for (SwitchPair pair: linksToRecompute) {
2326
2327 log.debug("Recompute path from {} to {}", pair.getSource(), pair.getDestination());
2328 // We need the following function for optimization
2329 //ECMPShortestPathGraph ecmpSPG =
2330 // new ECMPShortestPathGraph(pair.getSource(), pair.getDestination());
2331 ECMPShortestPathGraph ecmpSPG =
2332 new ECMPShortestPathGraph(pair.getSource());
2333 populateEcmpRoutingRulesForPath(pair.getSource(), ecmpSPG, true);
2334 }
2335 }
2336
2337 /**
2338 * Optimize the mpls label
2339 * The feature will be used only for policy of "avoid a specific switch".
2340 * Check route to each router in route backward.
2341 * If there is only one route to the router and the routers are included in
2342 * the route, remove the id from the path.
2343 * A-B-C-D-E => A-B-C-D-E -> A-E
2344 * | | => A-B-H-I -> A-I
Sangho Shin5b8f5452014-10-20 11:46:01 -07002345 * F-G-H-I => A-D-I > A-D-I
Sangho Shin7330c032014-10-20 10:34:51 -07002346 */
2347 private List<String> getOptimizedPath(Switch srcSw, Switch dstSw, List<String> route) {
2348
2349 List<String> optimizedPath = new ArrayList<String>();
2350 optimizedPath.addAll(route);
2351 ECMPShortestPathGraph ecmpSPG = new ECMPShortestPathGraph(srcSw);
2352
2353 HashMap<Integer, HashMap<Switch, ArrayList<Path>>> paths =
2354 ecmpSPG.getCompleteLearnedSwitchesAndPaths();
2355 for (HashMap<Switch, ArrayList<Path>> p: paths.values()) {
2356 for (Switch s: p.keySet()) {
2357 if (s.getDpid().toString().equals(dstSw.getDpid().toString())) {
2358 ArrayList<Path> ecmpPaths = p.get(s);
2359 if (ecmpPaths!= null && ecmpPaths.size() == 1) {
2360 for (Path path: ecmpPaths) {
2361 for (LinkData link: path) {
2362 String srcId = getMplsLabel(link.getSrc().getDpid().toString());
2363 String dstId = getMplsLabel(link.getSrc().getDpid().toString());
2364 if (optimizedPath.contains(srcId)) {
2365 optimizedPath.remove(srcId);
2366 }
2367 if (optimizedPath.contains(dstId)) {
2368 optimizedPath.remove(dstId);
2369 }
2370 }
2371 }
2372 }
2373 }
2374 }
2375 }
2376
2377 return optimizedPath;
2378
2379 }
2380
2381 /**
2382 * Check if the path is affected from the link removed
2383 *
2384 * @param path Path to check
2385 * @param linkRemoved link removed
2386 * @return true if the path contains the link removed
2387 */
2388 private boolean checkPath(ArrayList<Path> path, LinkData linkRemoved) {
2389
2390 for (Path ppp: path) {
2391 // TODO: need to check if this is a bidirectional or
2392 // unidirectional
2393 for (LinkData link: ppp) {
2394 if (link.getDst().getDpid().equals(linkRemoved.getDst().getDpid()) &&
2395 link.getSrc().getDpid().equals(linkRemoved.getSrc().getDpid()))
2396 return true;
2397 }
2398 }
2399
2400 return false;
2401 }
Sangho Shin15273b62014-10-16 22:22:05 -07002402
2403
Sangho Shin2f263692014-09-15 14:09:41 -07002404}