Categorized and organized the SemgementRoutingManager.java
Change-Id: I6c1925715aa7f3472d5ddf507dece8228be8ed0c
diff --git a/src/main/java/net/onrc/onos/apps/segmentrouting/GenericIpHandler.java b/src/main/java/net/onrc/onos/apps/segmentrouting/GenericIpHandler.java
index edd2539..5895a8e 100644
--- a/src/main/java/net/onrc/onos/apps/segmentrouting/GenericIpHandler.java
+++ b/src/main/java/net/onrc/onos/apps/segmentrouting/GenericIpHandler.java
@@ -87,7 +87,7 @@
// Check if the destination is within subnets of the swtich
if (isWithinSubnets(sw, IPv4Address.of(destinationAddress).toString())) {
- srManager.addPacket(ipv4);
+ srManager.addPacketToPacketBuffer(ipv4);
srManager.sendArpRequest(sw, destinationAddress, inPort);
}
}
diff --git a/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingManager.java b/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingManager.java
index 668ceaa..ce91138 100644
--- a/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingManager.java
+++ b/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingManager.java
@@ -27,6 +27,7 @@
import net.floodlightcontroller.core.module.IFloodlightModule;
import net.floodlightcontroller.core.module.IFloodlightService;
import net.floodlightcontroller.core.util.SingletonTask;
+import net.floodlightcontroller.restserver.IRestApiService;
import net.floodlightcontroller.threadpool.IThreadPoolService;
import net.floodlightcontroller.util.MACAddress;
import net.onrc.onos.api.packet.IPacketListener;
@@ -70,7 +71,6 @@
import net.onrc.onos.core.util.Dpid;
import net.onrc.onos.core.util.IPv4Net;
import net.onrc.onos.core.util.SwitchPort;
-import net.floodlightcontroller.restserver.IRestApiService;
import org.json.JSONArray;
import org.json.JSONException;
@@ -115,6 +115,10 @@
private final int DELAY_TO_ADD_LINK = 10;
private final int MAX_NUM_LABELS = 3;
+ // ************************************
+ // IFloodlightModule implementation
+ // ************************************
+
@Override
public Collection<Class<? extends IFloodlightService>> getModuleServices() {
// TODO Auto-generated method stub
@@ -199,13 +203,12 @@
//testTask.reschedule(20, TimeUnit.SECONDS);
}
-
@Override
public void receive(Switch sw, Port inPort, Ethernet payload) {
if (payload.getEtherType() == Ethernet.TYPE_ARP)
arpHandler.processPacketIn(sw, inPort, payload);
if (payload.getEtherType() == Ethernet.TYPE_IPV4) {
- addPacket((IPv4) payload.getPayload());
+ addPacketToPacketBuffer((IPv4) payload.getPayload());
if (((IPv4) payload.getPayload()).getProtocol() == IPv4.PROTOCOL_ICMP)
icmpHandler.processPacketIn(sw, inPort, payload);
else
@@ -216,78 +219,10 @@
}
}
- /**
- * Update ARP Cache using ARP packets It is used to set destination MAC
- * address to forward packets to known hosts. But, it will be replace with
- * Host information of Topology service later.
- *
- * @param arp APR packets to use for updating ARP entries
- */
- public void updateArpCache(ARP arp) {
- ArpEntry arpEntry = new ArpEntry(arp.getSenderHardwareAddress(),
- arp.getSenderProtocolAddress());
- // TODO: Need to check the duplication
- arpEntries.add(arpEntry);
- }
-
- /**
- * Get MAC address to known hosts
- *
- * @param destinationAddress IP address to get MAC address
- * @return MAC Address to given IP address
- */
- public byte[] getMacAddressFromIpAddress(int destinationAddress) {
-
- // Can't we get the host IP address from the TopologyService ??
-
- Iterator<ArpEntry> iterator = arpEntries.iterator();
-
- IPv4Address ipAddress = IPv4Address.of(destinationAddress);
- byte[] ipAddressInByte = ipAddress.getBytes();
-
- while (iterator.hasNext()) {
- ArpEntry arpEntry = iterator.next();
- byte[] address = arpEntry.targetIpAddress;
-
- IPv4Address a = IPv4Address.of(address);
- IPv4Address b = IPv4Address.of(ipAddressInByte);
-
- if (a.equals(b)) {
- log.debug("Found an arp entry");
- return arpEntry.targetMacAddress;
- }
- }
-
- return null;
- }
-
- /**
- * Send an ARP request via ArpHandler
- *
- * @param destinationAddress
- * @param sw
- * @param inPort
- *
- */
- public void sendArpRequest(Switch sw, int destinationAddress, Port inPort) {
- arpHandler.sendArpRequest(sw, destinationAddress, inPort);
- }
-
- /**
- * Temporary class to to keep ARP entry
- *
- */
- private class ArpEntry {
-
- byte[] targetMacAddress;
- byte[] targetIpAddress;
-
- private ArpEntry(byte[] macAddress, byte[] ipAddress) {
- this.targetMacAddress = macAddress;
- this.targetIpAddress = ipAddress;
- }
- }
+ // ************************************
+ // Topology event handlers
+ // ************************************
/**
* Topology events that have been generated.
@@ -400,17 +335,6 @@
}
/**
- * Add the link immediately
- * The function is scheduled when link add event happens and called
- * DELAY_TO_ADD_LINK seconds after the event to avoid link flip-flop.
- */
- private void delayedAddLink() {
-
- processLinkAdd(linksToAdd.values(), true);
-
- }
-
- /**
* Process the SwitchAdded events from topologyMananger.
* It does nothing. When a switch is added, then link will be added too.
* LinkAdded event will handle process all re-computation.
@@ -595,6 +519,22 @@
}
/**
+ * Add the link immediately
+ * The function is scheduled when link add event happens and called
+ * DELAY_TO_ADD_LINK seconds after the event to avoid link flip-flop.
+ */
+ private void delayedAddLink() {
+
+ processLinkAdd(linksToAdd.values(), true);
+
+ }
+
+
+ // ************************************
+ // ECMP shorted path routing functions
+ // ************************************
+
+ /**
* Populate routing rules walking through the ECMP shortest paths
*
* @param modified if true, it "modifies" the rules
@@ -679,100 +619,6 @@
}
-
- /**
- * This class is used only for link recovery optimization in
- * modifyEcmpRoutingRules() function.
- * TODO: please remove if the optimization is not used at all
- */
- private class SwitchPair {
- private Switch src;
- private Switch dst;
-
- public SwitchPair(Switch src, Switch dst) {
- this.src = src;
- this.dst = dst;
- }
-
- public Switch getSource() {
- return src;
- }
-
- public Switch getDestination() {
- return dst;
- }
- }
-
- /**
- * Modify the routing rules for the lost links
- * - Recompute the path if the link failed is included in the path
- * (including src and dest).
- *
- * @param newLink
- */
- private void modifyEcmpRoutingRules(LinkData linkRemoved) {
-
- //HashMap<Switch, SwitchPair> linksToRecompute = new HashMap<Switch, SwitchPair>();
- Set<SwitchPair> linksToRecompute = new HashSet<SwitchPair>();
-
- for (ECMPShortestPathGraph ecmpSPG : graphs.values()) {
- Switch rootSw = ecmpSPG.getRootSwitch();
- HashMap<Integer, HashMap<Switch, ArrayList<Path>>> paths =
- ecmpSPG.getCompleteLearnedSwitchesAndPaths();
- for (HashMap<Switch, ArrayList<Path>> p: paths.values()) {
- for (Switch destSw: p.keySet()) {
- ArrayList<Path> path = p.get(destSw);
- if (checkPath(path, linkRemoved)) {
- boolean found = false;
- for (SwitchPair pair: linksToRecompute) {
- if (pair.getSource().getDpid() == rootSw.getDpid() &&
- pair.getSource().getDpid() == destSw.getDpid()) {
- found = true;
- }
- }
- if (!found) {
- linksToRecompute.add(new SwitchPair(rootSw, destSw));
- }
- }
- }
- }
- }
-
- // Recompute the path for the specific route
- for (SwitchPair pair: linksToRecompute) {
-
- log.debug("Recompute path from {} to {}", pair.getSource(), pair.getDestination());
- // We need the following function for optimization
- //ECMPShortestPathGraph ecmpSPG =
- // new ECMPShortestPathGraph(pair.getSource(), pair.getDestination());
- ECMPShortestPathGraph ecmpSPG =
- new ECMPShortestPathGraph(pair.getSource());
- populateEcmpRoutingRulesForPath(pair.getSource(), ecmpSPG, true);
- }
- }
-
- /**
- * Check if the path is affected from the link removed
- *
- * @param path Path to check
- * @param linkRemoved link removed
- * @return true if the path contains the link removed
- */
- private boolean checkPath(ArrayList<Path> path, LinkData linkRemoved) {
-
- for (Path ppp: path) {
- // TODO: need to check if this is a bidirectional or
- // unidirectional
- for (LinkData link: ppp) {
- if (link.getDst().getDpid().equals(linkRemoved.getDst().getDpid()) &&
- link.getSrc().getDpid().equals(linkRemoved.getSrc().getDpid()))
- return true;
- }
- }
-
- return false;
- }
-
/**
*
* Set routing rules in targetSw {forward packets to fwdToSw switches in
@@ -869,38 +715,6 @@
}
/**
- * Check if the switch is the edge router or not.
- *
- * @param dpid Dpid of the switch to check
- * @return true if it is an edge router, otherwise false
- */
- private boolean IsEdgeRouter(String dpid) {
-
- for (Switch sw : mutableTopology.getSwitches()) {
- String dpidStr = sw.getDpid().toString();
- if (dpid.equals(dpidStr)) {
- /*
- String subnetInfo = sw.getStringAttribute("subnets");
- if (subnetInfo == null || subnetInfo.equals("[]")) {
- return false;
- }
- else
- return true;
- */
- String isEdge = sw.getStringAttribute("isEdgeRouter");
- if (isEdge != null) {
- if (isEdge.equals("true"))
- return true;
- else
- return false;
- }
- }
- }
-
- return false;
- }
-
- /**
* Set IP forwarding rule - If the destination is the next hop, then do not
* push MPLS, just decrease the NW TTL - Otherwise, push MPLS label and set
* the MPLS ID
@@ -1104,6 +918,51 @@
}
}
+
+ // ************************************
+ // Policy routing classes and functions
+ // ************************************
+
+ class PolicyRouteInfo {
+
+ String srcSwDpid;
+ List<Dpid> fwdSwDpids;
+ List<String> route;
+
+ PolicyRouteInfo() {
+ fwdSwDpids = new ArrayList<Dpid>();
+ route = new ArrayList<String>();
+ }
+
+ void setSrcDpid(String dpid) {
+ this.srcSwDpid = dpid;
+ }
+
+ void setFwdSwDpid(List<Dpid> dpid) {
+ this.fwdSwDpids = dpid;
+ }
+
+ void addRoute(String id) {
+ route.add(id);
+ }
+
+ void setRoute(List<String> r) {
+ this.route = r;
+ }
+
+ String getSrcSwDpid() {
+ return this.srcSwDpid;
+ }
+
+ List<Dpid> getFwdSwDpid() {
+ return this.fwdSwDpids;
+ }
+
+ List<String> getRoute() {
+ return this.route;
+ }
+ }
+
/**
* Create a tunnel for policy routing
* It delivers the node IDs of tunnels to driver.
@@ -1224,216 +1083,6 @@
}
/**
- * Get the forwarding Switch DPIDs to send packets to a node
- *
- * @param srcSw source switch
- * @param nodeId destination node Id
- * @return list of switch DPID to forward packets to
- */
-
- private List<Dpid> getForwardingSwitchForNodeId(Switch srcSw, String nodeId) {
-
- List<Dpid> fwdSws = new ArrayList<Dpid>();
- Switch destSw = null;
-
- destSw = getSwitchFromNodeId(nodeId);
-
- if (destSw == null) {
- log.debug("Cannot find the switch with ID {}", nodeId);
- return null;
- }
-
- ECMPShortestPathGraph ecmpSPG = new ECMPShortestPathGraph(srcSw);
-
- HashMap<Integer, HashMap<Switch, ArrayList<ArrayList<Dpid>>>> switchVia =
- ecmpSPG.getAllLearnedSwitchesAndVia();
- for (Integer itrIdx : switchVia.keySet()) {
- HashMap<Switch, ArrayList<ArrayList<Dpid>>> swViaMap =
- switchVia.get(itrIdx);
- for (Switch targetSw : swViaMap.keySet()) {
- String destSwDpid = destSw.getDpid().toString();
- if (targetSw.getDpid().toString().equals(destSwDpid)) {
- for (ArrayList<Dpid> via : swViaMap.get(targetSw)) {
- if (via.isEmpty()) {
- fwdSws.add(destSw.getDpid());
- }
- else {
- fwdSws.add(via.get(0));
- }
- }
- }
- }
- }
-
- return fwdSws;
- }
-
- /**
- * Get switch for the node Id specified
- *
- * @param nodeId node ID for switch
- * @return Switch
- */
- private Switch getSwitchFromNodeId(String nodeId) {
-
- for (Switch sw : mutableTopology.getSwitches()) {
- String id = sw.getStringAttribute("nodeSid");
- if (id.equals(nodeId)) {
- return sw;
- }
- }
-
- return null;
- }
-
- /**
- * Convert a string DPID to its Switch Id (integer)
- *
- * @param dpid
- * @return
- */
- private long getSwId(String dpid) {
-
- long swId = 0;
-
- String swIdHexStr = "0x"+dpid.substring(dpid.lastIndexOf(":") + 1);
- if (swIdHexStr != null)
- swId = Integer.decode(swIdHexStr);
-
- return swId;
- }
-
- private void runTest() {
-
- String[] routeArray = {"101", "102", "103", "104", "105", "108", "110"};
- List<String> routeList = new ArrayList<String>();
- for (int i = 0; i < routeArray.length; i++)
- routeList.add(routeArray[i]);
-
- if (createTunnel(1, routeList)) {
- IPv4Net srcIp = new IPv4Net("10.0.1.1/24");
- IPv4Net dstIp = new IPv4Net("10.1.2.1/24");
-
- this.setPolicyTable(null, null, Ethernet.TYPE_IPV4, srcIp, dstIp, IPv4.PROTOCOL_ICMP, (short)-1, (short)-1, 1);
- }
- else {
- testTask.reschedule(5, TimeUnit.SECONDS);
- }
- }
-
- private void runTest1() {
-
- String dpid1 = "00:00:00:00:00:00:00:01";
- String dpid2 = "00:00:00:00:00:00:00:0a";
- Switch srcSw = mutableTopology.getSwitch(new Dpid(dpid1));
- Switch dstSw = mutableTopology.getSwitch(new Dpid(dpid2));
-
- if (srcSw == null || dstSw == null) {
- testTask.reschedule(1, TimeUnit.SECONDS);
- log.debug("Switch is gone. Reschedule the test");
- return;
- }
-
- String[] routeArray = {"101", "102", "105", "108", "110"};
- List<String> routeList = new ArrayList<String>();
- for (int i = 0; i < routeArray.length; i++)
- routeList.add(routeArray[i]);
-
- List<String> optimizedRoute = this.getOptimizedPath(srcSw, dstSw, routeList);
-
- log.debug("Test set is {}", routeList.toString());
- log.debug("Result set is {}", optimizedRoute.toString());
-
-
- }
-
- /**
- * Optimize the mpls label
- * The feature will be used only for policy of "avoid a specific switch".
- * Check route to each router in route backward.
- * If there is only one route to the router and the routers are included in
- * the route, remove the id from the path.
- * A-B-C-D-E => A-B-C-D-E -> A-E
- * | | => A-B-H-I -> A-I
- * F-G-H-I => A-D-I -> A-D-I
- */
- private List<String> getOptimizedPath(Switch srcSw, Switch dstSw, List<String> route) {
-
- List<String> optimizedPath = new ArrayList<String>();
- optimizedPath.addAll(route);
- ECMPShortestPathGraph ecmpSPG = new ECMPShortestPathGraph(srcSw);
-
- HashMap<Integer, HashMap<Switch, ArrayList<Path>>> paths =
- ecmpSPG.getCompleteLearnedSwitchesAndPaths();
- for (HashMap<Switch, ArrayList<Path>> p: paths.values()) {
- for (Switch s: p.keySet()) {
- if (s.getDpid().toString().equals(dstSw.getDpid().toString())) {
- ArrayList<Path> ecmpPaths = p.get(s);
- if (ecmpPaths!= null && ecmpPaths.size() == 1) {
- for (Path path: ecmpPaths) {
- for (LinkData link: path) {
- String srcId = getMplsLabel(link.getSrc().getDpid().toString());
- String dstId = getMplsLabel(link.getSrc().getDpid().toString());
- if (optimizedPath.contains(srcId)) {
- optimizedPath.remove(srcId);
- }
- if (optimizedPath.contains(dstId)) {
- optimizedPath.remove(dstId);
- }
- }
- }
- }
- }
- }
- }
-
- return optimizedPath;
-
- }
-
-
- class PolicyRouteInfo {
-
- String srcSwDpid;
- List<Dpid> fwdSwDpids;
- List<String> route;
-
- PolicyRouteInfo() {
- fwdSwDpids = new ArrayList<Dpid>();
- route = new ArrayList<String>();
- }
-
- void setSrcDpid(String dpid) {
- this.srcSwDpid = dpid;
- }
-
- void setFwdSwDpid(List<Dpid> dpid) {
- this.fwdSwDpids = dpid;
- }
-
- void addRoute(String id) {
- route.add(id);
- }
-
- void setRoute(List<String> r) {
- this.route = r;
- }
-
- String getSrcSwDpid() {
- return this.srcSwDpid;
- }
-
- List<Dpid> getFwdSwDpid() {
- return this.fwdSwDpids;
- }
-
- List<String> getRoute() {
- return this.route;
- }
- }
-
-
- /**
*
*
* @param srcSw
@@ -1528,96 +1177,120 @@
return rules;
}
+
+ // ************************************
+ // Utility functions
+ // ************************************
+
/**
- * print tunnel info - used only for debugging.
- * @param targetSw
+ * Get the forwarding Switch DPIDs to send packets to a node
*
- * @param fwdSwDpids
- * @param ids
- * @param tunnelId
+ * @param srcSw source switch
+ * @param nodeId destination node Id
+ * @return list of switch DPID to forward packets to
*/
- private void printTunnelInfo(IOF13Switch targetSw, int tunnelId,
- List<String> ids, NeighborSet ns) {
- StringBuilder logStr = new StringBuilder("In switch " +
- targetSw.getId() + ", create a tunnel " + tunnelId + " " + " of push ");
- for (String id: ids)
- logStr.append(id + "-");
- logStr.append(" output to ");
- for (Dpid dpid: ns.getDpids())
- logStr.append(dpid + " - ");
+ private List<Dpid> getForwardingSwitchForNodeId(Switch srcSw, String nodeId) {
- log.debug(logStr.toString());
+ List<Dpid> fwdSws = new ArrayList<Dpid>();
+ Switch destSw = null;
+ destSw = getSwitchFromNodeId(nodeId);
+
+ if (destSw == null) {
+ log.debug("Cannot find the switch with ID {}", nodeId);
+ return null;
+ }
+
+ ECMPShortestPathGraph ecmpSPG = new ECMPShortestPathGraph(srcSw);
+
+ HashMap<Integer, HashMap<Switch, ArrayList<ArrayList<Dpid>>>> switchVia =
+ ecmpSPG.getAllLearnedSwitchesAndVia();
+ for (Integer itrIdx : switchVia.keySet()) {
+ HashMap<Switch, ArrayList<ArrayList<Dpid>>> swViaMap =
+ switchVia.get(itrIdx);
+ for (Switch targetSw : swViaMap.keySet()) {
+ String destSwDpid = destSw.getDpid().toString();
+ if (targetSw.getDpid().toString().equals(destSwDpid)) {
+ for (ArrayList<Dpid> via : swViaMap.get(targetSw)) {
+ if (via.isEmpty()) {
+ fwdSws.add(destSw.getDpid());
+ }
+ else {
+ fwdSws.add(via.get(0));
+ }
+ }
+ }
+ }
+ }
+
+ return fwdSws;
}
+ /**
+ * Get switch for the node Id specified
+ *
+ * @param nodeId node ID for switch
+ * @return Switch
+ */
+ private Switch getSwitchFromNodeId(String nodeId) {
+ for (Switch sw : mutableTopology.getSwitches()) {
+ String id = sw.getStringAttribute("nodeSid");
+ if (id.equals(nodeId)) {
+ return sw;
+ }
+ }
+
+ return null;
+ }
/**
- * Debugging function to print out the Match Action Entry
- * @param sw13
+ * Convert a string DPID to its Switch Id (integer)
*
- * @param maEntry
+ * @param dpid
+ * @return
*/
- private void printMatchActionOperationEntry(
- IOF13Switch sw13, MatchActionOperationEntry maEntry) {
+ private long getSwId(String dpid) {
- StringBuilder logStr = new StringBuilder("In switch " + sw13.getId() + ", ");
+ long swId = 0;
- MatchAction ma = maEntry.getTarget();
- Match m = ma.getMatch();
- List<Action> actions = ma.getActions();
+ String swIdHexStr = "0x"+dpid.substring(dpid.lastIndexOf(":") + 1);
+ if (swIdHexStr != null)
+ swId = Integer.decode(swIdHexStr);
- if (m instanceof Ipv4Match) {
- logStr.append("If the IP matches with ");
- IPv4Net ip = ((Ipv4Match) m).getDestination();
- logStr.append(ip.toString());
- logStr.append(" then ");
- }
- else if (m instanceof MplsMatch) {
- logStr.append("If the MPLS label matches with ");
- int mplsLabel = ((MplsMatch) m).getMplsLabel();
- logStr.append(mplsLabel);
- logStr.append(" then ");
- }
- else if (m instanceof PacketMatch) {
- GroupAction ga = (GroupAction)actions.get(0);
- logStr.append("if the policy match is XXX then go to group " +
- ga.getGroupId());
- log.debug(logStr.toString());
- return;
- }
+ return swId;
+ }
- logStr.append(" do { ");
- for (Action action : actions) {
- if (action instanceof CopyTtlInAction) {
- logStr.append("copy ttl In, ");
- }
- else if (action instanceof CopyTtlOutAction) {
- logStr.append("copy ttl Out, ");
- }
- else if (action instanceof DecMplsTtlAction) {
- logStr.append("Dec MPLS TTL , ");
- }
- else if (action instanceof GroupAction) {
- logStr.append("Forward packet to < ");
- NeighborSet dpids = ((GroupAction) action).getDpids();
- logStr.append(dpids.toString() + ",");
+ /**
+ * Check if the switch is the edge router or not.
+ *
+ * @param dpid Dpid of the switch to check
+ * @return true if it is an edge router, otherwise false
+ */
+ private boolean IsEdgeRouter(String dpid) {
- }
- else if (action instanceof PopMplsAction) {
- logStr.append("Pop MPLS label, ");
- }
- else if (action instanceof PushMplsAction) {
- logStr.append("Push MPLS label, ");
- }
- else if (action instanceof SetMplsIdAction) {
- int id = ((SetMplsIdAction) action).getMplsId();
- logStr.append("Set MPLS ID as " + id + ", ");
+ for (Switch sw : mutableTopology.getSwitches()) {
+ String dpidStr = sw.getDpid().toString();
+ if (dpid.equals(dpidStr)) {
+ /*
+ String subnetInfo = sw.getStringAttribute("subnets");
+ if (subnetInfo == null || subnetInfo.equals("[]")) {
+ return false;
+ }
+ else
+ return true;
+ */
+ String isEdge = sw.getStringAttribute("isEdgeRouter");
+ if (isEdge != null) {
+ if (isEdge.equals("true"))
+ return true;
+ else
+ return false;
+ }
}
}
- log.debug(logStr.toString());
-
+ return false;
}
/**
@@ -1626,7 +1299,6 @@
* @param dipid DPID of the switch
* @return MPLS label for the switch
*/
-
private String getMplsLabel(String dpid) {
String mplsLabel = null;
@@ -1704,7 +1376,6 @@
*/
public void addRouteToHost(Switch sw, int hostIpAddress, byte[] hostMacAddress) {
ipHandler.addRouteToHost(sw, hostIpAddress, hostMacAddress);
-
}
/**
@@ -1712,7 +1383,7 @@
*
* @param ipv4
*/
- public void addPacket(IPv4 ipv4) {
+ public void addPacketToPacketBuffer(IPv4 ipv4) {
ipPacketQueue.add(ipv4);
}
@@ -1739,6 +1410,359 @@
return bufferedPackets;
}
+ /**
+ * Get MAC address to known hosts
+ *
+ * @param destinationAddress IP address to get MAC address
+ * @return MAC Address to given IP address
+ */
+ public byte[] getMacAddressFromIpAddress(int destinationAddress) {
+
+ // Can't we get the host IP address from the TopologyService ??
+
+ Iterator<ArpEntry> iterator = arpEntries.iterator();
+
+ IPv4Address ipAddress = IPv4Address.of(destinationAddress);
+ byte[] ipAddressInByte = ipAddress.getBytes();
+
+ while (iterator.hasNext()) {
+ ArpEntry arpEntry = iterator.next();
+ byte[] address = arpEntry.targetIpAddress;
+
+ IPv4Address a = IPv4Address.of(address);
+ IPv4Address b = IPv4Address.of(ipAddressInByte);
+
+ if (a.equals(b)) {
+ log.debug("Found an arp entry");
+ return arpEntry.targetMacAddress;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Send an ARP request via ArpHandler
+ *
+ * @param destinationAddress
+ * @param sw
+ * @param inPort
+ *
+ */
+ public void sendArpRequest(Switch sw, int destinationAddress, Port inPort) {
+ arpHandler.sendArpRequest(sw, destinationAddress, inPort);
+ }
+
+
+ // ************************************
+ // Test functions
+ // ************************************
+
+ private void runTest() {
+
+ String[] routeArray = {"101", "102", "103", "104", "105", "108", "110"};
+ List<String> routeList = new ArrayList<String>();
+ for (int i = 0; i < routeArray.length; i++)
+ routeList.add(routeArray[i]);
+
+ if (createTunnel(1, routeList)) {
+ IPv4Net srcIp = new IPv4Net("10.0.1.1/24");
+ IPv4Net dstIp = new IPv4Net("10.1.2.1/24");
+
+ this.setPolicyTable(null, null, Ethernet.TYPE_IPV4, srcIp, dstIp, IPv4.PROTOCOL_ICMP, (short)-1, (short)-1, 1);
+ }
+ else {
+ testTask.reschedule(5, TimeUnit.SECONDS);
+ }
+ }
+
+ private void runTest1() {
+
+ String dpid1 = "00:00:00:00:00:00:00:01";
+ String dpid2 = "00:00:00:00:00:00:00:0a";
+ Switch srcSw = mutableTopology.getSwitch(new Dpid(dpid1));
+ Switch dstSw = mutableTopology.getSwitch(new Dpid(dpid2));
+
+ if (srcSw == null || dstSw == null) {
+ testTask.reschedule(1, TimeUnit.SECONDS);
+ log.debug("Switch is gone. Reschedule the test");
+ return;
+ }
+
+ String[] routeArray = {"101", "102", "105", "108", "110"};
+ List<String> routeList = new ArrayList<String>();
+ for (int i = 0; i < routeArray.length; i++)
+ routeList.add(routeArray[i]);
+
+ List<String> optimizedRoute = this.getOptimizedPath(srcSw, dstSw, routeList);
+
+ log.debug("Test set is {}", routeList.toString());
+ log.debug("Result set is {}", optimizedRoute.toString());
+
+
+ }
+
+ /**
+ * print tunnel info - used only for debugging.
+ * @param targetSw
+ *
+ * @param fwdSwDpids
+ * @param ids
+ * @param tunnelId
+ */
+ private void printTunnelInfo(IOF13Switch targetSw, int tunnelId,
+ List<String> ids, NeighborSet ns) {
+ StringBuilder logStr = new StringBuilder("In switch " +
+ targetSw.getId() + ", create a tunnel " + tunnelId + " " + " of push ");
+ for (String id: ids)
+ logStr.append(id + "-");
+ logStr.append(" output to ");
+ for (Dpid dpid: ns.getDpids())
+ logStr.append(dpid + " - ");
+
+ log.debug(logStr.toString());
+
+ }
+
+ /**
+ * Debugging function to print out the Match Action Entry
+ * @param sw13
+ *
+ * @param maEntry
+ */
+ private void printMatchActionOperationEntry(
+ IOF13Switch sw13, MatchActionOperationEntry maEntry) {
+
+ StringBuilder logStr = new StringBuilder("In switch " + sw13.getId() + ", ");
+
+ MatchAction ma = maEntry.getTarget();
+ Match m = ma.getMatch();
+ List<Action> actions = ma.getActions();
+
+ if (m instanceof Ipv4Match) {
+ logStr.append("If the IP matches with ");
+ IPv4Net ip = ((Ipv4Match) m).getDestination();
+ logStr.append(ip.toString());
+ logStr.append(" then ");
+ }
+ else if (m instanceof MplsMatch) {
+ logStr.append("If the MPLS label matches with ");
+ int mplsLabel = ((MplsMatch) m).getMplsLabel();
+ logStr.append(mplsLabel);
+ logStr.append(" then ");
+ }
+ else if (m instanceof PacketMatch) {
+ GroupAction ga = (GroupAction)actions.get(0);
+ logStr.append("if the policy match is XXX then go to group " +
+ ga.getGroupId());
+ log.debug(logStr.toString());
+ return;
+ }
+
+ logStr.append(" do { ");
+ for (Action action : actions) {
+ if (action instanceof CopyTtlInAction) {
+ logStr.append("copy ttl In, ");
+ }
+ else if (action instanceof CopyTtlOutAction) {
+ logStr.append("copy ttl Out, ");
+ }
+ else if (action instanceof DecMplsTtlAction) {
+ logStr.append("Dec MPLS TTL , ");
+ }
+ else if (action instanceof GroupAction) {
+ logStr.append("Forward packet to < ");
+ NeighborSet dpids = ((GroupAction) action).getDpids();
+ logStr.append(dpids.toString() + ",");
+
+ }
+ else if (action instanceof PopMplsAction) {
+ logStr.append("Pop MPLS label, ");
+ }
+ else if (action instanceof PushMplsAction) {
+ logStr.append("Push MPLS label, ");
+ }
+ else if (action instanceof SetMplsIdAction) {
+ int id = ((SetMplsIdAction) action).getMplsId();
+ logStr.append("Set MPLS ID as " + id + ", ");
+ }
+ }
+
+ log.debug(logStr.toString());
+
+ }
+
+
+ // ************************************
+ // Unused classes and functions
+ // ************************************
+
+ /**
+ * Temporary class to to keep ARP entry
+ *
+ */
+ private class ArpEntry {
+
+ byte[] targetMacAddress;
+ byte[] targetIpAddress;
+
+ private ArpEntry(byte[] macAddress, byte[] ipAddress) {
+ this.targetMacAddress = macAddress;
+ this.targetIpAddress = ipAddress;
+ }
+ }
+
+ /**
+ * This class is used only for link recovery optimization in
+ * modifyEcmpRoutingRules() function.
+ * TODO: please remove if the optimization is not used at all
+ */
+ private class SwitchPair {
+ private Switch src;
+ private Switch dst;
+
+ public SwitchPair(Switch src, Switch dst) {
+ this.src = src;
+ this.dst = dst;
+ }
+
+ public Switch getSource() {
+ return src;
+ }
+
+ public Switch getDestination() {
+ return dst;
+ }
+ }
+
+ /**
+ * Update ARP Cache using ARP packets It is used to set destination MAC
+ * address to forward packets to known hosts. But, it will be replace with
+ * Host information of Topology service later.
+ *
+ * @param arp APR packets to use for updating ARP entries
+ */
+ public void updateArpCache(ARP arp) {
+
+ ArpEntry arpEntry = new ArpEntry(arp.getSenderHardwareAddress(),
+ arp.getSenderProtocolAddress());
+ // TODO: Need to check the duplication
+ arpEntries.add(arpEntry);
+ }
+
+ /**
+ * Modify the routing rules for the lost links
+ * - Recompute the path if the link failed is included in the path
+ * (including src and dest).
+ *
+ * @param newLink
+ */
+ private void modifyEcmpRoutingRules(LinkData linkRemoved) {
+
+ //HashMap<Switch, SwitchPair> linksToRecompute = new HashMap<Switch, SwitchPair>();
+ Set<SwitchPair> linksToRecompute = new HashSet<SwitchPair>();
+
+ for (ECMPShortestPathGraph ecmpSPG : graphs.values()) {
+ Switch rootSw = ecmpSPG.getRootSwitch();
+ HashMap<Integer, HashMap<Switch, ArrayList<Path>>> paths =
+ ecmpSPG.getCompleteLearnedSwitchesAndPaths();
+ for (HashMap<Switch, ArrayList<Path>> p: paths.values()) {
+ for (Switch destSw: p.keySet()) {
+ ArrayList<Path> path = p.get(destSw);
+ if (checkPath(path, linkRemoved)) {
+ boolean found = false;
+ for (SwitchPair pair: linksToRecompute) {
+ if (pair.getSource().getDpid() == rootSw.getDpid() &&
+ pair.getSource().getDpid() == destSw.getDpid()) {
+ found = true;
+ }
+ }
+ if (!found) {
+ linksToRecompute.add(new SwitchPair(rootSw, destSw));
+ }
+ }
+ }
+ }
+ }
+
+ // Recompute the path for the specific route
+ for (SwitchPair pair: linksToRecompute) {
+
+ log.debug("Recompute path from {} to {}", pair.getSource(), pair.getDestination());
+ // We need the following function for optimization
+ //ECMPShortestPathGraph ecmpSPG =
+ // new ECMPShortestPathGraph(pair.getSource(), pair.getDestination());
+ ECMPShortestPathGraph ecmpSPG =
+ new ECMPShortestPathGraph(pair.getSource());
+ populateEcmpRoutingRulesForPath(pair.getSource(), ecmpSPG, true);
+ }
+ }
+
+ /**
+ * Optimize the mpls label
+ * The feature will be used only for policy of "avoid a specific switch".
+ * Check route to each router in route backward.
+ * If there is only one route to the router and the routers are included in
+ * the route, remove the id from the path.
+ * A-B-C-D-E => A-B-C-D-E -> A-E
+ * | | => A-B-H-I -> A-I
+ * F-G-H-I => A-D-I -> A-D-I
+ */
+ private List<String> getOptimizedPath(Switch srcSw, Switch dstSw, List<String> route) {
+
+ List<String> optimizedPath = new ArrayList<String>();
+ optimizedPath.addAll(route);
+ ECMPShortestPathGraph ecmpSPG = new ECMPShortestPathGraph(srcSw);
+
+ HashMap<Integer, HashMap<Switch, ArrayList<Path>>> paths =
+ ecmpSPG.getCompleteLearnedSwitchesAndPaths();
+ for (HashMap<Switch, ArrayList<Path>> p: paths.values()) {
+ for (Switch s: p.keySet()) {
+ if (s.getDpid().toString().equals(dstSw.getDpid().toString())) {
+ ArrayList<Path> ecmpPaths = p.get(s);
+ if (ecmpPaths!= null && ecmpPaths.size() == 1) {
+ for (Path path: ecmpPaths) {
+ for (LinkData link: path) {
+ String srcId = getMplsLabel(link.getSrc().getDpid().toString());
+ String dstId = getMplsLabel(link.getSrc().getDpid().toString());
+ if (optimizedPath.contains(srcId)) {
+ optimizedPath.remove(srcId);
+ }
+ if (optimizedPath.contains(dstId)) {
+ optimizedPath.remove(dstId);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return optimizedPath;
+
+ }
+
+ /**
+ * Check if the path is affected from the link removed
+ *
+ * @param path Path to check
+ * @param linkRemoved link removed
+ * @return true if the path contains the link removed
+ */
+ private boolean checkPath(ArrayList<Path> path, LinkData linkRemoved) {
+
+ for (Path ppp: path) {
+ // TODO: need to check if this is a bidirectional or
+ // unidirectional
+ for (LinkData link: ppp) {
+ if (link.getDst().getDpid().equals(linkRemoved.getDst().getDpid()) &&
+ link.getSrc().getDpid().equals(linkRemoved.getSrc().getDpid()))
+ return true;
+ }
+ }
+
+ return false;
+ }
}