blob: 4c9c1d515ca1f6b840276f43e7d0eb9e53fce5e6 [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 Shin1a692c02014-10-23 17:05:41 -07001335 /**
1336 * Create groups for the tunnel
1337 *
1338 * @param tunnelId tunnel ID
1339 * @param routeInfo label stacks for the tunnel
1340 * @param ns NeighborSet to forward packets
1341 * @return group ID, return -1 if it fails
1342 */
Sangho Shin6471d202014-10-23 10:59:36 -07001343 private int createGroupsForTunnel(String tunnelId, TunnelRouteInfo routeInfo,
1344 NeighborSet ns) {
1345
1346 IOF13Switch targetSw = (IOF13Switch) floodlightProvider.getMasterSwitch(
1347 getSwId(routeInfo.srcSwDpid));
1348
1349 if (targetSw == null) {
1350 log.debug("Switch {} is gone.", routeInfo.srcSwDpid);
1351 return -1;
1352 }
1353
1354 List<Integer> Ids = new ArrayList<Integer>();
1355 for (String IdStr: routeInfo.route)
1356 Ids.add(Integer.parseInt(IdStr));
1357
1358 List<PortNumber> ports = getPortsFromNeighborSet(routeInfo.srcSwDpid, ns);
1359 int groupId = targetSw.createGroup(Ids, ports);
1360
1361 return groupId;
1362 }
1363
Sangho Shin15273b62014-10-16 22:22:05 -07001364 /**
1365 * Set policy table for policy routing
1366 *
1367 * @param sw
1368 * @param mplsLabel
Sangho Shin306633a2014-10-20 14:26:55 -07001369 * @return
Sangho Shin15273b62014-10-16 22:22:05 -07001370 */
Sangho Shin306633a2014-10-20 14:26:55 -07001371 public boolean createPolicy(String pid, MACAddress srcMac, MACAddress dstMac,
Sangho Shin15273b62014-10-16 22:22:05 -07001372 Short etherType, IPv4Net srcIp, IPv4Net dstIp, Byte ipProto,
Sangho Shine020cc32014-10-20 13:28:02 -07001373 Short srcTcpPort, Short dstTcpPort, int priority, String tid) {
Sangho Shin15273b62014-10-16 22:22:05 -07001374
Sangho Shin5b8f5452014-10-20 11:46:01 -07001375 PacketMatchBuilder packetBuilder = new PacketMatchBuilder();
1376
1377 if (srcMac != null)
1378 packetBuilder.setSrcMac(srcMac);
1379 if (dstMac != null)
1380 packetBuilder.setDstMac(dstMac);
Sangho Shin58182672014-10-21 13:23:38 -07001381 if (etherType == null) // Cqpd requires the type of IPV4
1382 packetBuilder.setEtherType(Ethernet.TYPE_IPV4);
1383 else
Sangho Shin5b8f5452014-10-20 11:46:01 -07001384 packetBuilder.setEtherType(etherType);
1385 if (srcIp != null)
1386 packetBuilder.setSrcIp(srcIp.address(), srcIp.prefixLen());
1387 if (dstIp != null)
1388 packetBuilder.setDstIp(dstIp.address(), dstIp.prefixLen());
1389 if (ipProto != null)
1390 packetBuilder.setIpProto(ipProto);
1391 if (srcTcpPort > 0)
1392 packetBuilder.setSrcTcpPort(srcTcpPort);
1393 if (dstTcpPort > 0)
1394 packetBuilder.setDstTcpPort(dstTcpPort);
1395 PacketMatch policyMatch = packetBuilder.build();
Sangho Shin81655442014-10-20 14:22:46 -07001396 TunnelInfo tunnelInfo = tunnelTable.get(tid);
Sangho Shin6471d202014-10-23 10:59:36 -07001397 if (tunnelInfo == null) {
1398 log.debug("Tunnel {} is not defined", tid);
1399 return false;
1400 }
Sangho Shin81655442014-10-20 14:22:46 -07001401 List<TunnelRouteInfo> routes = tunnelInfo.routes;
Sangho Shin5b8f5452014-10-20 11:46:01 -07001402
Sangho Shin81655442014-10-20 14:22:46 -07001403 for (TunnelRouteInfo route : routes) {
Sangho Shin15273b62014-10-16 22:22:05 -07001404 List<Action> actions = new ArrayList<>();
1405 GroupAction groupAction = new GroupAction();
Sangho Shin6471d202014-10-23 10:59:36 -07001406 groupAction.setGroupId(route.getGroupId());
Sangho Shin15273b62014-10-16 22:22:05 -07001407 actions.add(groupAction);
1408
1409 MatchAction matchAction = new MatchAction(new MatchActionId(
1410 matchActionId++),
Sangho Shin5b8f5452014-10-20 11:46:01 -07001411 new SwitchPort((long) 0, (short) 0), policyMatch, priority,
1412 actions);
Sangho Shin15273b62014-10-16 22:22:05 -07001413 MatchActionOperationEntry maEntry =
1414 new MatchActionOperationEntry(Operator.ADD, matchAction);
1415
1416 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin81655442014-10-20 14:22:46 -07001417 getSwId(route.srcSwDpid));
Sangho Shin15273b62014-10-16 22:22:05 -07001418
1419 if (sw13 != null) {
1420 printMatchActionOperationEntry(sw13, maEntry);
1421 try {
1422 sw13.pushFlow(maEntry);
1423 } catch (IOException e) {
1424 e.printStackTrace();
Sangho Shin306633a2014-10-20 14:26:55 -07001425 return false;
Sangho Shin15273b62014-10-16 22:22:05 -07001426 }
1427 }
1428 }
Sangho Shin5b8f5452014-10-20 11:46:01 -07001429
1430 PolicyInfo policyInfo = new PolicyInfo(pid, policyMatch, priority, tid);
Sangho Shine020cc32014-10-20 13:28:02 -07001431 policyTable.put(pid, policyInfo);
Sangho Shin306633a2014-10-20 14:26:55 -07001432
1433 return true;
Sangho Shin15273b62014-10-16 22:22:05 -07001434 }
1435
1436 /**
Sangho Shin1ad7be02014-10-20 16:56:49 -07001437 * Split the nodes IDs into multiple tunnel if Segment Stitching is required.
1438 * We assume that the first node ID is the one of source router, and the last
1439 * node ID is that of the destination router.
Sangho Shin15273b62014-10-16 22:22:05 -07001440 *
Sangho Shin1ad7be02014-10-20 16:56:49 -07001441 * @param route list of node IDs
1442 * @return List of the TunnelRoutInfo
Sangho Shin15273b62014-10-16 22:22:05 -07001443 */
Sangho Shin81655442014-10-20 14:22:46 -07001444 private List<TunnelRouteInfo> getStitchingRule(List<String> route) {
Sangho Shin15273b62014-10-16 22:22:05 -07001445
Sangho Shin1a692c02014-10-23 17:05:41 -07001446 if (route.isEmpty() || route.size() < 3)
Sangho Shin15273b62014-10-16 22:22:05 -07001447 return null;
1448
Sangho Shin81655442014-10-20 14:22:46 -07001449 List<TunnelRouteInfo> rules = new ArrayList<TunnelRouteInfo>();
Sangho Shin15273b62014-10-16 22:22:05 -07001450
1451 Switch srcSw = this.getSwitchFromNodeId(route.get(0));
Sangho Shin6471d202014-10-23 10:59:36 -07001452 if (srcSw == null) {
1453 log.warn("Switch is not found for Node SID {}", route.get(0));
1454 return null;
1455 }
Sangho Shin15273b62014-10-16 22:22:05 -07001456 String srcDpid = srcSw.getDpid().toString();
1457
Sangho Shin15273b62014-10-16 22:22:05 -07001458 int i = 0;
Sangho Shine020cc32014-10-20 13:28:02 -07001459 TunnelRouteInfo routeInfo = new TunnelRouteInfo();
Sangho Shin1a692c02014-10-23 17:05:41 -07001460 boolean checkNeighbor = false;
Sangho Shin6471d202014-10-23 10:59:36 -07001461 String prevAdjacencySid = null;
1462 String prevNodeId = null;
Sangho Shin15273b62014-10-16 22:22:05 -07001463
1464 for (String nodeId: route) {
Sangho Shin6471d202014-10-23 10:59:36 -07001465 // The first node ID is always the source router.
1466 // We assume that the first ID cannot be an Adjacency SID.
Sangho Shin15273b62014-10-16 22:22:05 -07001467 if (i == 0) {
Sangho Shin15273b62014-10-16 22:22:05 -07001468 srcSw = getSwitchFromNodeId(nodeId);
Sangho Shin1a692c02014-10-23 17:05:41 -07001469 if (srcDpid == null)
1470 srcDpid = srcSw.getDpid().toString();
1471 routeInfo.setSrcDpid(srcDpid);
1472 checkNeighbor = true;
Sangho Shin15273b62014-10-16 22:22:05 -07001473 i++;
1474 }
Sangho Shin1a692c02014-10-23 17:05:41 -07001475 // if this is the first node ID to put the label stack..
Sangho Shin6471d202014-10-23 10:59:36 -07001476 else if (i == 1) {
Sangho Shin1a692c02014-10-23 17:05:41 -07001477 if (checkNeighbor) {
1478 List<Dpid> fwdSws = getDpidIfNeighborOf(nodeId, srcSw);
1479 // if nodeId is NOT the neighbor of srcSw..
1480 if (fwdSws.isEmpty()) {
1481 fwdSws = getForwardingSwitchForNodeId(srcSw,nodeId);
1482 if (fwdSws == null || fwdSws.isEmpty()) {
1483 log.warn("There is no route from node {} to node {}",
1484 srcSw.getDpid(), nodeId);
1485 return null;
Sangho Shin6471d202014-10-23 10:59:36 -07001486 }
Sangho Shin6471d202014-10-23 10:59:36 -07001487 routeInfo.addRoute(nodeId);
Sangho Shin6471d202014-10-23 10:59:36 -07001488 i++;
1489 }
Sangho Shin1a692c02014-10-23 17:05:41 -07001490 routeInfo.setFwdSwDpid(fwdSws);
Sangho Shin6471d202014-10-23 10:59:36 -07001491 // we check only the next node ID of the source router
1492 checkNeighbor = false;
Sangho Shin1a692c02014-10-23 17:05:41 -07001493 }
1494 // if neighbor check is already done, then just add it
1495 else {
Sangho Shin6471d202014-10-23 10:59:36 -07001496 routeInfo.addRoute(nodeId);
Sangho Shin15273b62014-10-16 22:22:05 -07001497 i++;
1498 }
1499 }
Sangho Shin6471d202014-10-23 10:59:36 -07001500 // if i > 1
Sangho Shin15273b62014-10-16 22:22:05 -07001501 else {
Sangho Shin6471d202014-10-23 10:59:36 -07001502 // If the adjacency SID is pushed and the next SID is the destination
1503 // of the adjacency SID, then do not add the SID.
1504 if (prevAdjacencySid != null) {
1505 if (isAdjacencySidNeighborOf(prevNodeId, prevAdjacencySid, nodeId)) {
1506 prevAdjacencySid = null;
1507 continue;
1508 }
1509 prevAdjacencySid = null;
1510 }
Sangho Shin15273b62014-10-16 22:22:05 -07001511 routeInfo.addRoute(nodeId);
1512 i++;
1513 }
1514
Sangho Shin1a692c02014-10-23 17:05:41 -07001515 // If the adjacency ID is added the label stack,
1516 // then we need to check if the next node is the destination of the adjacency SID
1517 if (isAdjacencySid(nodeId))
1518 prevAdjacencySid = nodeId;
1519
Sangho Shin1ad7be02014-10-20 16:56:49 -07001520 // If the number of labels reaches the limit, start over the procedure
Sangho Shin15273b62014-10-16 22:22:05 -07001521 if (i == MAX_NUM_LABELS+1) {
Sangho Shin1a692c02014-10-23 17:05:41 -07001522
Sangho Shin81655442014-10-20 14:22:46 -07001523 rules.add(routeInfo);
Sangho Shine020cc32014-10-20 13:28:02 -07001524 routeInfo = new TunnelRouteInfo();
Sangho Shin1a692c02014-10-23 17:05:41 -07001525
Sangho Shin62325582014-10-24 10:36:09 -07001526 if (isAdjacencySid(nodeId)) {
1527 // If the previous sub tunnel finishes with adjacency SID,
1528 // then we need to start the procedure from the adjacency
1529 // destination ID.
1530 List<Switch> destNodeList =
1531 getAdjacencyDestinationNode(prevNodeId, nodeId);
1532 if (destNodeList == null || destNodeList.isEmpty()) {
1533 log.warn("Cannot find destination node for adjacencySID {}",
1534 nodeId);
1535 return null;
1536 }
1537 // If the previous sub tunnel finishes with adjacency SID with
1538 // multiple ports, then we need to remove the adjacency Sid
1539 // from the previous sub tunnel and start the new sub tunnel
1540 // with the adjacency Sid. Technically, the new subtunnel
1541 // forward packets to the port assigned to the adjacency Sid
1542 // and the label stack starts with the next ID.
1543 // This is to avoid to install new policy rule to multiple nodes for stitching when the
1544 // adjacency Sid that has more than one port.
1545 if (destNodeList.size() > 1) {
1546 rules.get(rules.size()-1).route.remove(nodeId);
1547 srcSw = getSwitchFromNodeId(prevNodeId);
1548 List<Dpid> fwdSws = getDpidIfNeighborOf(nodeId, srcSw);
1549 routeInfo.setFwdSwDpid(fwdSws);
1550 routeInfo.setSrcDpid(srcSw.getDpid().toString());
1551 i = 1;
1552 checkNeighbor = false;
1553 continue;
1554 }
1555 else {
Sangho Shin1a692c02014-10-23 17:05:41 -07001556 srcSw = destNodeList.get(0);
Sangho Shin62325582014-10-24 10:36:09 -07001557 }
1558 }
1559 else {
1560 srcSw = getSwitchFromNodeId(nodeId);
Sangho Shin1a692c02014-10-23 17:05:41 -07001561 }
1562 srcDpid = srcSw.getDpid().toString();
Sangho Shin15273b62014-10-16 22:22:05 -07001563 routeInfo.setSrcDpid(srcDpid);
1564 i = 1;
1565 checkNeighbor = true;
1566 }
Sangho Shin6471d202014-10-23 10:59:36 -07001567
1568 if (prevAdjacencySid == null)
1569 prevNodeId = nodeId;
Sangho Shin15273b62014-10-16 22:22:05 -07001570 }
1571
Sangho Shin1a692c02014-10-23 17:05:41 -07001572
Sangho Shineb148ea2014-10-24 12:44:15 -07001573 if (i < MAX_NUM_LABELS+1 && (routeInfo.getFwdSwDpid() != null &&
1574 !routeInfo.getFwdSwDpid().isEmpty())) {
Sangho Shin81655442014-10-20 14:22:46 -07001575 rules.add(routeInfo);
Sangho Shineb148ea2014-10-24 12:44:15 -07001576 // NOTE: empty label stack can happen, but forwarding destination should be set
Sangho Shin15273b62014-10-16 22:22:05 -07001577 }
1578
1579 return rules;
1580 }
1581
Sangho Shin5b8f5452014-10-20 11:46:01 -07001582 /**
1583 * Remove all policies applied to specific tunnel.
1584 *
1585 * @param srcMac
1586 * @param dstMac
1587 * @param etherType
1588 * @param srcIp
1589 * @param dstIp
1590 * @param ipProto
1591 * @param srcTcpPort
1592 * @param dstTcpPort
1593 * @param tid
Sangho Shin306633a2014-10-20 14:26:55 -07001594 * @return
Sangho Shin5b8f5452014-10-20 11:46:01 -07001595 */
Sangho Shin306633a2014-10-20 14:26:55 -07001596 public boolean removePolicy(String pid) {
Sangho Shine020cc32014-10-20 13:28:02 -07001597 PolicyInfo policyInfo = policyTable.get(pid);
Sangho Shin5671cbb2014-10-20 22:35:41 -07001598 if (policyInfo == null)
1599 return false;
Sangho Shin5b8f5452014-10-20 11:46:01 -07001600 PacketMatch policyMatch = policyInfo.match;
Sangho Shine020cc32014-10-20 13:28:02 -07001601 String tid = policyInfo.tunnelId;
Sangho Shin5b8f5452014-10-20 11:46:01 -07001602 int priority = policyInfo.priority;
1603
1604 List<Action> actions = new ArrayList<>();
1605 int gropuId = 0; // dummy group ID
1606 GroupAction groupAction = new GroupAction();
1607 groupAction.setGroupId(gropuId);
1608 actions.add(groupAction);
1609
1610 MatchAction matchAction = new MatchAction(new MatchActionId(
1611 matchActionId++),
1612 new SwitchPort((long) 0, (short) 0), policyMatch, priority,
1613 actions);
1614 MatchActionOperationEntry maEntry =
1615 new MatchActionOperationEntry(Operator.REMOVE, matchAction);
1616
Sangho Shin81655442014-10-20 14:22:46 -07001617 TunnelInfo tunnelInfo = tunnelTable.get(tid);
Sangho Shin5671cbb2014-10-20 22:35:41 -07001618 if (tunnelInfo == null)
1619 return false;
Sangho Shin81655442014-10-20 14:22:46 -07001620 List<TunnelRouteInfo> routes = tunnelInfo.routes;
1621
1622 for (TunnelRouteInfo route : routes) {
Sangho Shin5b8f5452014-10-20 11:46:01 -07001623 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
Sangho Shin81655442014-10-20 14:22:46 -07001624 getSwId(route.srcSwDpid));
Sangho Shin5b8f5452014-10-20 11:46:01 -07001625
Sangho Shin5671cbb2014-10-20 22:35:41 -07001626 if (sw13 == null) {
1627 return false;
1628 }
1629 else {
Sangho Shin5b8f5452014-10-20 11:46:01 -07001630 printMatchActionOperationEntry(sw13, maEntry);
1631 try {
1632 sw13.pushFlow(maEntry);
1633 } catch (IOException e) {
1634 e.printStackTrace();
1635 log.debug("policy remove failed due to pushFlow() exception");
Sangho Shin306633a2014-10-20 14:26:55 -07001636 return false;
Sangho Shin5b8f5452014-10-20 11:46:01 -07001637 }
1638 }
1639 }
1640
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001641 policyTable.remove(pid);
Sangho Shin5b8f5452014-10-20 11:46:01 -07001642 log.debug("Policy {} is removed.", pid);
Sangho Shin306633a2014-10-20 14:26:55 -07001643 return true;
Sangho Shine020cc32014-10-20 13:28:02 -07001644 }
Sangho Shin5b8f5452014-10-20 11:46:01 -07001645
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001646 /**
1647 * Remove a tunnel
1648 * It removes all groups for the tunnel if the tunnel is not used for any
1649 * policy.
1650 *
1651 * @param tunnelId tunnel ID to remove
1652 */
Sangho Shin306633a2014-10-20 14:26:55 -07001653 public boolean removeTunnel(String tunnelId) {
Sangho Shin55d00e12014-10-20 12:13:07 -07001654
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001655 // Check if the tunnel is used for any policy
1656 for (PolicyInfo policyInfo: policyTable.values()) {
Sangho Shina000c612014-10-21 14:17:59 -07001657 if (policyInfo.tunnelId.equals(tunnelId)) {
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001658 log.debug("Tunnel {} is still used for the policy {}.",
1659 policyInfo.policyId, tunnelId);
1660 return false;
1661 }
1662 }
1663
1664 TunnelInfo tunnelInfo = tunnelTable.get(tunnelId);
Sangho Shin5671cbb2014-10-20 22:35:41 -07001665 if (tunnelInfo == null)
1666 return false;
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001667
1668 List<TunnelRouteInfo> routes = tunnelInfo.routes;
1669 for (TunnelRouteInfo route: routes) {
1670 IOF13Switch sw13 = (IOF13Switch) floodlightProvider.getMasterSwitch(
1671 getSwId(route.srcSwDpid));
1672
Sangho Shin5671cbb2014-10-20 22:35:41 -07001673 if (sw13 == null) {
1674 return false;
1675 }
1676 else {
Sangho Shin93f623c2014-10-24 12:59:53 -07001677 if (!sw13.removeGroup(route.getGroupId())) {
1678 log.warn("Tunnel {} was not removed ", tunnelId);
1679 return false; }
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001680 }
1681 }
1682
1683 tunnelTable.remove(tunnelId);
1684 log.debug("Tunnel {} was removed ", tunnelId);
1685
Sangho Shin306633a2014-10-20 14:26:55 -07001686 return true;
Sangho Shin55d00e12014-10-20 12:13:07 -07001687 }
1688
Sangho Shin7330c032014-10-20 10:34:51 -07001689 // ************************************
1690 // Utility functions
1691 // ************************************
1692
Sangho Shin1a692c02014-10-23 17:05:41 -07001693 /**
1694 * Get the destination Nodes of the adjacency Sid
1695 *
1696 * @param nodeId node ID of the adjacency Sid
1697 * @param adjacencySid adjacency Sid
1698 * @return List of Switch, empty list if not found
1699 */
1700 private List<Switch> getAdjacencyDestinationNode(String nodeId, String adjacencySid) {
1701 List<Switch> dstSwList = new ArrayList<Switch>();
1702
1703 HashMap<Integer, List<Integer>> adjacencySidInfo =
1704 adjacencySidTable.get(Integer.valueOf(nodeId));
1705 List<Integer> ports = adjacencySidInfo.get(Integer.valueOf(adjacencySid));
1706 Switch srcSw = getSwitchFromNodeId(nodeId);
1707 for (Integer port: ports) {
1708 for (Link link: srcSw.getOutgoingLinks()) {
1709 if (link.getSrcPort().getPortNumber().value() == port) {
1710 dstSwList.add(link.getDstSwitch());
1711 }
1712 }
1713 }
1714
1715 return dstSwList;
1716
1717 }
1718
1719 /**
1720 * Get the DPID of the router with node ID IF the node ID is the neighbor of the
1721 * Switch srcSW.
1722 * If the nodeId is the adjacency Sid, then it returns the destination router DPIDs.
1723 *
1724 * @param nodeId Node ID to check
1725 * @param srcSw target Switch
1726 * @return List of DPID of nodeId, empty list if the nodeId is not the neighbor of srcSW
1727 */
1728 private List<Dpid> getDpidIfNeighborOf(String nodeId, Switch srcSw) {
1729 List<Dpid> fwdSws = new ArrayList<Dpid>();
1730 // if the nodeID is the adjacency ID, then we need to regard it as the
1731 // neighbor node ID and need to return the destination router DPID(s)
1732 if (isAdjacencySid(nodeId)) {
1733 String srcNodeId = this.getMplsLabel(srcSw.getDpid().toString());
1734 HashMap<Integer, List<Integer>> adjacencySidInfo =
1735 adjacencySidTable.get(Integer.valueOf(srcNodeId));
1736 List<Integer> ports = adjacencySidInfo.get(Integer.valueOf(nodeId));
1737
1738 for (Integer port: ports) {
1739 for (Link link: srcSw.getOutgoingLinks()) {
1740 if (link.getSrcPort().getPortNumber().value() == port) {
1741 fwdSws.add(link.getDstSwitch().getDpid());
1742 }
1743 }
1744 }
1745 }
1746 else {
1747 List<Dpid> fwdSwDpids = getForwardingSwitchForNodeId(srcSw,nodeId);
1748 if (fwdSwDpids == null || fwdSwDpids.isEmpty()) {
1749 log.warn("There is no route from node {} to node {}",
1750 srcSw.getDpid(), nodeId);
1751 return null;
1752 }
1753
1754 for (Dpid dpid: fwdSwDpids) {
1755 if (getMplsLabel(dpid.toString()).toString().equals(nodeId)) {
1756 fwdSws.add(dpid);
1757 break;
1758 }
1759 }
1760 }
1761
1762 return fwdSws;
1763 }
1764
1765 /**
1766 * Get port numbers of the neighbor set
1767 *
1768 * @param srcSwDpid source switch
1769 * @param ns Neighbor set of the switch
1770 * @return List of PortNumber, null if not found
1771 */
Sangho Shin6471d202014-10-23 10:59:36 -07001772 private List<PortNumber> getPortsFromNeighborSet(String srcSwDpid, NeighborSet ns) {
1773
1774 List<PortNumber> portList = new ArrayList<PortNumber>();
1775 Switch srcSwitch = mutableTopology.getSwitch(new Dpid(srcSwDpid));
1776 if (srcSwitch == null)
1777 return null;
1778 for (Dpid neighborDpid: ns.getDpids()) {
1779 Link link = srcSwitch.getLinkToNeighbor(neighborDpid);
1780 portList.add(link.getSrcPort().getNumber());
1781 }
1782
1783 return portList;
1784 }
1785
1786 private boolean isAdjacencySidNeighborOf(String prevNodeId, String prevAdjacencySid, String nodeId) {
1787
1788 HashMap<Integer, List<Integer>> adjacencySidInfo = adjacencySidTable.get(Integer.valueOf(prevNodeId));
1789 List<Integer> ports = adjacencySidInfo.get(Integer.valueOf(prevAdjacencySid));
1790
1791 for (Integer port: ports) {
1792 Switch sw = getSwitchFromNodeId(prevNodeId);
1793 for (Link link: sw.getOutgoingLinks()) {
1794 if (link.getSrcPort().getPortNumber().value() == port) {
1795 if (getMplsLabel(link.getDstPort().getDpid().toString()).equals(nodeId)) {
1796 return true;
1797 }
1798 }
1799 }
1800 }
1801
1802 return false;
1803 }
1804
1805 private boolean isAdjacencySid(String nodeId) {
1806 // XXX The rule might change
1807 if (Integer.parseInt(nodeId) > 10000)
1808 return true;
1809
1810 return false;
1811 }
1812
Sangho Shin15273b62014-10-16 22:22:05 -07001813 /**
Sangho Shinced05b62014-10-22 11:23:14 -07001814 * Returns the Adjacency IDs for the node
1815 *
1816 * @param nodeSid Node SID
Sangho Shincfef3922014-10-22 12:04:16 -07001817 * @return Collection of Adjacency ID
Sangho Shinced05b62014-10-22 11:23:14 -07001818 */
Sangho Shincfef3922014-10-22 12:04:16 -07001819 public Collection<Integer> getAdjacencyIds(int nodeSid) {
1820 HashMap<Integer, List<Integer>> adjecencyInfo =
Sangho Shin6471d202014-10-23 10:59:36 -07001821 adjacencySidTable.get(Integer.valueOf(nodeSid));
Sangho Shincfef3922014-10-22 12:04:16 -07001822
1823 return adjecencyInfo.keySet();
1824 }
1825
1826 /**
1827 * Returns the Adjacency Info for the node
1828 *
1829 * @param nodeSid Node SID
1830 * @return HashMap of <AdjacencyID, list of ports>
1831 */
1832 public HashMap<Integer, List<Integer>> getAdjacencyInfo(int nodeSid) {
Sangho Shin6471d202014-10-23 10:59:36 -07001833 return adjacencySidTable.get(Integer.valueOf(nodeSid));
Sangho Shincfef3922014-10-22 12:04:16 -07001834 }
1835
1836 private HashMap<Integer, List<Integer>> parseAdjacencySidInfo(String adjInfo) throws JSONException {
1837 JSONArray arry = new JSONArray(adjInfo);
1838 HashMap<Integer, List<Integer>> AdjacencyInfo =
1839 new HashMap<Integer, List<Integer>>();
1840
1841 for (int i = 0; i < arry.length(); i++) {
1842 Integer adjId = (Integer) arry.getJSONObject(i).get("adjSid");
1843 JSONArray portNos = (JSONArray) arry.getJSONObject(i).get("ports");
1844 if (adjId == null || portNos == null)
1845 continue;
1846
1847 List<Integer> portNoList = new ArrayList<Integer>();
1848 for (int j = 0; j < portNos.length(); j++) {
Sangho Shin62325582014-10-24 10:36:09 -07001849 portNoList.add(Integer.valueOf(portNos.getInt(j)));
Sangho Shincfef3922014-10-22 12:04:16 -07001850 }
1851 AdjacencyInfo.put(adjId, portNoList);
1852 }
1853 return AdjacencyInfo;
Sangho Shinced05b62014-10-22 11:23:14 -07001854 }
1855
1856 /**
Sangho Shin7330c032014-10-20 10:34:51 -07001857 * Get the forwarding Switch DPIDs to send packets to a node
Sangho Shin15273b62014-10-16 22:22:05 -07001858 *
Sangho Shin7330c032014-10-20 10:34:51 -07001859 * @param srcSw source switch
1860 * @param nodeId destination node Id
1861 * @return list of switch DPID to forward packets to
Sangho Shin15273b62014-10-16 22:22:05 -07001862 */
Sangho Shin7330c032014-10-20 10:34:51 -07001863 private List<Dpid> getForwardingSwitchForNodeId(Switch srcSw, String nodeId) {
Sangho Shin15273b62014-10-16 22:22:05 -07001864
Sangho Shin7330c032014-10-20 10:34:51 -07001865 List<Dpid> fwdSws = new ArrayList<Dpid>();
1866 Switch destSw = null;
Sangho Shin15273b62014-10-16 22:22:05 -07001867
Sangho Shin7330c032014-10-20 10:34:51 -07001868 destSw = getSwitchFromNodeId(nodeId);
1869
1870 if (destSw == null) {
1871 log.debug("Cannot find the switch with ID {}", nodeId);
1872 return null;
1873 }
1874
1875 ECMPShortestPathGraph ecmpSPG = new ECMPShortestPathGraph(srcSw);
1876
1877 HashMap<Integer, HashMap<Switch, ArrayList<ArrayList<Dpid>>>> switchVia =
1878 ecmpSPG.getAllLearnedSwitchesAndVia();
1879 for (Integer itrIdx : switchVia.keySet()) {
1880 HashMap<Switch, ArrayList<ArrayList<Dpid>>> swViaMap =
1881 switchVia.get(itrIdx);
1882 for (Switch targetSw : swViaMap.keySet()) {
1883 String destSwDpid = destSw.getDpid().toString();
1884 if (targetSw.getDpid().toString().equals(destSwDpid)) {
1885 for (ArrayList<Dpid> via : swViaMap.get(targetSw)) {
1886 if (via.isEmpty()) {
1887 fwdSws.add(destSw.getDpid());
1888 }
1889 else {
Sangho Shina000c612014-10-21 14:17:59 -07001890 Dpid firstVia = via.get(via.size()-1);
1891 fwdSws.add(firstVia);
Sangho Shin7330c032014-10-20 10:34:51 -07001892 }
1893 }
1894 }
1895 }
1896 }
1897
1898 return fwdSws;
Sangho Shin15273b62014-10-16 22:22:05 -07001899 }
1900
Sangho Shin7330c032014-10-20 10:34:51 -07001901 /**
1902 * Get switch for the node Id specified
1903 *
1904 * @param nodeId node ID for switch
1905 * @return Switch
1906 */
1907 private Switch getSwitchFromNodeId(String nodeId) {
Fahad Naeem Khan4444b952014-10-18 22:30:50 -07001908
Sangho Shin7330c032014-10-20 10:34:51 -07001909 for (Switch sw : mutableTopology.getSwitches()) {
1910 String id = sw.getStringAttribute("nodeSid");
1911 if (id.equals(nodeId)) {
1912 return sw;
1913 }
1914 }
1915
1916 return null;
1917 }
Fahad Naeem Khan4444b952014-10-18 22:30:50 -07001918
Sangho Shin43cee112014-09-25 16:43:34 -07001919 /**
Sangho Shin7330c032014-10-20 10:34:51 -07001920 * Convert a string DPID to its Switch Id (integer)
Sangho Shinfbc572c2014-10-02 16:37:05 -07001921 *
Sangho Shin7330c032014-10-20 10:34:51 -07001922 * @param dpid
1923 * @return
Sangho Shin43cee112014-09-25 16:43:34 -07001924 */
Sangho Shin7330c032014-10-20 10:34:51 -07001925 private long getSwId(String dpid) {
Sangho Shin43cee112014-09-25 16:43:34 -07001926
Sangho Shin7330c032014-10-20 10:34:51 -07001927 long swId = 0;
Sangho Shin43cee112014-09-25 16:43:34 -07001928
Sangho Shin7330c032014-10-20 10:34:51 -07001929 String swIdHexStr = "0x"+dpid.substring(dpid.lastIndexOf(":") + 1);
1930 if (swIdHexStr != null)
1931 swId = Integer.decode(swIdHexStr);
Sangho Shin43cee112014-09-25 16:43:34 -07001932
Sangho Shin7330c032014-10-20 10:34:51 -07001933 return swId;
1934 }
Sangho Shin43cee112014-09-25 16:43:34 -07001935
Sangho Shin7330c032014-10-20 10:34:51 -07001936 /**
1937 * Check if the switch is the edge router or not.
1938 *
1939 * @param dpid Dpid of the switch to check
1940 * @return true if it is an edge router, otherwise false
1941 */
1942 private boolean IsEdgeRouter(String dpid) {
Sangho Shin0df01982014-09-25 17:11:18 -07001943
Sangho Shin7330c032014-10-20 10:34:51 -07001944 for (Switch sw : mutableTopology.getSwitches()) {
1945 String dpidStr = sw.getDpid().toString();
1946 if (dpid.equals(dpidStr)) {
1947 /*
1948 String subnetInfo = sw.getStringAttribute("subnets");
1949 if (subnetInfo == null || subnetInfo.equals("[]")) {
1950 return false;
1951 }
1952 else
1953 return true;
1954 */
1955 String isEdge = sw.getStringAttribute("isEdgeRouter");
1956 if (isEdge != null) {
1957 if (isEdge.equals("true"))
1958 return true;
1959 else
1960 return false;
1961 }
Sangho Shin43cee112014-09-25 16:43:34 -07001962 }
1963 }
1964
Sangho Shin7330c032014-10-20 10:34:51 -07001965 return false;
Sangho Shineb083032014-09-22 16:11:34 -07001966 }
1967
1968 /**
1969 * Get MPLS label reading the config file
Sangho Shinfbc572c2014-10-02 16:37:05 -07001970 *
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001971 * @param dipid DPID of the switch
Sangho Shineb083032014-09-22 16:11:34 -07001972 * @return MPLS label for the switch
1973 */
Sangho Shin43cee112014-09-25 16:43:34 -07001974 private String getMplsLabel(String dpid) {
Sangho Shineb083032014-09-22 16:11:34 -07001975
1976 String mplsLabel = null;
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001977 for (Switch sw : mutableTopology.getSwitches()) {
Sangho Shin43cee112014-09-25 16:43:34 -07001978 String dpidStr = sw.getDpid().toString();
1979 if (dpid.equals(dpidStr)) {
Sangho Shineb083032014-09-22 16:11:34 -07001980 mplsLabel = sw.getStringAttribute("nodeSid");
1981 break;
Sangho Shin1aa93542014-09-22 09:49:44 -07001982 }
1983 }
1984
Sangho Shineb083032014-09-22 16:11:34 -07001985 return mplsLabel;
Sangho Shin1aa93542014-09-22 09:49:44 -07001986 }
1987
Sangho Shineb083032014-09-22 16:11:34 -07001988 /**
Sangho Shin1aa93542014-09-22 09:49:44 -07001989 * The function checks if given IP matches to the given subnet mask
Sangho Shinfbc572c2014-10-02 16:37:05 -07001990 *
Sangho Shin1aa93542014-09-22 09:49:44 -07001991 * @param addr - subnet address to match
1992 * @param addr1 - IP address to check
1993 * @return true if the IP address matches to the subnet, otherwise false
1994 */
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001995 public boolean netMatch(String addr, String addr1) { // addr is subnet
1996 // address and addr1 is
1997 // ip address. Function
1998 // will return true, if
1999 // addr1 is within
2000 // addr(subnet)
Sangho Shin1aa93542014-09-22 09:49:44 -07002001
2002 String[] parts = addr.split("/");
2003 String ip = parts[0];
2004 int prefix;
2005
2006 if (parts.length < 2) {
2007 prefix = 0;
2008 } else {
2009 prefix = Integer.parseInt(parts[1]);
2010 }
2011
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002012 Inet4Address a = null;
2013 Inet4Address a1 = null;
Sangho Shin1aa93542014-09-22 09:49:44 -07002014 try {
2015 a = (Inet4Address) InetAddress.getByName(ip);
2016 a1 = (Inet4Address) InetAddress.getByName(addr1);
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002017 } catch (UnknownHostException e) {
2018 }
Sangho Shin1aa93542014-09-22 09:49:44 -07002019
2020 byte[] b = a.getAddress();
2021 int ipInt = ((b[0] & 0xFF) << 24) |
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002022 ((b[1] & 0xFF) << 16) |
2023 ((b[2] & 0xFF) << 8) |
2024 ((b[3] & 0xFF) << 0);
Sangho Shin1aa93542014-09-22 09:49:44 -07002025
2026 byte[] b1 = a1.getAddress();
2027 int ipInt1 = ((b1[0] & 0xFF) << 24) |
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002028 ((b1[1] & 0xFF) << 16) |
2029 ((b1[2] & 0xFF) << 8) |
2030 ((b1[3] & 0xFF) << 0);
Sangho Shin1aa93542014-09-22 09:49:44 -07002031
2032 int mask = ~((1 << (32 - prefix)) - 1);
2033
2034 if ((ipInt & mask) == (ipInt1 & mask)) {
2035 return true;
2036 }
2037 else {
2038 return false;
2039 }
2040 }
Sangho Shineb083032014-09-22 16:11:34 -07002041
Sangho Shinac5ee2b2014-09-28 21:27:20 -07002042 /**
2043 * Add a routing rule for the host
Sangho Shinfbc572c2014-10-02 16:37:05 -07002044 *
Sangho Shinac5ee2b2014-09-28 21:27:20 -07002045 * @param sw - Switch to add the rule
2046 * @param hostIpAddress Destination host IP address
2047 * @param hostMacAddress Destination host MAC address
2048 */
Sangho Shineb083032014-09-22 16:11:34 -07002049 public void addRouteToHost(Switch sw, int hostIpAddress, byte[] hostMacAddress) {
2050 ipHandler.addRouteToHost(sw, hostIpAddress, hostMacAddress);
Sangho Shineb083032014-09-22 16:11:34 -07002051 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -07002052
Sangho Shin463bee52014-09-29 15:14:43 -07002053 /**
2054 * Add IP packet to a buffer queue
Sangho Shinfbc572c2014-10-02 16:37:05 -07002055 *
Sangho Shin463bee52014-09-29 15:14:43 -07002056 * @param ipv4
2057 */
Sangho Shin7330c032014-10-20 10:34:51 -07002058 public void addPacketToPacketBuffer(IPv4 ipv4) {
Sangho Shin61535402014-10-01 11:37:14 -07002059 ipPacketQueue.add(ipv4);
Sangho Shin463bee52014-09-29 15:14:43 -07002060 }
2061
2062 /**
2063 * Retrieve all packets whose destination is the given address.
Sangho Shinfbc572c2014-10-02 16:37:05 -07002064 *
Sangho Shin463bee52014-09-29 15:14:43 -07002065 * @param destIp Destination address of packets to retrieve
2066 */
2067 public List<IPv4> getIpPacketFromQueue(byte[] destIp) {
2068
2069 List<IPv4> bufferedPackets = new ArrayList<IPv4>();
2070
Sangho Shin61535402014-10-01 11:37:14 -07002071 if (!ipPacketQueue.isEmpty()) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002072 for (IPv4 ip : ipPacketQueue) {
Sangho Shin61535402014-10-01 11:37:14 -07002073 int dest = ip.getDestinationAddress();
2074 IPv4Address ip1 = IPv4Address.of(dest);
2075 IPv4Address ip2 = IPv4Address.of(destIp);
2076 if (ip1.equals(ip2)) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002077 bufferedPackets.add((IPv4) (ipPacketQueue.poll()).clone());
Sangho Shin463bee52014-09-29 15:14:43 -07002078 }
2079 }
2080 }
2081
2082 return bufferedPackets;
2083 }
2084
Sangho Shin7330c032014-10-20 10:34:51 -07002085 /**
2086 * Get MAC address to known hosts
2087 *
2088 * @param destinationAddress IP address to get MAC address
2089 * @return MAC Address to given IP address
2090 */
2091 public byte[] getMacAddressFromIpAddress(int destinationAddress) {
2092
2093 // Can't we get the host IP address from the TopologyService ??
2094
2095 Iterator<ArpEntry> iterator = arpEntries.iterator();
2096
2097 IPv4Address ipAddress = IPv4Address.of(destinationAddress);
2098 byte[] ipAddressInByte = ipAddress.getBytes();
2099
2100 while (iterator.hasNext()) {
2101 ArpEntry arpEntry = iterator.next();
2102 byte[] address = arpEntry.targetIpAddress;
2103
2104 IPv4Address a = IPv4Address.of(address);
2105 IPv4Address b = IPv4Address.of(ipAddressInByte);
2106
2107 if (a.equals(b)) {
2108 log.debug("Found an arp entry");
2109 return arpEntry.targetMacAddress;
2110 }
2111 }
2112
2113 return null;
2114 }
2115
2116 /**
2117 * Send an ARP request via ArpHandler
2118 *
2119 * @param destinationAddress
2120 * @param sw
2121 * @param inPort
2122 *
2123 */
2124 public void sendArpRequest(Switch sw, int destinationAddress, Port inPort) {
2125 arpHandler.sendArpRequest(sw, destinationAddress, inPort);
2126 }
2127
2128
2129 // ************************************
2130 // Test functions
2131 // ************************************
2132
Sangho Shin55d00e12014-10-20 12:13:07 -07002133 private void runTest() {
2134
2135 if (testMode == POLICY_ADD1) {
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07002136 Integer[] routeArray = {101, 105, 110};
2137 /*List<Dpid> routeList = new ArrayList<Dpid>();
Sangho Shin55d00e12014-10-20 12:13:07 -07002138 for (int i = 0; i < routeArray.length; i++) {
2139 Dpid dpid = getSwitchFromNodeId(routeArray[i]).getDpid();
2140 routeList.add(dpid);
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07002141 }*/
Sangho Shin55d00e12014-10-20 12:13:07 -07002142
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07002143 if (createTunnel("1", Arrays.asList(routeArray))) {
Sangho Shin55d00e12014-10-20 12:13:07 -07002144 IPv4Net srcIp = new IPv4Net("10.0.1.1/24");
2145 IPv4Net dstIp = new IPv4Net("10.1.2.1/24");
2146
2147 log.debug("Set the policy 1");
Sangho Shine020cc32014-10-20 13:28:02 -07002148 this.createPolicy("1", null, null, Ethernet.TYPE_IPV4, srcIp,
Sangho Shin55d00e12014-10-20 12:13:07 -07002149 dstIp, IPv4.PROTOCOL_ICMP, (short)-1, (short)-1, 10000,
Sangho Shine020cc32014-10-20 13:28:02 -07002150 "1");
Sangho Shin55d00e12014-10-20 12:13:07 -07002151 testMode = POLICY_ADD2;
Sangho Shin4b46bcd2014-10-20 15:48:47 -07002152 testTask.reschedule(5, TimeUnit.SECONDS);
Sangho Shin55d00e12014-10-20 12:13:07 -07002153 }
2154 else {
2155 // retry it
2156 testTask.reschedule(5, TimeUnit.SECONDS);
2157 }
2158 }
2159 else if (testMode == POLICY_ADD2) {
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07002160 Integer[] routeArray = {101, 102, 103, 104, 105, 108, 110};
Sangho Shin55d00e12014-10-20 12:13:07 -07002161
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07002162 if (createTunnel("2", Arrays.asList(routeArray))) {
Sangho Shin55d00e12014-10-20 12:13:07 -07002163 IPv4Net srcIp = new IPv4Net("10.0.1.1/24");
2164 IPv4Net dstIp = new IPv4Net("10.1.2.1/24");
2165
2166 log.debug("Set the policy 2");
Sangho Shine020cc32014-10-20 13:28:02 -07002167 this.createPolicy("2", null, null, Ethernet.TYPE_IPV4, srcIp,
Sangho Shin55d00e12014-10-20 12:13:07 -07002168 dstIp, IPv4.PROTOCOL_ICMP, (short)-1, (short)-1, 20000,
Sangho Shine020cc32014-10-20 13:28:02 -07002169 "2");
Fahad Naeem Khan95aa4012014-10-21 14:07:00 -07002170 //testMode = POLICY_REMOVE2;
2171 //testTask.reschedule(5, TimeUnit.SECONDS);
Sangho Shin55d00e12014-10-20 12:13:07 -07002172 }
2173 else {
2174 log.debug("Retry it");
2175 testTask.reschedule(5, TimeUnit.SECONDS);
2176 }
2177 }
2178 else if (testMode == POLICY_REMOVE2){
2179 log.debug("Remove the policy 2");
Sangho Shine020cc32014-10-20 13:28:02 -07002180 this.removePolicy("2");
Sangho Shin55d00e12014-10-20 12:13:07 -07002181 testMode = POLICY_REMOVE1;
Sangho Shin4b46bcd2014-10-20 15:48:47 -07002182 testTask.reschedule(5, TimeUnit.SECONDS);
Sangho Shin55d00e12014-10-20 12:13:07 -07002183 }
2184 else if (testMode == POLICY_REMOVE1){
2185 log.debug("Remove the policy 1");
Sangho Shine020cc32014-10-20 13:28:02 -07002186 this.removePolicy("1");
Sangho Shin55d00e12014-10-20 12:13:07 -07002187
Sangho Shin4b46bcd2014-10-20 15:48:47 -07002188 testMode = TUNNEL_REMOVE1;
2189 testTask.reschedule(5, TimeUnit.SECONDS);
2190 }
2191 else if (testMode == TUNNEL_REMOVE1) {
2192 log.debug("Remove the tunnel 1");
2193 this.removeTunnel("1");
2194
2195 testMode = TUNNEL_REMOVE2;
2196 testTask.reschedule(5, TimeUnit.SECONDS);
2197 }
2198 else if (testMode == TUNNEL_REMOVE2) {
2199 log.debug("Remove the tunnel 2");
2200 this.removeTunnel("2");
2201 log.debug("The end of test");
2202 }
Sangho Shin55d00e12014-10-20 12:13:07 -07002203 }
Sangho Shin7330c032014-10-20 10:34:51 -07002204
2205 private void runTest1() {
2206
2207 String dpid1 = "00:00:00:00:00:00:00:01";
2208 String dpid2 = "00:00:00:00:00:00:00:0a";
2209 Switch srcSw = mutableTopology.getSwitch(new Dpid(dpid1));
2210 Switch dstSw = mutableTopology.getSwitch(new Dpid(dpid2));
2211
2212 if (srcSw == null || dstSw == null) {
2213 testTask.reschedule(1, TimeUnit.SECONDS);
2214 log.debug("Switch is gone. Reschedule the test");
2215 return;
2216 }
2217
2218 String[] routeArray = {"101", "102", "105", "108", "110"};
2219 List<String> routeList = new ArrayList<String>();
2220 for (int i = 0; i < routeArray.length; i++)
2221 routeList.add(routeArray[i]);
2222
2223 List<String> optimizedRoute = this.getOptimizedPath(srcSw, dstSw, routeList);
2224
2225 log.debug("Test set is {}", routeList.toString());
2226 log.debug("Result set is {}", optimizedRoute.toString());
2227
2228
2229 }
2230
2231 /**
2232 * print tunnel info - used only for debugging.
2233 * @param targetSw
2234 *
2235 * @param fwdSwDpids
2236 * @param ids
2237 * @param tunnelId
2238 */
Sangho Shin6471d202014-10-23 10:59:36 -07002239 private void printTunnelInfo(String targetSw, String tunnelId,
Sangho Shin7330c032014-10-20 10:34:51 -07002240 List<String> ids, NeighborSet ns) {
2241 StringBuilder logStr = new StringBuilder("In switch " +
Sangho Shin6471d202014-10-23 10:59:36 -07002242 targetSw + ", create a tunnel " + tunnelId + " " + " of push ");
Sangho Shin7330c032014-10-20 10:34:51 -07002243 for (String id: ids)
2244 logStr.append(id + "-");
2245 logStr.append(" output to ");
2246 for (Dpid dpid: ns.getDpids())
2247 logStr.append(dpid + " - ");
2248
2249 log.debug(logStr.toString());
2250
2251 }
2252
2253 /**
2254 * Debugging function to print out the Match Action Entry
2255 * @param sw13
2256 *
2257 * @param maEntry
2258 */
2259 private void printMatchActionOperationEntry(
2260 IOF13Switch sw13, MatchActionOperationEntry maEntry) {
2261
2262 StringBuilder logStr = new StringBuilder("In switch " + sw13.getId() + ", ");
2263
2264 MatchAction ma = maEntry.getTarget();
2265 Match m = ma.getMatch();
2266 List<Action> actions = ma.getActions();
2267
2268 if (m instanceof Ipv4Match) {
2269 logStr.append("If the IP matches with ");
2270 IPv4Net ip = ((Ipv4Match) m).getDestination();
2271 logStr.append(ip.toString());
2272 logStr.append(" then ");
2273 }
2274 else if (m instanceof MplsMatch) {
2275 logStr.append("If the MPLS label matches with ");
2276 int mplsLabel = ((MplsMatch) m).getMplsLabel();
2277 logStr.append(mplsLabel);
2278 logStr.append(" then ");
2279 }
2280 else if (m instanceof PacketMatch) {
2281 GroupAction ga = (GroupAction)actions.get(0);
2282 logStr.append("if the policy match is XXX then go to group " +
2283 ga.getGroupId());
2284 log.debug(logStr.toString());
2285 return;
2286 }
2287
2288 logStr.append(" do { ");
2289 for (Action action : actions) {
2290 if (action instanceof CopyTtlInAction) {
2291 logStr.append("copy ttl In, ");
2292 }
2293 else if (action instanceof CopyTtlOutAction) {
2294 logStr.append("copy ttl Out, ");
2295 }
2296 else if (action instanceof DecMplsTtlAction) {
2297 logStr.append("Dec MPLS TTL , ");
2298 }
2299 else if (action instanceof GroupAction) {
2300 logStr.append("Forward packet to < ");
2301 NeighborSet dpids = ((GroupAction) action).getDpids();
2302 logStr.append(dpids.toString() + ",");
2303
2304 }
2305 else if (action instanceof PopMplsAction) {
2306 logStr.append("Pop MPLS label, ");
2307 }
2308 else if (action instanceof PushMplsAction) {
2309 logStr.append("Push MPLS label, ");
2310 }
2311 else if (action instanceof SetMplsIdAction) {
2312 int id = ((SetMplsIdAction) action).getMplsId();
2313 logStr.append("Set MPLS ID as " + id + ", ");
2314 }
2315 }
2316
2317 log.debug(logStr.toString());
2318
2319 }
2320
2321
2322 // ************************************
2323 // Unused classes and functions
2324 // ************************************
2325
2326 /**
2327 * Temporary class to to keep ARP entry
2328 *
2329 */
2330 private class ArpEntry {
2331
2332 byte[] targetMacAddress;
2333 byte[] targetIpAddress;
2334
2335 private ArpEntry(byte[] macAddress, byte[] ipAddress) {
2336 this.targetMacAddress = macAddress;
2337 this.targetIpAddress = ipAddress;
2338 }
2339 }
2340
2341 /**
2342 * This class is used only for link recovery optimization in
2343 * modifyEcmpRoutingRules() function.
2344 * TODO: please remove if the optimization is not used at all
2345 */
2346 private class SwitchPair {
2347 private Switch src;
2348 private Switch dst;
2349
2350 public SwitchPair(Switch src, Switch dst) {
2351 this.src = src;
2352 this.dst = dst;
2353 }
2354
2355 public Switch getSource() {
2356 return src;
2357 }
2358
2359 public Switch getDestination() {
2360 return dst;
2361 }
2362 }
2363
2364 /**
2365 * Update ARP Cache using ARP packets It is used to set destination MAC
2366 * address to forward packets to known hosts. But, it will be replace with
2367 * Host information of Topology service later.
2368 *
2369 * @param arp APR packets to use for updating ARP entries
2370 */
2371 public void updateArpCache(ARP arp) {
2372
2373 ArpEntry arpEntry = new ArpEntry(arp.getSenderHardwareAddress(),
2374 arp.getSenderProtocolAddress());
2375 // TODO: Need to check the duplication
2376 arpEntries.add(arpEntry);
2377 }
2378
2379 /**
2380 * Modify the routing rules for the lost links
2381 * - Recompute the path if the link failed is included in the path
2382 * (including src and dest).
2383 *
2384 * @param newLink
2385 */
2386 private void modifyEcmpRoutingRules(LinkData linkRemoved) {
2387
2388 //HashMap<Switch, SwitchPair> linksToRecompute = new HashMap<Switch, SwitchPair>();
2389 Set<SwitchPair> linksToRecompute = new HashSet<SwitchPair>();
2390
2391 for (ECMPShortestPathGraph ecmpSPG : graphs.values()) {
2392 Switch rootSw = ecmpSPG.getRootSwitch();
2393 HashMap<Integer, HashMap<Switch, ArrayList<Path>>> paths =
2394 ecmpSPG.getCompleteLearnedSwitchesAndPaths();
2395 for (HashMap<Switch, ArrayList<Path>> p: paths.values()) {
2396 for (Switch destSw: p.keySet()) {
2397 ArrayList<Path> path = p.get(destSw);
2398 if (checkPath(path, linkRemoved)) {
2399 boolean found = false;
2400 for (SwitchPair pair: linksToRecompute) {
2401 if (pair.getSource().getDpid() == rootSw.getDpid() &&
2402 pair.getSource().getDpid() == destSw.getDpid()) {
2403 found = true;
2404 }
2405 }
2406 if (!found) {
2407 linksToRecompute.add(new SwitchPair(rootSw, destSw));
2408 }
2409 }
2410 }
2411 }
2412 }
2413
2414 // Recompute the path for the specific route
2415 for (SwitchPair pair: linksToRecompute) {
2416
2417 log.debug("Recompute path from {} to {}", pair.getSource(), pair.getDestination());
2418 // We need the following function for optimization
2419 //ECMPShortestPathGraph ecmpSPG =
2420 // new ECMPShortestPathGraph(pair.getSource(), pair.getDestination());
2421 ECMPShortestPathGraph ecmpSPG =
2422 new ECMPShortestPathGraph(pair.getSource());
2423 populateEcmpRoutingRulesForPath(pair.getSource(), ecmpSPG, true);
2424 }
2425 }
2426
2427 /**
2428 * Optimize the mpls label
2429 * The feature will be used only for policy of "avoid a specific switch".
2430 * Check route to each router in route backward.
2431 * If there is only one route to the router and the routers are included in
2432 * the route, remove the id from the path.
2433 * A-B-C-D-E => A-B-C-D-E -> A-E
2434 * | | => A-B-H-I -> A-I
Sangho Shin5b8f5452014-10-20 11:46:01 -07002435 * F-G-H-I => A-D-I > A-D-I
Sangho Shin7330c032014-10-20 10:34:51 -07002436 */
2437 private List<String> getOptimizedPath(Switch srcSw, Switch dstSw, List<String> route) {
2438
2439 List<String> optimizedPath = new ArrayList<String>();
2440 optimizedPath.addAll(route);
2441 ECMPShortestPathGraph ecmpSPG = new ECMPShortestPathGraph(srcSw);
2442
2443 HashMap<Integer, HashMap<Switch, ArrayList<Path>>> paths =
2444 ecmpSPG.getCompleteLearnedSwitchesAndPaths();
2445 for (HashMap<Switch, ArrayList<Path>> p: paths.values()) {
2446 for (Switch s: p.keySet()) {
2447 if (s.getDpid().toString().equals(dstSw.getDpid().toString())) {
2448 ArrayList<Path> ecmpPaths = p.get(s);
2449 if (ecmpPaths!= null && ecmpPaths.size() == 1) {
2450 for (Path path: ecmpPaths) {
2451 for (LinkData link: path) {
2452 String srcId = getMplsLabel(link.getSrc().getDpid().toString());
2453 String dstId = getMplsLabel(link.getSrc().getDpid().toString());
2454 if (optimizedPath.contains(srcId)) {
2455 optimizedPath.remove(srcId);
2456 }
2457 if (optimizedPath.contains(dstId)) {
2458 optimizedPath.remove(dstId);
2459 }
2460 }
2461 }
2462 }
2463 }
2464 }
2465 }
2466
2467 return optimizedPath;
2468
2469 }
2470
2471 /**
2472 * Check if the path is affected from the link removed
2473 *
2474 * @param path Path to check
2475 * @param linkRemoved link removed
2476 * @return true if the path contains the link removed
2477 */
2478 private boolean checkPath(ArrayList<Path> path, LinkData linkRemoved) {
2479
2480 for (Path ppp: path) {
2481 // TODO: need to check if this is a bidirectional or
2482 // unidirectional
2483 for (LinkData link: ppp) {
2484 if (link.getDst().getDpid().equals(linkRemoved.getDst().getDpid()) &&
2485 link.getSrc().getDpid().equals(linkRemoved.getSrc().getDpid()))
2486 return true;
2487 }
2488 }
2489
2490 return false;
2491 }
Sangho Shin15273b62014-10-16 22:22:05 -07002492
2493
Sangho Shin2f263692014-09-15 14:09:41 -07002494}