blob: 492dc339322ce922a591d58896992865a085d6ac [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 Shin79dc5172014-10-23 11:15:12 -07001677 sw13.removeGroup(route.getGroupId());
Sangho Shin4b46bcd2014-10-20 15:48:47 -07001678 }
1679 }
1680
1681 tunnelTable.remove(tunnelId);
1682 log.debug("Tunnel {} was removed ", tunnelId);
1683
Sangho Shin306633a2014-10-20 14:26:55 -07001684 return true;
Sangho Shin55d00e12014-10-20 12:13:07 -07001685 }
1686
Sangho Shin7330c032014-10-20 10:34:51 -07001687 // ************************************
1688 // Utility functions
1689 // ************************************
1690
Sangho Shin1a692c02014-10-23 17:05:41 -07001691 /**
1692 * Get the destination Nodes of the adjacency Sid
1693 *
1694 * @param nodeId node ID of the adjacency Sid
1695 * @param adjacencySid adjacency Sid
1696 * @return List of Switch, empty list if not found
1697 */
1698 private List<Switch> getAdjacencyDestinationNode(String nodeId, String adjacencySid) {
1699 List<Switch> dstSwList = new ArrayList<Switch>();
1700
1701 HashMap<Integer, List<Integer>> adjacencySidInfo =
1702 adjacencySidTable.get(Integer.valueOf(nodeId));
1703 List<Integer> ports = adjacencySidInfo.get(Integer.valueOf(adjacencySid));
1704 Switch srcSw = getSwitchFromNodeId(nodeId);
1705 for (Integer port: ports) {
1706 for (Link link: srcSw.getOutgoingLinks()) {
1707 if (link.getSrcPort().getPortNumber().value() == port) {
1708 dstSwList.add(link.getDstSwitch());
1709 }
1710 }
1711 }
1712
1713 return dstSwList;
1714
1715 }
1716
1717 /**
1718 * Get the DPID of the router with node ID IF the node ID is the neighbor of the
1719 * Switch srcSW.
1720 * If the nodeId is the adjacency Sid, then it returns the destination router DPIDs.
1721 *
1722 * @param nodeId Node ID to check
1723 * @param srcSw target Switch
1724 * @return List of DPID of nodeId, empty list if the nodeId is not the neighbor of srcSW
1725 */
1726 private List<Dpid> getDpidIfNeighborOf(String nodeId, Switch srcSw) {
1727 List<Dpid> fwdSws = new ArrayList<Dpid>();
1728 // if the nodeID is the adjacency ID, then we need to regard it as the
1729 // neighbor node ID and need to return the destination router DPID(s)
1730 if (isAdjacencySid(nodeId)) {
1731 String srcNodeId = this.getMplsLabel(srcSw.getDpid().toString());
1732 HashMap<Integer, List<Integer>> adjacencySidInfo =
1733 adjacencySidTable.get(Integer.valueOf(srcNodeId));
1734 List<Integer> ports = adjacencySidInfo.get(Integer.valueOf(nodeId));
1735
1736 for (Integer port: ports) {
1737 for (Link link: srcSw.getOutgoingLinks()) {
1738 if (link.getSrcPort().getPortNumber().value() == port) {
1739 fwdSws.add(link.getDstSwitch().getDpid());
1740 }
1741 }
1742 }
1743 }
1744 else {
1745 List<Dpid> fwdSwDpids = getForwardingSwitchForNodeId(srcSw,nodeId);
1746 if (fwdSwDpids == null || fwdSwDpids.isEmpty()) {
1747 log.warn("There is no route from node {} to node {}",
1748 srcSw.getDpid(), nodeId);
1749 return null;
1750 }
1751
1752 for (Dpid dpid: fwdSwDpids) {
1753 if (getMplsLabel(dpid.toString()).toString().equals(nodeId)) {
1754 fwdSws.add(dpid);
1755 break;
1756 }
1757 }
1758 }
1759
1760 return fwdSws;
1761 }
1762
1763 /**
1764 * Get port numbers of the neighbor set
1765 *
1766 * @param srcSwDpid source switch
1767 * @param ns Neighbor set of the switch
1768 * @return List of PortNumber, null if not found
1769 */
Sangho Shin6471d202014-10-23 10:59:36 -07001770 private List<PortNumber> getPortsFromNeighborSet(String srcSwDpid, NeighborSet ns) {
1771
1772 List<PortNumber> portList = new ArrayList<PortNumber>();
1773 Switch srcSwitch = mutableTopology.getSwitch(new Dpid(srcSwDpid));
1774 if (srcSwitch == null)
1775 return null;
1776 for (Dpid neighborDpid: ns.getDpids()) {
1777 Link link = srcSwitch.getLinkToNeighbor(neighborDpid);
1778 portList.add(link.getSrcPort().getNumber());
1779 }
1780
1781 return portList;
1782 }
1783
1784 private boolean isAdjacencySidNeighborOf(String prevNodeId, String prevAdjacencySid, String nodeId) {
1785
1786 HashMap<Integer, List<Integer>> adjacencySidInfo = adjacencySidTable.get(Integer.valueOf(prevNodeId));
1787 List<Integer> ports = adjacencySidInfo.get(Integer.valueOf(prevAdjacencySid));
1788
1789 for (Integer port: ports) {
1790 Switch sw = getSwitchFromNodeId(prevNodeId);
1791 for (Link link: sw.getOutgoingLinks()) {
1792 if (link.getSrcPort().getPortNumber().value() == port) {
1793 if (getMplsLabel(link.getDstPort().getDpid().toString()).equals(nodeId)) {
1794 return true;
1795 }
1796 }
1797 }
1798 }
1799
1800 return false;
1801 }
1802
1803 private boolean isAdjacencySid(String nodeId) {
1804 // XXX The rule might change
1805 if (Integer.parseInt(nodeId) > 10000)
1806 return true;
1807
1808 return false;
1809 }
1810
Sangho Shin15273b62014-10-16 22:22:05 -07001811 /**
Sangho Shinced05b62014-10-22 11:23:14 -07001812 * Returns the Adjacency IDs for the node
1813 *
1814 * @param nodeSid Node SID
Sangho Shincfef3922014-10-22 12:04:16 -07001815 * @return Collection of Adjacency ID
Sangho Shinced05b62014-10-22 11:23:14 -07001816 */
Sangho Shincfef3922014-10-22 12:04:16 -07001817 public Collection<Integer> getAdjacencyIds(int nodeSid) {
1818 HashMap<Integer, List<Integer>> adjecencyInfo =
Sangho Shin6471d202014-10-23 10:59:36 -07001819 adjacencySidTable.get(Integer.valueOf(nodeSid));
Sangho Shincfef3922014-10-22 12:04:16 -07001820
1821 return adjecencyInfo.keySet();
1822 }
1823
1824 /**
1825 * Returns the Adjacency Info for the node
1826 *
1827 * @param nodeSid Node SID
1828 * @return HashMap of <AdjacencyID, list of ports>
1829 */
1830 public HashMap<Integer, List<Integer>> getAdjacencyInfo(int nodeSid) {
Sangho Shin6471d202014-10-23 10:59:36 -07001831 return adjacencySidTable.get(Integer.valueOf(nodeSid));
Sangho Shincfef3922014-10-22 12:04:16 -07001832 }
1833
1834 private HashMap<Integer, List<Integer>> parseAdjacencySidInfo(String adjInfo) throws JSONException {
1835 JSONArray arry = new JSONArray(adjInfo);
1836 HashMap<Integer, List<Integer>> AdjacencyInfo =
1837 new HashMap<Integer, List<Integer>>();
1838
1839 for (int i = 0; i < arry.length(); i++) {
1840 Integer adjId = (Integer) arry.getJSONObject(i).get("adjSid");
1841 JSONArray portNos = (JSONArray) arry.getJSONObject(i).get("ports");
1842 if (adjId == null || portNos == null)
1843 continue;
1844
1845 List<Integer> portNoList = new ArrayList<Integer>();
1846 for (int j = 0; j < portNos.length(); j++) {
Sangho Shin62325582014-10-24 10:36:09 -07001847 portNoList.add(Integer.valueOf(portNos.getInt(j)));
Sangho Shincfef3922014-10-22 12:04:16 -07001848 }
1849 AdjacencyInfo.put(adjId, portNoList);
1850 }
1851 return AdjacencyInfo;
Sangho Shinced05b62014-10-22 11:23:14 -07001852 }
1853
1854 /**
Sangho Shin7330c032014-10-20 10:34:51 -07001855 * Get the forwarding Switch DPIDs to send packets to a node
Sangho Shin15273b62014-10-16 22:22:05 -07001856 *
Sangho Shin7330c032014-10-20 10:34:51 -07001857 * @param srcSw source switch
1858 * @param nodeId destination node Id
1859 * @return list of switch DPID to forward packets to
Sangho Shin15273b62014-10-16 22:22:05 -07001860 */
Sangho Shin7330c032014-10-20 10:34:51 -07001861 private List<Dpid> getForwardingSwitchForNodeId(Switch srcSw, String nodeId) {
Sangho Shin15273b62014-10-16 22:22:05 -07001862
Sangho Shin7330c032014-10-20 10:34:51 -07001863 List<Dpid> fwdSws = new ArrayList<Dpid>();
1864 Switch destSw = null;
Sangho Shin15273b62014-10-16 22:22:05 -07001865
Sangho Shin7330c032014-10-20 10:34:51 -07001866 destSw = getSwitchFromNodeId(nodeId);
1867
1868 if (destSw == null) {
1869 log.debug("Cannot find the switch with ID {}", nodeId);
1870 return null;
1871 }
1872
1873 ECMPShortestPathGraph ecmpSPG = new ECMPShortestPathGraph(srcSw);
1874
1875 HashMap<Integer, HashMap<Switch, ArrayList<ArrayList<Dpid>>>> switchVia =
1876 ecmpSPG.getAllLearnedSwitchesAndVia();
1877 for (Integer itrIdx : switchVia.keySet()) {
1878 HashMap<Switch, ArrayList<ArrayList<Dpid>>> swViaMap =
1879 switchVia.get(itrIdx);
1880 for (Switch targetSw : swViaMap.keySet()) {
1881 String destSwDpid = destSw.getDpid().toString();
1882 if (targetSw.getDpid().toString().equals(destSwDpid)) {
1883 for (ArrayList<Dpid> via : swViaMap.get(targetSw)) {
1884 if (via.isEmpty()) {
1885 fwdSws.add(destSw.getDpid());
1886 }
1887 else {
Sangho Shina000c612014-10-21 14:17:59 -07001888 Dpid firstVia = via.get(via.size()-1);
1889 fwdSws.add(firstVia);
Sangho Shin7330c032014-10-20 10:34:51 -07001890 }
1891 }
1892 }
1893 }
1894 }
1895
1896 return fwdSws;
Sangho Shin15273b62014-10-16 22:22:05 -07001897 }
1898
Sangho Shin7330c032014-10-20 10:34:51 -07001899 /**
1900 * Get switch for the node Id specified
1901 *
1902 * @param nodeId node ID for switch
1903 * @return Switch
1904 */
1905 private Switch getSwitchFromNodeId(String nodeId) {
Fahad Naeem Khan4444b952014-10-18 22:30:50 -07001906
Sangho Shin7330c032014-10-20 10:34:51 -07001907 for (Switch sw : mutableTopology.getSwitches()) {
1908 String id = sw.getStringAttribute("nodeSid");
1909 if (id.equals(nodeId)) {
1910 return sw;
1911 }
1912 }
1913
1914 return null;
1915 }
Fahad Naeem Khan4444b952014-10-18 22:30:50 -07001916
Sangho Shin43cee112014-09-25 16:43:34 -07001917 /**
Sangho Shin7330c032014-10-20 10:34:51 -07001918 * Convert a string DPID to its Switch Id (integer)
Sangho Shinfbc572c2014-10-02 16:37:05 -07001919 *
Sangho Shin7330c032014-10-20 10:34:51 -07001920 * @param dpid
1921 * @return
Sangho Shin43cee112014-09-25 16:43:34 -07001922 */
Sangho Shin7330c032014-10-20 10:34:51 -07001923 private long getSwId(String dpid) {
Sangho Shin43cee112014-09-25 16:43:34 -07001924
Sangho Shin7330c032014-10-20 10:34:51 -07001925 long swId = 0;
Sangho Shin43cee112014-09-25 16:43:34 -07001926
Sangho Shin7330c032014-10-20 10:34:51 -07001927 String swIdHexStr = "0x"+dpid.substring(dpid.lastIndexOf(":") + 1);
1928 if (swIdHexStr != null)
1929 swId = Integer.decode(swIdHexStr);
Sangho Shin43cee112014-09-25 16:43:34 -07001930
Sangho Shin7330c032014-10-20 10:34:51 -07001931 return swId;
1932 }
Sangho Shin43cee112014-09-25 16:43:34 -07001933
Sangho Shin7330c032014-10-20 10:34:51 -07001934 /**
1935 * Check if the switch is the edge router or not.
1936 *
1937 * @param dpid Dpid of the switch to check
1938 * @return true if it is an edge router, otherwise false
1939 */
1940 private boolean IsEdgeRouter(String dpid) {
Sangho Shin0df01982014-09-25 17:11:18 -07001941
Sangho Shin7330c032014-10-20 10:34:51 -07001942 for (Switch sw : mutableTopology.getSwitches()) {
1943 String dpidStr = sw.getDpid().toString();
1944 if (dpid.equals(dpidStr)) {
1945 /*
1946 String subnetInfo = sw.getStringAttribute("subnets");
1947 if (subnetInfo == null || subnetInfo.equals("[]")) {
1948 return false;
1949 }
1950 else
1951 return true;
1952 */
1953 String isEdge = sw.getStringAttribute("isEdgeRouter");
1954 if (isEdge != null) {
1955 if (isEdge.equals("true"))
1956 return true;
1957 else
1958 return false;
1959 }
Sangho Shin43cee112014-09-25 16:43:34 -07001960 }
1961 }
1962
Sangho Shin7330c032014-10-20 10:34:51 -07001963 return false;
Sangho Shineb083032014-09-22 16:11:34 -07001964 }
1965
1966 /**
1967 * Get MPLS label reading the config file
Sangho Shinfbc572c2014-10-02 16:37:05 -07001968 *
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001969 * @param dipid DPID of the switch
Sangho Shineb083032014-09-22 16:11:34 -07001970 * @return MPLS label for the switch
1971 */
Sangho Shin43cee112014-09-25 16:43:34 -07001972 private String getMplsLabel(String dpid) {
Sangho Shineb083032014-09-22 16:11:34 -07001973
1974 String mplsLabel = null;
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001975 for (Switch sw : mutableTopology.getSwitches()) {
Sangho Shin43cee112014-09-25 16:43:34 -07001976 String dpidStr = sw.getDpid().toString();
1977 if (dpid.equals(dpidStr)) {
Sangho Shineb083032014-09-22 16:11:34 -07001978 mplsLabel = sw.getStringAttribute("nodeSid");
1979 break;
Sangho Shin1aa93542014-09-22 09:49:44 -07001980 }
1981 }
1982
Sangho Shineb083032014-09-22 16:11:34 -07001983 return mplsLabel;
Sangho Shin1aa93542014-09-22 09:49:44 -07001984 }
1985
Sangho Shineb083032014-09-22 16:11:34 -07001986 /**
Sangho Shin1aa93542014-09-22 09:49:44 -07001987 * The function checks if given IP matches to the given subnet mask
Sangho Shinfbc572c2014-10-02 16:37:05 -07001988 *
Sangho Shin1aa93542014-09-22 09:49:44 -07001989 * @param addr - subnet address to match
1990 * @param addr1 - IP address to check
1991 * @return true if the IP address matches to the subnet, otherwise false
1992 */
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07001993 public boolean netMatch(String addr, String addr1) { // addr is subnet
1994 // address and addr1 is
1995 // ip address. Function
1996 // will return true, if
1997 // addr1 is within
1998 // addr(subnet)
Sangho Shin1aa93542014-09-22 09:49:44 -07001999
2000 String[] parts = addr.split("/");
2001 String ip = parts[0];
2002 int prefix;
2003
2004 if (parts.length < 2) {
2005 prefix = 0;
2006 } else {
2007 prefix = Integer.parseInt(parts[1]);
2008 }
2009
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002010 Inet4Address a = null;
2011 Inet4Address a1 = null;
Sangho Shin1aa93542014-09-22 09:49:44 -07002012 try {
2013 a = (Inet4Address) InetAddress.getByName(ip);
2014 a1 = (Inet4Address) InetAddress.getByName(addr1);
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002015 } catch (UnknownHostException e) {
2016 }
Sangho Shin1aa93542014-09-22 09:49:44 -07002017
2018 byte[] b = a.getAddress();
2019 int ipInt = ((b[0] & 0xFF) << 24) |
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002020 ((b[1] & 0xFF) << 16) |
2021 ((b[2] & 0xFF) << 8) |
2022 ((b[3] & 0xFF) << 0);
Sangho Shin1aa93542014-09-22 09:49:44 -07002023
2024 byte[] b1 = a1.getAddress();
2025 int ipInt1 = ((b1[0] & 0xFF) << 24) |
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002026 ((b1[1] & 0xFF) << 16) |
2027 ((b1[2] & 0xFF) << 8) |
2028 ((b1[3] & 0xFF) << 0);
Sangho Shin1aa93542014-09-22 09:49:44 -07002029
2030 int mask = ~((1 << (32 - prefix)) - 1);
2031
2032 if ((ipInt & mask) == (ipInt1 & mask)) {
2033 return true;
2034 }
2035 else {
2036 return false;
2037 }
2038 }
Sangho Shineb083032014-09-22 16:11:34 -07002039
Sangho Shinac5ee2b2014-09-28 21:27:20 -07002040 /**
2041 * Add a routing rule for the host
Sangho Shinfbc572c2014-10-02 16:37:05 -07002042 *
Sangho Shinac5ee2b2014-09-28 21:27:20 -07002043 * @param sw - Switch to add the rule
2044 * @param hostIpAddress Destination host IP address
2045 * @param hostMacAddress Destination host MAC address
2046 */
Sangho Shineb083032014-09-22 16:11:34 -07002047 public void addRouteToHost(Switch sw, int hostIpAddress, byte[] hostMacAddress) {
2048 ipHandler.addRouteToHost(sw, hostIpAddress, hostMacAddress);
Sangho Shineb083032014-09-22 16:11:34 -07002049 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -07002050
Sangho Shin463bee52014-09-29 15:14:43 -07002051 /**
2052 * Add IP packet to a buffer queue
Sangho Shinfbc572c2014-10-02 16:37:05 -07002053 *
Sangho Shin463bee52014-09-29 15:14:43 -07002054 * @param ipv4
2055 */
Sangho Shin7330c032014-10-20 10:34:51 -07002056 public void addPacketToPacketBuffer(IPv4 ipv4) {
Sangho Shin61535402014-10-01 11:37:14 -07002057 ipPacketQueue.add(ipv4);
Sangho Shin463bee52014-09-29 15:14:43 -07002058 }
2059
2060 /**
2061 * Retrieve all packets whose destination is the given address.
Sangho Shinfbc572c2014-10-02 16:37:05 -07002062 *
Sangho Shin463bee52014-09-29 15:14:43 -07002063 * @param destIp Destination address of packets to retrieve
2064 */
2065 public List<IPv4> getIpPacketFromQueue(byte[] destIp) {
2066
2067 List<IPv4> bufferedPackets = new ArrayList<IPv4>();
2068
Sangho Shin61535402014-10-01 11:37:14 -07002069 if (!ipPacketQueue.isEmpty()) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002070 for (IPv4 ip : ipPacketQueue) {
Sangho Shin61535402014-10-01 11:37:14 -07002071 int dest = ip.getDestinationAddress();
2072 IPv4Address ip1 = IPv4Address.of(dest);
2073 IPv4Address ip2 = IPv4Address.of(destIp);
2074 if (ip1.equals(ip2)) {
Srikanth Vavilapallif25c7b02014-10-01 14:30:43 -07002075 bufferedPackets.add((IPv4) (ipPacketQueue.poll()).clone());
Sangho Shin463bee52014-09-29 15:14:43 -07002076 }
2077 }
2078 }
2079
2080 return bufferedPackets;
2081 }
2082
Sangho Shin7330c032014-10-20 10:34:51 -07002083 /**
2084 * Get MAC address to known hosts
2085 *
2086 * @param destinationAddress IP address to get MAC address
2087 * @return MAC Address to given IP address
2088 */
2089 public byte[] getMacAddressFromIpAddress(int destinationAddress) {
2090
2091 // Can't we get the host IP address from the TopologyService ??
2092
2093 Iterator<ArpEntry> iterator = arpEntries.iterator();
2094
2095 IPv4Address ipAddress = IPv4Address.of(destinationAddress);
2096 byte[] ipAddressInByte = ipAddress.getBytes();
2097
2098 while (iterator.hasNext()) {
2099 ArpEntry arpEntry = iterator.next();
2100 byte[] address = arpEntry.targetIpAddress;
2101
2102 IPv4Address a = IPv4Address.of(address);
2103 IPv4Address b = IPv4Address.of(ipAddressInByte);
2104
2105 if (a.equals(b)) {
2106 log.debug("Found an arp entry");
2107 return arpEntry.targetMacAddress;
2108 }
2109 }
2110
2111 return null;
2112 }
2113
2114 /**
2115 * Send an ARP request via ArpHandler
2116 *
2117 * @param destinationAddress
2118 * @param sw
2119 * @param inPort
2120 *
2121 */
2122 public void sendArpRequest(Switch sw, int destinationAddress, Port inPort) {
2123 arpHandler.sendArpRequest(sw, destinationAddress, inPort);
2124 }
2125
2126
2127 // ************************************
2128 // Test functions
2129 // ************************************
2130
Sangho Shin55d00e12014-10-20 12:13:07 -07002131 private void runTest() {
2132
2133 if (testMode == POLICY_ADD1) {
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07002134 Integer[] routeArray = {101, 105, 110};
2135 /*List<Dpid> routeList = new ArrayList<Dpid>();
Sangho Shin55d00e12014-10-20 12:13:07 -07002136 for (int i = 0; i < routeArray.length; i++) {
2137 Dpid dpid = getSwitchFromNodeId(routeArray[i]).getDpid();
2138 routeList.add(dpid);
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07002139 }*/
Sangho Shin55d00e12014-10-20 12:13:07 -07002140
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07002141 if (createTunnel("1", Arrays.asList(routeArray))) {
Sangho Shin55d00e12014-10-20 12:13:07 -07002142 IPv4Net srcIp = new IPv4Net("10.0.1.1/24");
2143 IPv4Net dstIp = new IPv4Net("10.1.2.1/24");
2144
2145 log.debug("Set the policy 1");
Sangho Shine020cc32014-10-20 13:28:02 -07002146 this.createPolicy("1", null, null, Ethernet.TYPE_IPV4, srcIp,
Sangho Shin55d00e12014-10-20 12:13:07 -07002147 dstIp, IPv4.PROTOCOL_ICMP, (short)-1, (short)-1, 10000,
Sangho Shine020cc32014-10-20 13:28:02 -07002148 "1");
Sangho Shin55d00e12014-10-20 12:13:07 -07002149 testMode = POLICY_ADD2;
Sangho Shin4b46bcd2014-10-20 15:48:47 -07002150 testTask.reschedule(5, TimeUnit.SECONDS);
Sangho Shin55d00e12014-10-20 12:13:07 -07002151 }
2152 else {
2153 // retry it
2154 testTask.reschedule(5, TimeUnit.SECONDS);
2155 }
2156 }
2157 else if (testMode == POLICY_ADD2) {
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07002158 Integer[] routeArray = {101, 102, 103, 104, 105, 108, 110};
Sangho Shin55d00e12014-10-20 12:13:07 -07002159
Srikanth Vavilapalli1f6a5742014-10-21 13:45:11 -07002160 if (createTunnel("2", Arrays.asList(routeArray))) {
Sangho Shin55d00e12014-10-20 12:13:07 -07002161 IPv4Net srcIp = new IPv4Net("10.0.1.1/24");
2162 IPv4Net dstIp = new IPv4Net("10.1.2.1/24");
2163
2164 log.debug("Set the policy 2");
Sangho Shine020cc32014-10-20 13:28:02 -07002165 this.createPolicy("2", null, null, Ethernet.TYPE_IPV4, srcIp,
Sangho Shin55d00e12014-10-20 12:13:07 -07002166 dstIp, IPv4.PROTOCOL_ICMP, (short)-1, (short)-1, 20000,
Sangho Shine020cc32014-10-20 13:28:02 -07002167 "2");
Fahad Naeem Khan95aa4012014-10-21 14:07:00 -07002168 //testMode = POLICY_REMOVE2;
2169 //testTask.reschedule(5, TimeUnit.SECONDS);
Sangho Shin55d00e12014-10-20 12:13:07 -07002170 }
2171 else {
2172 log.debug("Retry it");
2173 testTask.reschedule(5, TimeUnit.SECONDS);
2174 }
2175 }
2176 else if (testMode == POLICY_REMOVE2){
2177 log.debug("Remove the policy 2");
Sangho Shine020cc32014-10-20 13:28:02 -07002178 this.removePolicy("2");
Sangho Shin55d00e12014-10-20 12:13:07 -07002179 testMode = POLICY_REMOVE1;
Sangho Shin4b46bcd2014-10-20 15:48:47 -07002180 testTask.reschedule(5, TimeUnit.SECONDS);
Sangho Shin55d00e12014-10-20 12:13:07 -07002181 }
2182 else if (testMode == POLICY_REMOVE1){
2183 log.debug("Remove the policy 1");
Sangho Shine020cc32014-10-20 13:28:02 -07002184 this.removePolicy("1");
Sangho Shin55d00e12014-10-20 12:13:07 -07002185
Sangho Shin4b46bcd2014-10-20 15:48:47 -07002186 testMode = TUNNEL_REMOVE1;
2187 testTask.reschedule(5, TimeUnit.SECONDS);
2188 }
2189 else if (testMode == TUNNEL_REMOVE1) {
2190 log.debug("Remove the tunnel 1");
2191 this.removeTunnel("1");
2192
2193 testMode = TUNNEL_REMOVE2;
2194 testTask.reschedule(5, TimeUnit.SECONDS);
2195 }
2196 else if (testMode == TUNNEL_REMOVE2) {
2197 log.debug("Remove the tunnel 2");
2198 this.removeTunnel("2");
2199 log.debug("The end of test");
2200 }
Sangho Shin55d00e12014-10-20 12:13:07 -07002201 }
Sangho Shin7330c032014-10-20 10:34:51 -07002202
2203 private void runTest1() {
2204
2205 String dpid1 = "00:00:00:00:00:00:00:01";
2206 String dpid2 = "00:00:00:00:00:00:00:0a";
2207 Switch srcSw = mutableTopology.getSwitch(new Dpid(dpid1));
2208 Switch dstSw = mutableTopology.getSwitch(new Dpid(dpid2));
2209
2210 if (srcSw == null || dstSw == null) {
2211 testTask.reschedule(1, TimeUnit.SECONDS);
2212 log.debug("Switch is gone. Reschedule the test");
2213 return;
2214 }
2215
2216 String[] routeArray = {"101", "102", "105", "108", "110"};
2217 List<String> routeList = new ArrayList<String>();
2218 for (int i = 0; i < routeArray.length; i++)
2219 routeList.add(routeArray[i]);
2220
2221 List<String> optimizedRoute = this.getOptimizedPath(srcSw, dstSw, routeList);
2222
2223 log.debug("Test set is {}", routeList.toString());
2224 log.debug("Result set is {}", optimizedRoute.toString());
2225
2226
2227 }
2228
2229 /**
2230 * print tunnel info - used only for debugging.
2231 * @param targetSw
2232 *
2233 * @param fwdSwDpids
2234 * @param ids
2235 * @param tunnelId
2236 */
Sangho Shin6471d202014-10-23 10:59:36 -07002237 private void printTunnelInfo(String targetSw, String tunnelId,
Sangho Shin7330c032014-10-20 10:34:51 -07002238 List<String> ids, NeighborSet ns) {
2239 StringBuilder logStr = new StringBuilder("In switch " +
Sangho Shin6471d202014-10-23 10:59:36 -07002240 targetSw + ", create a tunnel " + tunnelId + " " + " of push ");
Sangho Shin7330c032014-10-20 10:34:51 -07002241 for (String id: ids)
2242 logStr.append(id + "-");
2243 logStr.append(" output to ");
2244 for (Dpid dpid: ns.getDpids())
2245 logStr.append(dpid + " - ");
2246
2247 log.debug(logStr.toString());
2248
2249 }
2250
2251 /**
2252 * Debugging function to print out the Match Action Entry
2253 * @param sw13
2254 *
2255 * @param maEntry
2256 */
2257 private void printMatchActionOperationEntry(
2258 IOF13Switch sw13, MatchActionOperationEntry maEntry) {
2259
2260 StringBuilder logStr = new StringBuilder("In switch " + sw13.getId() + ", ");
2261
2262 MatchAction ma = maEntry.getTarget();
2263 Match m = ma.getMatch();
2264 List<Action> actions = ma.getActions();
2265
2266 if (m instanceof Ipv4Match) {
2267 logStr.append("If the IP matches with ");
2268 IPv4Net ip = ((Ipv4Match) m).getDestination();
2269 logStr.append(ip.toString());
2270 logStr.append(" then ");
2271 }
2272 else if (m instanceof MplsMatch) {
2273 logStr.append("If the MPLS label matches with ");
2274 int mplsLabel = ((MplsMatch) m).getMplsLabel();
2275 logStr.append(mplsLabel);
2276 logStr.append(" then ");
2277 }
2278 else if (m instanceof PacketMatch) {
2279 GroupAction ga = (GroupAction)actions.get(0);
2280 logStr.append("if the policy match is XXX then go to group " +
2281 ga.getGroupId());
2282 log.debug(logStr.toString());
2283 return;
2284 }
2285
2286 logStr.append(" do { ");
2287 for (Action action : actions) {
2288 if (action instanceof CopyTtlInAction) {
2289 logStr.append("copy ttl In, ");
2290 }
2291 else if (action instanceof CopyTtlOutAction) {
2292 logStr.append("copy ttl Out, ");
2293 }
2294 else if (action instanceof DecMplsTtlAction) {
2295 logStr.append("Dec MPLS TTL , ");
2296 }
2297 else if (action instanceof GroupAction) {
2298 logStr.append("Forward packet to < ");
2299 NeighborSet dpids = ((GroupAction) action).getDpids();
2300 logStr.append(dpids.toString() + ",");
2301
2302 }
2303 else if (action instanceof PopMplsAction) {
2304 logStr.append("Pop MPLS label, ");
2305 }
2306 else if (action instanceof PushMplsAction) {
2307 logStr.append("Push MPLS label, ");
2308 }
2309 else if (action instanceof SetMplsIdAction) {
2310 int id = ((SetMplsIdAction) action).getMplsId();
2311 logStr.append("Set MPLS ID as " + id + ", ");
2312 }
2313 }
2314
2315 log.debug(logStr.toString());
2316
2317 }
2318
2319
2320 // ************************************
2321 // Unused classes and functions
2322 // ************************************
2323
2324 /**
2325 * Temporary class to to keep ARP entry
2326 *
2327 */
2328 private class ArpEntry {
2329
2330 byte[] targetMacAddress;
2331 byte[] targetIpAddress;
2332
2333 private ArpEntry(byte[] macAddress, byte[] ipAddress) {
2334 this.targetMacAddress = macAddress;
2335 this.targetIpAddress = ipAddress;
2336 }
2337 }
2338
2339 /**
2340 * This class is used only for link recovery optimization in
2341 * modifyEcmpRoutingRules() function.
2342 * TODO: please remove if the optimization is not used at all
2343 */
2344 private class SwitchPair {
2345 private Switch src;
2346 private Switch dst;
2347
2348 public SwitchPair(Switch src, Switch dst) {
2349 this.src = src;
2350 this.dst = dst;
2351 }
2352
2353 public Switch getSource() {
2354 return src;
2355 }
2356
2357 public Switch getDestination() {
2358 return dst;
2359 }
2360 }
2361
2362 /**
2363 * Update ARP Cache using ARP packets It is used to set destination MAC
2364 * address to forward packets to known hosts. But, it will be replace with
2365 * Host information of Topology service later.
2366 *
2367 * @param arp APR packets to use for updating ARP entries
2368 */
2369 public void updateArpCache(ARP arp) {
2370
2371 ArpEntry arpEntry = new ArpEntry(arp.getSenderHardwareAddress(),
2372 arp.getSenderProtocolAddress());
2373 // TODO: Need to check the duplication
2374 arpEntries.add(arpEntry);
2375 }
2376
2377 /**
2378 * Modify the routing rules for the lost links
2379 * - Recompute the path if the link failed is included in the path
2380 * (including src and dest).
2381 *
2382 * @param newLink
2383 */
2384 private void modifyEcmpRoutingRules(LinkData linkRemoved) {
2385
2386 //HashMap<Switch, SwitchPair> linksToRecompute = new HashMap<Switch, SwitchPair>();
2387 Set<SwitchPair> linksToRecompute = new HashSet<SwitchPair>();
2388
2389 for (ECMPShortestPathGraph ecmpSPG : graphs.values()) {
2390 Switch rootSw = ecmpSPG.getRootSwitch();
2391 HashMap<Integer, HashMap<Switch, ArrayList<Path>>> paths =
2392 ecmpSPG.getCompleteLearnedSwitchesAndPaths();
2393 for (HashMap<Switch, ArrayList<Path>> p: paths.values()) {
2394 for (Switch destSw: p.keySet()) {
2395 ArrayList<Path> path = p.get(destSw);
2396 if (checkPath(path, linkRemoved)) {
2397 boolean found = false;
2398 for (SwitchPair pair: linksToRecompute) {
2399 if (pair.getSource().getDpid() == rootSw.getDpid() &&
2400 pair.getSource().getDpid() == destSw.getDpid()) {
2401 found = true;
2402 }
2403 }
2404 if (!found) {
2405 linksToRecompute.add(new SwitchPair(rootSw, destSw));
2406 }
2407 }
2408 }
2409 }
2410 }
2411
2412 // Recompute the path for the specific route
2413 for (SwitchPair pair: linksToRecompute) {
2414
2415 log.debug("Recompute path from {} to {}", pair.getSource(), pair.getDestination());
2416 // We need the following function for optimization
2417 //ECMPShortestPathGraph ecmpSPG =
2418 // new ECMPShortestPathGraph(pair.getSource(), pair.getDestination());
2419 ECMPShortestPathGraph ecmpSPG =
2420 new ECMPShortestPathGraph(pair.getSource());
2421 populateEcmpRoutingRulesForPath(pair.getSource(), ecmpSPG, true);
2422 }
2423 }
2424
2425 /**
2426 * Optimize the mpls label
2427 * The feature will be used only for policy of "avoid a specific switch".
2428 * Check route to each router in route backward.
2429 * If there is only one route to the router and the routers are included in
2430 * the route, remove the id from the path.
2431 * A-B-C-D-E => A-B-C-D-E -> A-E
2432 * | | => A-B-H-I -> A-I
Sangho Shin5b8f5452014-10-20 11:46:01 -07002433 * F-G-H-I => A-D-I > A-D-I
Sangho Shin7330c032014-10-20 10:34:51 -07002434 */
2435 private List<String> getOptimizedPath(Switch srcSw, Switch dstSw, List<String> route) {
2436
2437 List<String> optimizedPath = new ArrayList<String>();
2438 optimizedPath.addAll(route);
2439 ECMPShortestPathGraph ecmpSPG = new ECMPShortestPathGraph(srcSw);
2440
2441 HashMap<Integer, HashMap<Switch, ArrayList<Path>>> paths =
2442 ecmpSPG.getCompleteLearnedSwitchesAndPaths();
2443 for (HashMap<Switch, ArrayList<Path>> p: paths.values()) {
2444 for (Switch s: p.keySet()) {
2445 if (s.getDpid().toString().equals(dstSw.getDpid().toString())) {
2446 ArrayList<Path> ecmpPaths = p.get(s);
2447 if (ecmpPaths!= null && ecmpPaths.size() == 1) {
2448 for (Path path: ecmpPaths) {
2449 for (LinkData link: path) {
2450 String srcId = getMplsLabel(link.getSrc().getDpid().toString());
2451 String dstId = getMplsLabel(link.getSrc().getDpid().toString());
2452 if (optimizedPath.contains(srcId)) {
2453 optimizedPath.remove(srcId);
2454 }
2455 if (optimizedPath.contains(dstId)) {
2456 optimizedPath.remove(dstId);
2457 }
2458 }
2459 }
2460 }
2461 }
2462 }
2463 }
2464
2465 return optimizedPath;
2466
2467 }
2468
2469 /**
2470 * Check if the path is affected from the link removed
2471 *
2472 * @param path Path to check
2473 * @param linkRemoved link removed
2474 * @return true if the path contains the link removed
2475 */
2476 private boolean checkPath(ArrayList<Path> path, LinkData linkRemoved) {
2477
2478 for (Path ppp: path) {
2479 // TODO: need to check if this is a bidirectional or
2480 // unidirectional
2481 for (LinkData link: ppp) {
2482 if (link.getDst().getDpid().equals(linkRemoved.getDst().getDpid()) &&
2483 link.getSrc().getDpid().equals(linkRemoved.getSrc().getDpid()))
2484 return true;
2485 }
2486 }
2487
2488 return false;
2489 }
Sangho Shin15273b62014-10-16 22:22:05 -07002490
2491
Sangho Shin2f263692014-09-15 14:09:41 -07002492}