blob: 053ba8a974c917aeff5ecf12c13beed39622cc83 [file] [log] [blame]
Sangho Shin2f263692014-09-15 14:09:41 -07001package net.onrc.onos.apps.segmentrouting;
2
Sangho Shin9c0f4c32014-09-26 16:02:38 -07003import java.io.IOException;
Sangho Shin1aa93542014-09-22 09:49:44 -07004import java.net.Inet4Address;
5import java.net.InetAddress;
6import java.net.UnknownHostException;
Sangho Shin2f263692014-09-15 14:09:41 -07007import java.util.ArrayList;
8import java.util.Collection;
Srikanth Vavilapalli363f1dc2014-09-22 14:30:23 -07009import java.util.HashMap;
Sangho Shin2f263692014-09-15 14:09:41 -070010import java.util.Iterator;
11import java.util.List;
12import java.util.Map;
Sangho Shin61535402014-10-01 11:37:14 -070013import java.util.concurrent.ConcurrentLinkedQueue;
Sangho Shin11d4e0f2014-09-30 12:00:33 -070014import java.util.concurrent.ExecutionException;
Sangho Shin43cee112014-09-25 16:43:34 -070015import java.util.concurrent.ScheduledExecutorService;
16import java.util.concurrent.TimeUnit;
Sangho Shin11d4e0f2014-09-30 12:00:33 -070017import java.util.concurrent.TimeoutException;
Sangho Shin2f263692014-09-15 14:09:41 -070018
19import net.floodlightcontroller.core.IFloodlightProviderService;
Sangho Shin9c0f4c32014-09-26 16:02:38 -070020import net.floodlightcontroller.core.IOF13Switch;
Sangho Shin0df01982014-09-25 17:11:18 -070021import net.floodlightcontroller.core.IOF13Switch.NeighborSet;
Sangho Shin11d4e0f2014-09-30 12:00:33 -070022import net.floodlightcontroller.core.internal.OFBarrierReplyFuture;
Sangho Shin2f263692014-09-15 14:09:41 -070023import net.floodlightcontroller.core.module.FloodlightModuleContext;
24import net.floodlightcontroller.core.module.FloodlightModuleException;
25import net.floodlightcontroller.core.module.IFloodlightModule;
26import net.floodlightcontroller.core.module.IFloodlightService;
Sangho Shin43cee112014-09-25 16:43:34 -070027import net.floodlightcontroller.core.util.SingletonTask;
28import net.floodlightcontroller.threadpool.IThreadPoolService;
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070029import net.onrc.onos.api.packet.IPacketListener;
Sangho Shin2f263692014-09-15 14:09:41 -070030import net.onrc.onos.api.packet.IPacketService;
31import net.onrc.onos.core.flowprogrammer.IFlowPusherService;
32import net.onrc.onos.core.main.config.IConfigInfoService;
Sangho Shin43cee112014-09-25 16:43:34 -070033import net.onrc.onos.core.matchaction.MatchAction;
34import net.onrc.onos.core.matchaction.MatchActionId;
35import net.onrc.onos.core.matchaction.MatchActionOperationEntry;
36import net.onrc.onos.core.matchaction.action.Action;
37import net.onrc.onos.core.matchaction.action.CopyTtlInAction;
38import net.onrc.onos.core.matchaction.action.CopyTtlOutAction;
39import net.onrc.onos.core.matchaction.action.DecMplsTtlAction;
40import net.onrc.onos.core.matchaction.action.DecNwTtlAction;
41import net.onrc.onos.core.matchaction.action.GroupAction;
42import net.onrc.onos.core.matchaction.action.PopMplsAction;
43import net.onrc.onos.core.matchaction.action.PushMplsAction;
44import net.onrc.onos.core.matchaction.action.SetMplsIdAction;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -070045import net.onrc.onos.core.matchaction.match.Ipv4Match;
Sangho Shin43cee112014-09-25 16:43:34 -070046import net.onrc.onos.core.matchaction.match.Match;
47import net.onrc.onos.core.matchaction.match.MplsMatch;
Sangho Shin2f263692014-09-15 14:09:41 -070048import net.onrc.onos.core.packet.ARP;
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070049import net.onrc.onos.core.packet.Ethernet;
50import net.onrc.onos.core.packet.IPv4;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070051import net.onrc.onos.core.topology.ITopologyListener;
Sangho Shin1aa93542014-09-22 09:49:44 -070052import net.onrc.onos.core.topology.ITopologyService;
Sangho Shinc8d2f592014-09-30 16:53:57 -070053import net.onrc.onos.core.topology.LinkData;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070054import net.onrc.onos.core.topology.MutableTopology;
Sangho Shineb083032014-09-22 16:11:34 -070055import net.onrc.onos.core.topology.Port;
Sangho Shinc8d2f592014-09-30 16:53:57 -070056import net.onrc.onos.core.topology.PortData;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070057import net.onrc.onos.core.topology.Switch;
Sangho Shin1aa93542014-09-22 09:49:44 -070058import net.onrc.onos.core.topology.TopologyEvents;
Srikanth Vavilapalli363f1dc2014-09-22 14:30:23 -070059import net.onrc.onos.core.util.Dpid;
Sangho Shin43cee112014-09-25 16:43:34 -070060import net.onrc.onos.core.util.IPv4Net;
61import net.onrc.onos.core.util.SwitchPort;
Sangho Shin2f263692014-09-15 14:09:41 -070062
Sangho Shin43cee112014-09-25 16:43:34 -070063import org.json.JSONArray;
64import org.json.JSONException;
Saurav Dasbc594a42014-09-25 20:13:50 -070065import org.projectfloodlight.openflow.types.EthType;
Sangho Shin2f263692014-09-15 14:09:41 -070066import org.projectfloodlight.openflow.types.IPv4Address;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070067import org.projectfloodlight.openflow.util.HexString;
Sangho Shin2f263692014-09-15 14:09:41 -070068import org.slf4j.Logger;
69import org.slf4j.LoggerFactory;
70
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070071public class SegmentRoutingManager implements IFloodlightModule,
Sangho Shinac5ee2b2014-09-28 21:27:20 -070072 ITopologyListener, IPacketListener {
Sangho Shin2f263692014-09-15 14:09:41 -070073
74 private static final Logger log = LoggerFactory
75 .getLogger(SegmentRoutingManager.class);
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070076 private ITopologyService topologyService;
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070077 private IPacketService packetService;
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -070078 private MutableTopology mutableTopology;
Sangho Shin61535402014-10-01 11:37:14 -070079 private ConcurrentLinkedQueue<IPv4> ipPacketQueue;
Sangho Shin2f263692014-09-15 14:09:41 -070080
81 private List<ArpEntry> arpEntries;
Sangho Shineb083032014-09-22 16:11:34 -070082 private ArpHandler arpHandler;
83 private GenericIpHandler ipHandler;
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070084 private IcmpHandler icmpHandler;
Sangho Shin43cee112014-09-25 16:43:34 -070085 private IThreadPoolService threadPool;
86 private SingletonTask discoveryTask;
Sangho Shin9c0f4c32014-09-26 16:02:38 -070087 private IFloodlightProviderService floodlightProvider;
Sangho Shin2f263692014-09-15 14:09:41 -070088
89 @Override
90 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
91 // TODO Auto-generated method stub
92 return null;
93 }
94
95 @Override
96 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
97 // TODO Auto-generated method stub
98 return null;
99 }
100
101 @Override
102 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
103 Collection<Class<? extends IFloodlightService>> l = new ArrayList<Class<? extends IFloodlightService>>();
104
105 l.add(IFloodlightProviderService.class);
106 l.add(IConfigInfoService.class);
107 l.add(ITopologyService.class);
108 l.add(IPacketService.class);
109 l.add(IFlowPusherService.class);
110 l.add(ITopologyService.class);
111
112 return l;
113
114 }
115
116 @Override
117 public void init(FloodlightModuleContext context) throws FloodlightModuleException {
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700118 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Sangho Shineb083032014-09-22 16:11:34 -0700119 arpHandler = new ArpHandler(context, this);
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700120 icmpHandler = new IcmpHandler(context, this);
Sangho Shineb083032014-09-22 16:11:34 -0700121 ipHandler = new GenericIpHandler(context, this);
Sangho Shin2f263692014-09-15 14:09:41 -0700122 arpEntries = new ArrayList<ArpEntry>();
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700123 topologyService = context.getServiceImpl(ITopologyService.class);
Sangho Shin43cee112014-09-25 16:43:34 -0700124 threadPool = context.getServiceImpl(IThreadPoolService.class);
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700125 mutableTopology = topologyService.getTopology();
126 topologyService.addListener(this, false);
Sangho Shin61535402014-10-01 11:37:14 -0700127 ipPacketQueue = new ConcurrentLinkedQueue<IPv4>();
Sangho Shin2f263692014-09-15 14:09:41 -0700128
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700129 this.packetService = context.getServiceImpl(IPacketService.class);
130 packetService.registerPacketListener(this);
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700131
Sangho Shin2f263692014-09-15 14:09:41 -0700132 }
133
134 @Override
135 public void startUp(FloodlightModuleContext context) throws FloodlightModuleException {
Sangho Shinc8d2f592014-09-30 16:53:57 -0700136 ScheduledExecutorService ses = threadPool.getScheduledExecutor();
Sangho Shin2f263692014-09-15 14:09:41 -0700137
Sangho Shinc8d2f592014-09-30 16:53:57 -0700138 discoveryTask = new SingletonTask(ses, new Runnable() {
139 @Override
140 public void run() {
141 populateEcmpRoutingRules();
142 }
143 });
Sangho Shin2f263692014-09-15 14:09:41 -0700144 }
145
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700146 @Override
147 public void receive(Switch sw, Port inPort, Ethernet payload) {
148 if (payload.getEtherType() == Ethernet.TYPE_ARP)
149 arpHandler.processPacketIn(sw, inPort, payload);
150 if (payload.getEtherType() == Ethernet.TYPE_IPV4) {
Sangho Shin463bee52014-09-29 15:14:43 -0700151 addPacket((IPv4)payload.getPayload());
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700152 if (((IPv4)payload.getPayload()).getProtocol() == IPv4.PROTOCOL_ICMP)
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700153 icmpHandler.processPacketIn(sw, inPort, payload);
154 else
155 ipHandler.processPacketIn(sw, inPort, payload);
156 }
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700157 else {
158 log.debug("{}", payload.toString());
159 }
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700160 }
Sangho Shin2f263692014-09-15 14:09:41 -0700161 /**
162 * Update ARP Cache using ARP packets
163 * It is used to set destination MAC address to forward packets to known hosts.
164 * But, it will be replace with Host information of Topology service later.
165 *
166 * @param arp APR packets to use for updating ARP entries
167 */
168 public void updateArpCache(ARP arp) {
169
170 ArpEntry arpEntry = new ArpEntry(arp.getSenderHardwareAddress(), arp.getSenderProtocolAddress());
171 // TODO: Need to check the duplication
172 arpEntries.add(arpEntry);
173 }
174
175 /**
176 * Get MAC address to known hosts
177 *
178 * @param destinationAddress IP address to get MAC address
179 * @return MAC Address to given IP address
180 */
181 public byte[] getMacAddressFromIpAddress(int destinationAddress) {
182
183 // Can't we get the host IP address from the TopologyService ??
184
185 Iterator<ArpEntry> iterator = arpEntries.iterator();
186
187 IPv4Address ipAddress = IPv4Address.of(destinationAddress);
188 byte[] ipAddressInByte = ipAddress.getBytes();
189
190 while (iterator.hasNext() ) {
191 ArpEntry arpEntry = iterator.next();
192 byte[] address = arpEntry.targetIpAddress;
193
194 IPv4Address a = IPv4Address.of(address);
195 IPv4Address b = IPv4Address.of(ipAddressInByte);
196
197 if ( a.equals(b)) {
198 log.debug("Found an arp entry");
199 return arpEntry.targetMacAddress;
200 }
201 }
202
203 return null;
204 }
205
Sangho Shineb083032014-09-22 16:11:34 -0700206 /**
207 * Send an ARP request via ArpHandler
208 * @param destinationAddress
209 * @param sw
210 * @param inPort
211 *
212 */
213 public void sendArpRequest(Switch sw, int destinationAddress, Port inPort) {
214 arpHandler.sendArpRequest(sw, destinationAddress, inPort);
215 }
Sangho Shin2f263692014-09-15 14:09:41 -0700216
217 /**
218 * Temporary class to to keep ARP entry
219 *
220 */
221 private class ArpEntry {
222
223 byte[] targetMacAddress;
224 byte[] targetIpAddress;
225
226 private ArpEntry(byte[] macAddress, byte[] ipAddress) {
227 this.targetMacAddress = macAddress;
228 this.targetIpAddress = ipAddress;
229 }
Sangho Shin2f263692014-09-15 14:09:41 -0700230 }
Sangho Shineb083032014-09-22 16:11:34 -0700231
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700232 /**
233 * Topology events that have been generated.
234 *
235 * @param topologyEvents the generated Topology Events
236 * @see TopologyEvents
237 */
238 public void topologyEvents(TopologyEvents topologyEvents)
239 {
Sangho Shin61535402014-10-01 11:37:14 -0700240 if (topologyEvents.getAddedLinkDataEntries() != null)
Sangho Shin43cee112014-09-25 16:43:34 -0700241 {
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700242 discoveryTask.reschedule(1, TimeUnit.SECONDS);
243 }
Sangho Shinc8d2f592014-09-30 16:53:57 -0700244
245 Collection<PortData> portEntries =
246 topologyEvents.getRemovedPortDataEntries();
247 if (!portEntries.isEmpty()) {
Sangho Shin61535402014-10-01 11:37:14 -0700248 processPortRemoval(portEntries);
Sangho Shinc8d2f592014-09-30 16:53:57 -0700249 }
250
251 Collection<LinkData> linkEntries =
252 topologyEvents.getRemovedLinkDataEntries();
253 if (!linkEntries.isEmpty()) {
Sangho Shin61535402014-10-01 11:37:14 -0700254 processLinkRemoval(linkEntries);
255 }
256 }
Sangho Shinc8d2f592014-09-30 16:53:57 -0700257
Sangho Shin61535402014-10-01 11:37:14 -0700258 /**
259 * Check if all links are gone b/w the two switches.
260 * If all links are gone, then we need to recalculate the path.
261 * Otherwise, just report link failure to the driver.
262 *
263 * @param linkEntries
264 */
265 private void processLinkRemoval(Collection<LinkData> linkEntries) {
266 for (LinkData link: linkEntries) {
267 Dpid srcSwDpid = link.getSrc().getDpid();
268 Dpid dstSwDpid = link.getDst().getDpid();
Sangho Shinc8d2f592014-09-30 16:53:57 -0700269
Sangho Shin61535402014-10-01 11:37:14 -0700270 Switch srcSwitch = mutableTopology.getSwitch(srcSwDpid);
271 if (srcSwitch.getLinkToNeighbor(dstSwDpid) == null) {
272 discoveryTask.reschedule(1, TimeUnit.SECONDS);
273 log.debug("All links are gone b/w {} and {}",srcSwDpid,
274 dstSwDpid);
Sangho Shinc8d2f592014-09-30 16:53:57 -0700275 }
276 }
Sangho Shin61535402014-10-01 11:37:14 -0700277 }
Sangho Shinc8d2f592014-09-30 16:53:57 -0700278
Sangho Shin61535402014-10-01 11:37:14 -0700279 /**
280 * report ports removed to the driver
281 *
282 * @param portEntries
283 */
284 private void processPortRemoval(Collection<PortData> portEntries) {
285 for (PortData port: portEntries) {
286 Dpid dpid = port.getDpid();
287 int portNo = (int) port.getPortNumber().value();
288
289 IOF13Switch sw13 = (IOF13Switch)floodlightProvider.getMasterSwitch(
290 getSwId(port.getDpid().toString()));
291 //sw13.removePort(portNo);
292 log.debug("Remove port {} from switch {}", portNo, dpid.toString());
293 }
Srikanth Vavilapallib7e5c5e2014-09-18 07:38:27 -0700294 }
Sangho Shin1aa93542014-09-22 09:49:44 -0700295
296 /**
Sangho Shin43cee112014-09-25 16:43:34 -0700297 * Populate routing rules walking through the ECMP shortest paths
Sangho Shin1aa93542014-09-22 09:49:44 -0700298 *
Sangho Shin1aa93542014-09-22 09:49:44 -0700299 */
Sangho Shin43cee112014-09-25 16:43:34 -0700300 private void populateEcmpRoutingRules() {
Sangho Shin1aa93542014-09-22 09:49:44 -0700301
Sangho Shin43cee112014-09-25 16:43:34 -0700302 Iterable<Switch> switches= mutableTopology.getSwitches();
303 for (Switch sw : switches) {
304 ECMPShortestPathGraph ecmpSPG = new ECMPShortestPathGraph(sw);
305 log.debug("ECMPShortestPathGraph is computed for switch {}",
306 HexString.toHexString(sw.getDpid().value()));
Sangho Shin1aa93542014-09-22 09:49:44 -0700307
Sangho Shin43cee112014-09-25 16:43:34 -0700308 HashMap<Integer, HashMap<Switch,ArrayList<ArrayList<Dpid>>>> switchVia =
309 ecmpSPG.getAllLearnedSwitchesAndVia();
310 for (Integer itrIdx: switchVia.keySet()){
311 log.debug("ECMPShortestPathGraph:Switches learned in "
312 + "Iteration{} from switch {}:",
313 itrIdx,
314 HexString.toHexString(sw.getDpid().value()));
315 HashMap<Switch, ArrayList<ArrayList<Dpid>>> swViaMap =
316 switchVia.get(itrIdx);
317 for (Switch targetSw: swViaMap.keySet()){
318 log.debug("ECMPShortestPathGraph:****switch {} via:",
319 HexString.toHexString(targetSw.getDpid().value()));
320 String destSw = sw.getDpid().toString();
321 List<String> fwdToSw = new ArrayList<String>();
322
323 int i=0;
324 for (ArrayList<Dpid> via:swViaMap.get(targetSw)){
325 log.debug("ECMPShortestPathGraph:******{}) {}",++i,via);
326 if (via.isEmpty()) {
327 fwdToSw.add(destSw);
328 }
329 else {
330 fwdToSw.add(via.get(0).toString());
331 }
332 }
333 setRoutingRule(targetSw, destSw, fwdToSw);
334 }
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700335
336 // Send Barrier Message and make sure all rules are set
337 // before we set the rules to next routers
338 IOF13Switch sw13 = (IOF13Switch)floodlightProvider.getMasterSwitch(
339 getSwId(sw.getDpid().toString()));
340 try {
341 OFBarrierReplyFuture replyFuture = sw13.sendBarrier();
342 replyFuture.get(10, TimeUnit.SECONDS);
343 } catch (IOException e) {
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700344 e.printStackTrace();
345 }
346 catch (InterruptedException | ExecutionException | TimeoutException e) {
347 log.error("Barrier message not received for sw: {}", sw.getDpid());
348 e.printStackTrace();
349 }
Sangho Shineb083032014-09-22 16:11:34 -0700350 }
351 }
Sangho Shin43cee112014-09-25 16:43:34 -0700352 }
353
354 /**
355 *
356 * Set routing rules in targetSw
357 * {forward packets to fwdToSw switches in order to send packets to destSw}
358 * - If the target switch is an edge router and final destnation switch is also
359 * an edge router, then set IP forwarding rules to subnets
360 * - If only the target switch is an edge router, then set IP forwarding rule to
361 * the transit router loopback IP address
362 * - If the target is a transit router, then just set the MPLS forwarding rule
363 *
364 * @param targetSw Switch to set the rules
365 * @param destSw Final destination switches
366 * @param fwdToSw next hop switches
367 */
368 private void setRoutingRule(Switch targetSw, String destSw, List<String> fwdToSw) {
369
370
371 if (fwdToSw.isEmpty()) {
372 fwdToSw.add(destSw);
373 }
374
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700375 // if both target SW and dest SW are an edge router, then set IP table
Sangho Shin43cee112014-09-25 16:43:34 -0700376 if (IsEdgeRouter(targetSw.getDpid().toString()) &&
377 IsEdgeRouter(destSw)) {
378 // We assume that there is at least one transit router b/w edge routers
379 Switch destSwitch = mutableTopology.getSwitch(new Dpid(destSw));
380 String subnets = destSwitch.getStringAttribute("subnets");
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700381 setIpTableRouterSubnet(targetSw, subnets, getMplsLabel(destSw)
382 ,fwdToSw);
Sangho Shin43cee112014-09-25 16:43:34 -0700383
Sangho Shin43cee112014-09-25 16:43:34 -0700384 String routerIp = destSwitch.getStringAttribute("routerIp");
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700385 setIpTableRouter(targetSw, routerIp, getMplsLabel(destSw), fwdToSw, null);
Sangho Shin43cee112014-09-25 16:43:34 -0700386 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700387 // Only if the target switch is the edge router, then set the IP rules
Sangho Shin43cee112014-09-25 16:43:34 -0700388 else if (IsEdgeRouter(targetSw.getDpid().toString())) {
389 // We assume that there is at least one transit router b/w edge routers
390 Switch destSwitch = mutableTopology.getSwitch(new Dpid(destSw));
391 String routerIp = destSwitch.getStringAttribute("routerIp");
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700392 setIpTableRouter(targetSw, routerIp, getMplsLabel(destSw), fwdToSw, null);
Sangho Shin43cee112014-09-25 16:43:34 -0700393 }
394 // if it is a transit router, then set rules in the MPLS table
395 else {
396 setMplsTable(targetSw, getMplsLabel(destSw), fwdToSw);
397 }
398
399 }
400
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700401 private void setIpTableRouterSubnet(Switch targetSw, String subnets,
402 String mplsLabel, List<String> fwdToSw) {
403
404 Collection <MatchActionOperationEntry> entries =
405 new ArrayList<MatchActionOperationEntry>();
406
407 try {
408 JSONArray arry = new JSONArray(subnets);
409 for (int i = 0; i < arry.length(); i++) {
410 String subnetIp = (String) arry.getJSONObject(i).get("subnetIp");
411 setIpTableRouter(targetSw, subnetIp, mplsLabel, fwdToSw, entries);
412 }
413 } catch (JSONException e) {
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700414 e.printStackTrace();
415 }
416
417 if (!entries.isEmpty()) {
418 IOF13Switch sw13 = (IOF13Switch)floodlightProvider.getMasterSwitch(
419 getSwId(targetSw.getDpid().toString()));
420
421 try {
422 sw13.pushFlows(entries);
423 } catch (IOException e) {
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700424 e.printStackTrace();
425 }
426 }
427
428 }
429
Sangho Shin43cee112014-09-25 16:43:34 -0700430 /**
431 * Check if the switch is the edge router or not
432 * If any subnet information is defined in the config file, the we assume
433 * it is an edge router
434 *
435 * @param dpid Dpid of the switch to check
436 * @return true if it is an edge router, otherwise false
437 */
438 private boolean IsEdgeRouter(String dpid) {
439
440 for (Switch sw: mutableTopology.getSwitches()) {
441 String dpidStr = sw.getDpid().toString();
442 if (dpid.equals(dpidStr)) {
443 String subnetInfo = sw.getStringAttribute("subnets");
444 if (subnetInfo == null || subnetInfo.equals("[]")) {
445 return false;
446 }
447 else
448 return true;
449 }
450 }
451
452 return false;
453 }
454
455 /**
456 * Set IP forwarding rule
457 * - If the destination is the next hop, then do not push MPLS,
458 * just decrease the NW TTL
459 * - Otherwise, push MPLS label and set the MPLS ID
460 *
461 * @param sw target switch to set rules
462 * @param subnetIp Match IP address
463 * @param mplsLabel MPLS label of final destination router
464 * @param fwdToSws next hop routers
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700465 * @param entries
Sangho Shin43cee112014-09-25 16:43:34 -0700466 */
467 private void setIpTableRouter(Switch sw, String subnetIp, String mplsLabel,
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700468 List<String> fwdToSws, Collection<MatchActionOperationEntry> entries) {
Sangho Shin43cee112014-09-25 16:43:34 -0700469
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700470 Ipv4Match ipMatch = new Ipv4Match(subnetIp);
Sangho Shin43cee112014-09-25 16:43:34 -0700471 List<Action> actions = new ArrayList<>();
472
473 // If destination SW is the same as the fwd SW, then do not push MPLS label
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700474
475 if (fwdToSws.size() > 1) {
Sangho Shin43cee112014-09-25 16:43:34 -0700476 PushMplsAction pushMplsAction = new PushMplsAction();
477 SetMplsIdAction setIdAction = new SetMplsIdAction(Integer.parseInt(mplsLabel));
478 CopyTtlOutAction copyTtlOutAction = new CopyTtlOutAction();
Sangho Shin463bee52014-09-29 15:14:43 -0700479 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
Sangho Shin43cee112014-09-25 16:43:34 -0700480
481 actions.add(pushMplsAction);
Sangho Shin43cee112014-09-25 16:43:34 -0700482 actions.add(copyTtlOutAction);
Sangho Shin463bee52014-09-29 15:14:43 -0700483 actions.add(decMplsTtlAction);
484 actions.add(setIdAction);
Sangho Shin43cee112014-09-25 16:43:34 -0700485 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700486 else {
487 String fwdToSw = fwdToSws.get(0);
488 if (getMplsLabel(fwdToSw).equals(mplsLabel)) {
489 DecNwTtlAction decTtlAction = new DecNwTtlAction(1);
490 actions.add(decTtlAction);
491 }
492 else {
493 PushMplsAction pushMplsAction = new PushMplsAction();
494 SetMplsIdAction setIdAction = new SetMplsIdAction(Integer.parseInt(mplsLabel));
495 CopyTtlOutAction copyTtlOutAction = new CopyTtlOutAction();
Sangho Shin463bee52014-09-29 15:14:43 -0700496 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700497
498 actions.add(pushMplsAction);
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700499 actions.add(copyTtlOutAction);
Sangho Shin463bee52014-09-29 15:14:43 -0700500 actions.add(decMplsTtlAction);
501 actions.add(setIdAction);
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700502 }
503 }
Sangho Shin43cee112014-09-25 16:43:34 -0700504
505 GroupAction groupAction = new GroupAction();
506
507 for (String fwdSw : fwdToSws) {
508 groupAction.addSwitch(new Dpid(fwdSw));
509 }
510 actions.add(groupAction);
511
Sangho Shinc8d2f592014-09-30 16:53:57 -0700512 // TODO: Mactch Action Id should be set correctly
Sangho Shin43cee112014-09-25 16:43:34 -0700513 MatchAction matchAction = new MatchAction(new MatchActionId(0),
514 new SwitchPort((long)0,(short)0), ipMatch, actions);
515
516 MatchActionOperationEntry maEntry =
517 new MatchActionOperationEntry(
518 net.onrc.onos.core.matchaction.MatchActionOperations.Operator.ADD,
519 matchAction);
520
Sangho Shin463bee52014-09-29 15:14:43 -0700521 IOF13Switch sw13 = (IOF13Switch)floodlightProvider.getMasterSwitch(
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700522 getSwId(sw.getDpid().toString()));
523
524 try {
525 printMatchActionOperationEntry(sw, maEntry);
Sangho Shin11d4e0f2014-09-30 12:00:33 -0700526 if (entries != null)
527 entries.add(maEntry);
528 else
529 sw13.pushFlow(maEntry);
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700530 } catch (IOException e) {
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700531 e.printStackTrace();
532 }
533
Sangho Shin43cee112014-09-25 16:43:34 -0700534 }
535
536
Sangho Shinac5ee2b2014-09-28 21:27:20 -0700537 /**
538 * Convert a string DPID to its Switch Id (integer)
539 *
540 * @param dpid
541 * @return
542 */
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700543 private long getSwId(String dpid) {
544
545 long swId = 0;
546
547 String swIdStr = dpid.substring(dpid.lastIndexOf(":")+1);
548 if (swIdStr != null)
549 swId = Integer.parseInt(swIdStr);
550
551 return swId;
552 }
553
Sangho Shin43cee112014-09-25 16:43:34 -0700554 /**
555 * Set MPLS forwarding rules to MPLS table
556 * - If the destination is the same as the next hop to forward packets
557 * then, pop the MPLS label according to PHP rule
558 * - Otherwise, just forward packets to next hops using Group action
559 *
560 * @param sw Switch to set the rules
561 * @param mplsLabel destination MPLS label
562 * @param fwdSws next hop switches
563 */
564 private void setMplsTable(Switch sw, String mplsLabel, List<String> fwdSws) {
Sangho Shin463bee52014-09-29 15:14:43 -0700565
Sangho Shin43cee112014-09-25 16:43:34 -0700566 MplsMatch mplsMatch = new MplsMatch(Integer.parseInt(mplsLabel));
567
568 List<Action> actions = new ArrayList<Action>();
Sangho Shin43cee112014-09-25 16:43:34 -0700569
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700570 // If the destination is the same as the next hop, then pop MPLS
Sangho Shinc8d2f592014-09-30 16:53:57 -0700571 // Otherwise, just decrease the MPLS TTL.
Sangho Shin463bee52014-09-29 15:14:43 -0700572 if (fwdSws.size() == 1) {
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700573 String fwdMplsId = getMplsLabel(fwdSws.get(0));
574 if (fwdMplsId.equals(mplsLabel)) {
575 String fwdSw = fwdSws.get(0);
576 if (mplsLabel.equals(getMplsLabel(fwdSw))) {
577 PopMplsAction popAction = new PopMplsAction(EthType.IPv4);
578 CopyTtlInAction copyTtlInAction = new CopyTtlInAction();
Sangho Shin463bee52014-09-29 15:14:43 -0700579 DecNwTtlAction decNwTtlAction = new DecNwTtlAction(1);
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700580
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700581 actions.add(copyTtlInAction);
Sangho Shin463bee52014-09-29 15:14:43 -0700582 actions.add(popAction);
583 actions.add(decNwTtlAction);
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700584 }
585 }
Sangho Shinc8d2f592014-09-30 16:53:57 -0700586 else {
587 DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
588 actions.add(decMplsTtlAction);
589 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700590 }
Sangho Shin43cee112014-09-25 16:43:34 -0700591 GroupAction groupAction = new GroupAction();
592 for (String fwdSw: fwdSws)
593 groupAction.addSwitch(new Dpid(fwdSw));
594 actions.add(groupAction);
595
596 MatchAction matchAction = new MatchAction(new MatchActionId(0),
597 new SwitchPort((long)0,(short)0), mplsMatch, actions);
598
599 MatchActionOperationEntry maEntry =
600 new MatchActionOperationEntry(
601 net.onrc.onos.core.matchaction.MatchActionOperations.Operator.ADD,
602 matchAction);
603
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700604 IOF13Switch sw13 = (IOF13Switch)floodlightProvider.getMasterSwitch(
605 getSwId(sw.getDpid().toString()));
606
607 try {
608 printMatchActionOperationEntry(sw, maEntry);
609 sw13.pushFlow(maEntry);
610 } catch (IOException e) {
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700611 e.printStackTrace();
612 }
613
Sangho Shin43cee112014-09-25 16:43:34 -0700614 }
615
616
617 /**
618 * Debugging function to print out the Match Action Entry
619 *
620 * @param maEntry
621 */
Sangho Shinac5ee2b2014-09-28 21:27:20 -0700622 private void printMatchActionOperationEntry(Switch sw,
623 MatchActionOperationEntry maEntry) {
Sangho Shin43cee112014-09-25 16:43:34 -0700624
Sangho Shin0df01982014-09-25 17:11:18 -0700625 StringBuilder logStr = new StringBuilder("In switch " + sw.getDpid() + ", ");
Sangho Shin43cee112014-09-25 16:43:34 -0700626
627 MatchAction ma = maEntry.getTarget();
628 Match m = ma.getMatch();
629 List<Action> actions = ma.getActions();
630
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700631 if (m instanceof Ipv4Match) {
Sangho Shin43cee112014-09-25 16:43:34 -0700632 logStr.append("If the IP matches with ");
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700633 IPv4Net ip = ((Ipv4Match) m).getDestination();
Sangho Shin43cee112014-09-25 16:43:34 -0700634 logStr.append(ip.toString());
635 logStr.append(" then ");
636 }
637 else if (m instanceof MplsMatch) {
638 logStr.append("If the MPLS label matches with ");
639 int mplsLabel = ((MplsMatch) m).getMplsLabel();
640 logStr.append(mplsLabel);
641 logStr.append(" then ");
642 }
643
644 logStr.append(" do { ");
645 for (Action action: actions) {
646 if (action instanceof CopyTtlInAction) {
647 logStr.append("copy ttl In, ");
648 }
649 else if (action instanceof CopyTtlOutAction) {
650 logStr.append("copy ttl Out, ");
651 }
652 else if (action instanceof DecMplsTtlAction) {
653 logStr.append("Dec MPLS TTL , ");
654 }
655 else if (action instanceof GroupAction) {
656 logStr.append("Forward packet to < ");
Sangho Shin0df01982014-09-25 17:11:18 -0700657 NeighborSet dpids = ((GroupAction)action).getDpids();
658 logStr.append(dpids.toString() + ",");
659
Sangho Shin43cee112014-09-25 16:43:34 -0700660 }
661 else if (action instanceof PopMplsAction) {
662 logStr.append("Pop MPLS label, ");
663 }
664 else if (action instanceof PushMplsAction) {
665 logStr.append("Push MPLS label, ");
666 }
667 else if (action instanceof SetMplsIdAction) {
668 int id = ((SetMplsIdAction)action).getMplsId();
669 logStr.append("Set MPLS ID as " + id + ", ");
670
671 }
672 }
673
674 log.debug(logStr.toString());
675
Sangho Shineb083032014-09-22 16:11:34 -0700676 }
677
678 /**
679 * Get MPLS label reading the config file
680 *
681 * @param dipid DPID of the switch
682 * @return MPLS label for the switch
683 */
684
Sangho Shin43cee112014-09-25 16:43:34 -0700685 private String getMplsLabel(String dpid) {
Sangho Shineb083032014-09-22 16:11:34 -0700686
687 String mplsLabel = null;
688 for (Switch sw: mutableTopology.getSwitches()) {
Sangho Shin43cee112014-09-25 16:43:34 -0700689 String dpidStr = sw.getDpid().toString();
690 if (dpid.equals(dpidStr)) {
Sangho Shineb083032014-09-22 16:11:34 -0700691 mplsLabel = sw.getStringAttribute("nodeSid");
692 break;
Sangho Shin1aa93542014-09-22 09:49:44 -0700693 }
694 }
695
Sangho Shineb083032014-09-22 16:11:34 -0700696 return mplsLabel;
Sangho Shin1aa93542014-09-22 09:49:44 -0700697 }
698
Sangho Shineb083032014-09-22 16:11:34 -0700699
700
701 /**
Sangho Shin1aa93542014-09-22 09:49:44 -0700702 * The function checks if given IP matches to the given subnet mask
703 *
704 * @param addr - subnet address to match
705 * @param addr1 - IP address to check
706 * @return true if the IP address matches to the subnet, otherwise false
707 */
Sangho Shin1aa93542014-09-22 09:49:44 -0700708 public boolean netMatch(String addr, String addr1){ //addr is subnet address and addr1 is ip address. Function will return true, if addr1 is within addr(subnet)
709
710 String[] parts = addr.split("/");
711 String ip = parts[0];
712 int prefix;
713
714 if (parts.length < 2) {
715 prefix = 0;
716 } else {
717 prefix = Integer.parseInt(parts[1]);
718 }
719
720 Inet4Address a =null;
721 Inet4Address a1 =null;
722 try {
723 a = (Inet4Address) InetAddress.getByName(ip);
724 a1 = (Inet4Address) InetAddress.getByName(addr1);
725 } catch (UnknownHostException e){}
726
727 byte[] b = a.getAddress();
728 int ipInt = ((b[0] & 0xFF) << 24) |
729 ((b[1] & 0xFF) << 16) |
730 ((b[2] & 0xFF) << 8) |
731 ((b[3] & 0xFF) << 0);
732
733 byte[] b1 = a1.getAddress();
734 int ipInt1 = ((b1[0] & 0xFF) << 24) |
735 ((b1[1] & 0xFF) << 16) |
736 ((b1[2] & 0xFF) << 8) |
737 ((b1[3] & 0xFF) << 0);
738
739 int mask = ~((1 << (32 - prefix)) - 1);
740
741 if ((ipInt & mask) == (ipInt1 & mask)) {
742 return true;
743 }
744 else {
745 return false;
746 }
747 }
Sangho Shineb083032014-09-22 16:11:34 -0700748
Sangho Shinac5ee2b2014-09-28 21:27:20 -0700749 /**
750 * Add a routing rule for the host
751 *
752 * @param sw - Switch to add the rule
753 * @param hostIpAddress Destination host IP address
754 * @param hostMacAddress Destination host MAC address
755 */
Sangho Shineb083032014-09-22 16:11:34 -0700756 public void addRouteToHost(Switch sw, int hostIpAddress, byte[] hostMacAddress) {
757 ipHandler.addRouteToHost(sw, hostIpAddress, hostMacAddress);
758
759 }
Sangho Shin9c0f4c32014-09-26 16:02:38 -0700760
Sangho Shin463bee52014-09-29 15:14:43 -0700761 /**
762 * Add IP packet to a buffer queue
763 *
764 * @param ipv4
765 */
766 public void addPacket(IPv4 ipv4) {
Sangho Shin61535402014-10-01 11:37:14 -0700767 ipPacketQueue.add(ipv4);
Sangho Shin463bee52014-09-29 15:14:43 -0700768 }
769
770 /**
771 * Retrieve all packets whose destination is the given address.
772 *
773 * @param destIp Destination address of packets to retrieve
774 */
775 public List<IPv4> getIpPacketFromQueue(byte[] destIp) {
776
777 List<IPv4> bufferedPackets = new ArrayList<IPv4>();
778
Sangho Shin61535402014-10-01 11:37:14 -0700779 if (!ipPacketQueue.isEmpty()) {
780 for (IPv4 ip: ipPacketQueue) {
781 int dest = ip.getDestinationAddress();
782 IPv4Address ip1 = IPv4Address.of(dest);
783 IPv4Address ip2 = IPv4Address.of(destIp);
784 if (ip1.equals(ip2)) {
785 bufferedPackets.add((IPv4)(ipPacketQueue.poll()).clone());
Sangho Shin463bee52014-09-29 15:14:43 -0700786 }
787 }
788 }
789
790 return bufferedPackets;
791 }
792
Sangho Shin2f263692014-09-15 14:09:41 -0700793}