Tunnel loadbalancing policy: phase2 support
diff --git a/src/main/java/net/floodlightcontroller/core/IOF13Switch.java b/src/main/java/net/floodlightcontroller/core/IOF13Switch.java
index 3eaf58d..63e90c4 100644
--- a/src/main/java/net/floodlightcontroller/core/IOF13Switch.java
+++ b/src/main/java/net/floodlightcontroller/core/IOF13Switch.java
@@ -9,6 +9,8 @@
import java.util.Map;
import java.util.Set;
+import net.floodlightcontroller.core.IOF13Switch.GroupChain;
+import net.floodlightcontroller.core.IOF13Switch.GroupChainParams;
import net.onrc.onos.core.matchaction.MatchActionOperationEntry;
import net.onrc.onos.core.util.Dpid;
import net.onrc.onos.core.util.PortNumber;
@@ -205,7 +207,7 @@
* ports. This API can be used by user to create groups for a tunnel based
* policy routing scenario. NOTE: This API can not be used if a group to be
* created with different label stacks for each port in the given set of
- * ports. Use XXX API for this purpose
+ * ports. Use createGroupChain API for this purpose
*
* @param labelStack list of router segment Ids to be pushed. Can be empty.
* labelStack is processed from left to right with leftmost
@@ -298,7 +300,51 @@
}
}
- public List<GroupChain> createGroupChain(List<GroupChainParams> groupChainParams);
+ /**
+ * Create a group chain with the specified label stack for each given set of
+ * ports. This API can be used by user to create groups for a tunnel based
+ * policy routing scenario.
+ *
+ * @param groupChainParams list of ports along with label stacks to be
+ * applied. label stack can be empty.
+ * labelStack is processed from left to right with leftmost
+ * representing the outermost label and rightmost representing
+ * innermost label to be pushed
+ * List of ports on this switch to get to the first router in
+ * the labelStack
+ * @return List of GroupChain objects
+ */
+ public List<GroupChain> createGroupChain(
+ List<GroupChainParams> groupChainParams);
+ /**
+ * Add a new entry to an existing group chain
+ *
+ * @param currentGroupChainList Existing group chain to which this
+ * new entry to be added
+ * @param groupChainParams list of ports along with label stacks to be
+ * applied. label stack can be empty.
+ * labelStack is processed from left to right with leftmost
+ * representing the outermost label and rightmost representing
+ * innermost label to be pushed
+ * List of ports on this switch to get to the first router in
+ * the labelStack
+ * @return Modified list of GroupChain objects
+ */
+ public List<GroupChain> addNewEntryToGroupChain(
+ List<GroupChain> currentGroupChainList,
+ List<GroupChainParams> groupChainParams);
+ /**
+ * Remove one or more buckes from the given innermost group those
+ * point to the list of groups specified in chainedGroups list
+ *
+ * @param innermostGroupId The innermost group from which buckets,
+ * pointing to the groupIds in the chainedGroups list param,
+ * to be deleted
+ * @param chainedGroups list of groupIds
+ * @return True or False depending on the result of the removal
+ */
+ public boolean removeOutGroupBucketsFromGroup(
+ int innermostGroupId, List<Integer> chainedGroups);
/**
* Remove the specified group
diff --git a/src/main/java/net/onrc/onos/apps/segmentrouting/ISegmentRoutingService.java b/src/main/java/net/onrc/onos/apps/segmentrouting/ISegmentRoutingService.java
index 9c49eba..10d81e4 100644
--- a/src/main/java/net/onrc/onos/apps/segmentrouting/ISegmentRoutingService.java
+++ b/src/main/java/net/onrc/onos/apps/segmentrouting/ISegmentRoutingService.java
@@ -31,12 +31,12 @@
/**
* Create a tunnelset for policy routing.
*
- * @param tunnelId ID for the tunnel
- * @param labelIds Node label IDs for the tunnel
+ * @param tunnelsetId ID for the tunnelset
+ * @param tunnelsetParams tunnelset REST params
*
- * @return "true/false" depending tunnel creation status
+ * @return "true/false" depending tunnelset creation status
*/
- public boolean createTunnelset(String tunnelsetId,
+ public boolean createUpdateTunnelset(String tunnelsetId,
SegmentRouterTunnelsetRESTParams tunnelsetParams);
/**
@@ -49,6 +49,15 @@
public removeTunnelMessages removeTunnel(String tunnelId);
/**
+ * Remove a Segment Routing tunnelset given a tunnel Id.
+ *
+ * @param tunnelsetId ID for the tunnelset
+ *
+ * @return "true/false" depending tunnelset deletion status
+ */
+ public removeTunnelMessages removeTunnelset(String tunnelsetId);
+
+ /**
* Create a policy for policy based segment routing
*
* @param pid Unique Policy Identifier
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 921fd35..857a43e 100644
--- a/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingManager.java
+++ b/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingManager.java
@@ -1380,22 +1380,114 @@
}
}
- public boolean createTunnelset(String tunnelsetId,
+ public boolean createUpdateTunnelset(String tunnelsetId,
SegmentRouterTunnelsetRESTParams tunnelsetParams) {
- SegmentRoutingTunnelset srTunnelset =
- new SegmentRoutingTunnelset(this, tunnelsetParams);
- if (srTunnelset.createTunnelSet()) {
- tunnelsetTable.put(tunnelsetId, srTunnelset);
- HashMap<String,SegmentRoutingTunnel> tunnelsetTunnels =
- srTunnelset.getTunnels();
- for (String tunnelId:tunnelsetTunnels.keySet())
- tunnelTable.put(tunnelId, tunnelsetTunnels.get(tunnelId));
- return true;
- }
- else {
- log.warn("Failed to create a tunnel");
+ SegmentRoutingTunnelset srTunnelset = tunnelsetTable.get(tunnelsetId);
+ if (((tunnelsetParams.getTunnelParams() == null) &&
+ (tunnelsetParams.getRemove_tunnel_params() == null)) ||
+ ((tunnelsetParams.getRemove_tunnel_params() != null) &&
+ (srTunnelset == null))){
+ log.warn("Invalid input to create/update tunnelset");
return false;
- }
+ }
+
+ if (tunnelsetParams.getTunnelParams() != null) {
+ for (SegmentRouterTunnelRESTParams tunnelParams:tunnelsetParams.getTunnelParams()) {
+ if (tunnelTable.get(tunnelParams.getTunnel_id()) != null) {
+ /* A tunnel already exists with this Id */
+ log.warn("Invalid input to create/update tunnelset: "
+ + "A tunnel already exist with the same Id");
+ return false;
+ }
+ }
+ }
+ if (tunnelsetParams.getRemove_tunnel_params() != null) {
+ for (String tunnelId:tunnelsetParams.getRemove_tunnel_params()) {
+ if (srTunnelset.getTunnels().get(tunnelId) == null) {
+ /* tunnel does not exist in this tunnel set */
+ log.warn("Invalid input to create/update tunnelset: "
+ + "tunnelId {} is not part of tunnelset {}",
+ tunnelId, tunnelsetId);
+ return false;
+ }
+ }
+ }
+
+ if (srTunnelset == null) {
+ srTunnelset =
+ new SegmentRoutingTunnelset(this, tunnelsetParams);
+ if (srTunnelset.createTunnelSet()) {
+ tunnelsetTable.put(tunnelsetId, srTunnelset);
+ HashMap<String,SegmentRoutingTunnel> tunnelsetTunnels =
+ srTunnelset.getTunnels();
+ for (String tunnelId:tunnelsetTunnels.keySet())
+ tunnelTable.put(tunnelId, tunnelsetTunnels.get(tunnelId));
+ return true;
+ }
+ else {
+ log.warn("Failed to create a tunnel");
+ return false;
+ }
+ }
+ else {
+ /* Verify if this is an update operation on the existing tunnelset
+ * - Check if it is constituent tunnel addition or deletion
+ */
+ boolean tunnelsetUpdated = false;
+ if (tunnelsetParams.getTunnelParams() != null) {
+ /* add new tunnels */
+ HashMap<String,SegmentRoutingTunnel> newTunnelMap =
+ srTunnelset.addNewTunnelsToTunnelset(tunnelsetParams);
+ if (newTunnelMap == null) {
+ log.warn("Failed to add new tunnels "
+ + "to tunnelset {}",tunnelsetId);
+ return false;
+ }
+ for (String tunnelId:newTunnelMap.keySet())
+ tunnelTable.put(tunnelId, newTunnelMap.get(tunnelId));
+ tunnelsetUpdated = true;
+ }
+ if (tunnelsetParams.getRemove_tunnel_params() != null) {
+ /* remove tunnels from tunnelset */
+ if (srTunnelset.removeConstituentTunnelFromTunnelset(
+ tunnelsetParams) == false) {
+ log.warn("Failed to remove tunnels "
+ + "from tunnelset {}",tunnelsetId);
+ return false;
+ }
+ tunnelsetUpdated = true;
+ }
+
+ if (tunnelsetUpdated) {
+ /* Update the policies pointing to this tunnelset */
+ Collection<SegmentRoutingPolicy> policies = getPoclicyTable();
+ Iterator<SegmentRoutingPolicy> piI = policies.iterator();
+ while(piI.hasNext()){
+ SegmentRoutingPolicy policy = piI.next();
+ if(policy.getType() == PolicyType.LOADBALANCE &&
+ (((SegmentRoutingPolicyTunnel)policy).isTunnelsetId() &&
+ ((SegmentRoutingPolicyTunnel)policy).
+ getTunnelId().equals(tunnelsetId))){
+ if (((SegmentRoutingPolicyTunnel)policy).
+ removePolicy() == true) {
+ if (((SegmentRoutingPolicyTunnel)policy).
+ createPolicy() != true) {
+ log.warn("Failed to update policies "
+ + "pointing to this tunnelset");
+ return false;
+ }
+ }
+ else {
+ log.warn("Failed to update policies "
+ + "pointing to this tunnelset");
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+ return false;
+ }
}
/**
@@ -1435,7 +1527,8 @@
srcIp, dstIp, ipProto, srcPort, dstPort);
SegmentRoutingPolicy srPolicy =
- new SegmentRoutingPolicyTunnel(this,pid, PolicyType.TUNNEL_FLOW,
+ new SegmentRoutingPolicyTunnel(this,pid,
+ (isTunnelsetId)?PolicyType.LOADBALANCE:PolicyType.TUNNEL_FLOW,
policyMatch, priority, tid);
((SegmentRoutingPolicyTunnel)srPolicy).setIsTunnelsetId(isTunnelsetId);
if (srPolicy.createPolicy()) {
@@ -1588,6 +1681,51 @@
}
}
+ /**
+ * Remove a tunnelset
+ * It removes all groups for the tunnel if the tunnelset is not used for any
+ * policy.
+ *
+ * @param tunnelId tunnel ID to remove
+ */
+ public removeTunnelMessages removeTunnelset(String tunnelsetId) {
+
+ // Check if the tunnel is used for any policy
+ for (SegmentRoutingPolicy policy: policyTable.values()) {
+ if (policy.getType() == PolicyType.LOADBALANCE) {
+ if (((SegmentRoutingPolicyTunnel)policy).isTunnelsetId()) {
+ String tid = ((SegmentRoutingPolicyTunnel)policy).getTunnelId();
+ if (tid.equals(tunnelsetId)) {
+ log.debug("Tunnelset {} is still used for the policy {}.",
+ policy.getPolicyId(), tunnelsetId);
+ return removeTunnelMessages.ERROR_REFERENCED;
+ }
+ }
+ }
+ }
+
+ SegmentRoutingTunnelset tunnelset = tunnelsetTable.get(tunnelsetId);
+ if (tunnelset == null) {
+ log.warn("Tunnulset object does not exist {}", tunnelsetId);
+ return removeTunnelMessages.ERROR_TUNNEL;
+ }
+ else {
+ HashMap<String, SegmentRoutingTunnel> constituentTunnels = tunnelset.getTunnels();
+ if (tunnelset.removeTunnelset()) {
+ for (String tunnelId:constituentTunnels.keySet())
+ tunnelTable.remove(tunnelId);
+ tunnelsetTable.remove(tunnelsetId);
+ log.debug("Tunnelset {} was removed successfully.", tunnelsetId);
+ //tunnelEventChannel.removeEntry(tunnelId);
+ return removeTunnelMessages.SUCCESS;
+ }
+ else {
+ log.warn("Faild in removing the tunnelset {}", tunnelsetId);
+ return removeTunnelMessages.ERROR_DRIVER;
+ }
+ }
+ }
+
private void UpdatePolicyRules() {
diff --git a/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingPolicy.java b/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingPolicy.java
index 7645bad..1e9b357 100644
--- a/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingPolicy.java
+++ b/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingPolicy.java
@@ -197,8 +197,8 @@
/**
* Update the policy rules if necessary according to the topology changes
*/
- public void updatePolicy() {
-
+ public boolean updatePolicy() {
+ return false;
}
}
diff --git a/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingPolicyAvoid.java b/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingPolicyAvoid.java
index 835c770..2e3aeca 100644
--- a/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingPolicyAvoid.java
+++ b/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingPolicyAvoid.java
@@ -114,7 +114,7 @@
}
@Override
- public void updatePolicy() {
+ public boolean updatePolicy() {
Switch srcSwitch = srManager.getSwitch(srcDpid);
Switch dstSwitch = srManager.getSwitch(dstDpid);
ECMPShortestPathGraph graph = new ECMPShortestPathGraph(srcSwitch,
@@ -147,6 +147,8 @@
else {
log.debug("No need to update the policy {}, policyId");
}
+
+ return true;
}
private boolean checkIfIncluded(List<Integer> labelStack) {
diff --git a/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingPolicyTunnel.java b/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingPolicyTunnel.java
index e7e2026..b47617f 100644
--- a/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingPolicyTunnel.java
+++ b/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingPolicyTunnel.java
@@ -7,6 +7,7 @@
import net.floodlightcontroller.core.IOF13Switch.GroupChain;
import net.onrc.onos.core.matchaction.MatchAction;
import net.onrc.onos.core.matchaction.MatchActionOperationEntry;
+import net.onrc.onos.core.matchaction.MatchActionOperations;
import net.onrc.onos.core.matchaction.MatchActionOperations.Operator;
import net.onrc.onos.core.matchaction.action.Action;
import net.onrc.onos.core.matchaction.action.DecNwTtlAction;
@@ -52,7 +53,7 @@
if (isSetId) {
SegmentRoutingTunnelset tunnelset =
srManager.getTunnelsetInfo(tunnelId);
- populateAclRuleToTunnelset(tunnelset);
+ populateAclRuleToTunnelset(tunnelset, Operator.ADD);
}
else {
SegmentRoutingTunnel tunnelInfo = srManager.getTunnelInfo(tunnelId);
@@ -68,18 +69,40 @@
@Override
public boolean removePolicy() {
- SegmentRoutingTunnel tunnel = srManager.getTunnelInfo(tunnelId);
- if (tunnel == null) {
- log.warn("Cannot find the tunnel {} for the policy {}", tunnelId,
- policyId);
- return false;
- }
- List<TunnelRouteInfo> routes = tunnel.getRoutes();
- removeAclRules(routes);
+ if (isSetId) {
+ SegmentRoutingTunnelset tunnelset =
+ srManager.getTunnelsetInfo(tunnelId);
+ /* Remove flow rules pointing to tunnelset */
+ populateAclRuleToTunnelset(tunnelset, Operator.REMOVE);
+ }
+ else {
+ SegmentRoutingTunnel tunnel = srManager.getTunnelInfo(tunnelId);
+ if (tunnel == null) {
+ log.warn("Cannot find the tunnel {} for the policy {}", tunnelId,
+ policyId);
+ return false;
+ }
+ List<TunnelRouteInfo> routes = tunnel.getRoutes();
+ removeAclRules(routes);
+ }
return true;
}
+ @Override
+ public boolean updatePolicy() {
+ if (isSetId) {
+ /* Properties of tunnelset might have been changed.
+ * Update the policy pointing to it
+ */
+ SegmentRoutingTunnelset tunnelset =
+ srManager.getTunnelsetInfo(tunnelId);
+ populateAclRuleToTunnelset(tunnelset, Operator.ADD);
+ }
+ return true;
+
+ }
+
/**
* Get the Tunnel ID
* @return tunnel ID
@@ -96,7 +119,8 @@
this.isSetId = isSetId;
}
- protected void populateAclRuleToTunnelset(SegmentRoutingTunnelset tunnelset) {
+ private void populateAclRuleToTunnelset(SegmentRoutingTunnelset tunnelset,
+ MatchActionOperations.Operator operator) {
HashMap<String,List<GroupChain>> tunnelsetGroupChain =
tunnelset.getTunnelsetGroupChain();
for (String targetSwDpid: tunnelsetGroupChain.keySet()) {
@@ -106,12 +130,15 @@
get(targetSwDpid).get(0).getInnermostGroupId());
actions.add(groupAction);
+ log.warn("populateAclRuleToTunnelset to tunnelset {} "
+ + "in sw {} for the policy {}", tunnelId,
+ targetSwDpid, policyId);
MatchAction matchAction = new MatchAction(
srManager.getMatchActionId(),
new SwitchPort((new Dpid(targetSwDpid)).value(), (long)0), match, priority,
actions);
MatchActionOperationEntry maEntry =
- new MatchActionOperationEntry(Operator.ADD, matchAction);
+ new MatchActionOperationEntry(operator, matchAction);
srManager.executeMatchActionOpEntry(maEntry);
}
diff --git a/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingTunnelset.java b/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingTunnelset.java
index 8848714..d3e5a88 100644
--- a/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingTunnelset.java
+++ b/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingTunnelset.java
@@ -88,6 +88,189 @@
return true;
}
+
+ public HashMap<String,SegmentRoutingTunnel> addNewTunnelsToTunnelset(
+ SegmentRouterTunnelsetRESTParams tunnelsetParams) {
+
+ HashMap<String,SegmentRoutingTunnel> newTunnelMap = null;
+
+ for (SegmentRouterTunnelRESTParams tunnelParams:tunnelsetParams.getTunnelParams()) {
+ SegmentRoutingTunnel tunnel = new
+ SegmentRoutingTunnel(srManager, tunnelParams.getTunnel_id(),
+ tunnelParams.getLabel_path(), tunnelsetId);
+ tunnel.computeTunnelLabelStack();
+
+
+ HashMap<String, GroupChainParams> tunnelGroupChainParams =
+ tunnel.getGroupChainParams();
+ for (String targetSwDpid: tunnelGroupChainParams.keySet()) {
+ IOF13Switch targetSw = srManager.getIOF13Switch(targetSwDpid);
+
+ if (targetSw == null) {
+ log.debug("Switch {} is gone.", targetSwDpid);
+ continue;
+ }
+
+ List<GroupChainParams> groupChainParamsList = new
+ ArrayList<IOF13Switch.GroupChainParams>();
+ groupChainParamsList.add(tunnelGroupChainParams.get(
+ targetSwDpid));
+ List<GroupChain> currentGroupChainList = tunnelsetGroupChain.get(targetSwDpid);
+ List<GroupChain> newGroupChainList = null;
+
+ if (currentGroupChainList == null) {
+ newGroupChainList = targetSw.
+ createGroupChain(groupChainParamsList);
+ }
+ else {
+ newGroupChainList = targetSw.addNewEntryToGroupChain(
+ currentGroupChainList,
+ groupChainParamsList);
+ }
+
+ if (newGroupChainList == null) {
+ log.warn("CreateGroupChain for Switch {} failed at driver", targetSwDpid);
+ continue;
+ }
+
+ for (GroupChain groupChain:newGroupChainList) {
+ HashMap<String,GroupChain> dpidGroupMap =
+ tunnelIdGroupChainMap.get(groupChain.getId());
+ if (dpidGroupMap == null)
+ {
+ dpidGroupMap = new HashMap<String, IOF13Switch.GroupChain>();
+ tunnelIdGroupChainMap.put(groupChain.getId(), dpidGroupMap);
+ }
+
+ dpidGroupMap.put(targetSwDpid, groupChain);
+ }
+ tunnelsetGroupChain.put(targetSwDpid, newGroupChainList);
+ }
+ tunnelMap.put(tunnelParams.getTunnel_id(), tunnel);
+ if (newTunnelMap == null)
+ newTunnelMap = new HashMap<String, SegmentRoutingTunnel>();
+ newTunnelMap.put(tunnelParams.getTunnel_id(), tunnel);
+ }
+ return newTunnelMap;
+ }
+
+ public boolean removeConstituentTunnelFromTunnelset(
+ SegmentRouterTunnelsetRESTParams tunnelsetParams) {
+ for (String tunnelId:tunnelsetParams.getRemove_tunnel_params()) {
+ HashMap<String, GroupChain> tunnelIdGroupChain =
+ tunnelIdGroupChainMap.get(tunnelId);
+ for (String targetSwDpid:tunnelIdGroupChain.keySet()) {
+ IOF13Switch sw13 = srManager.getIOF13Switch(targetSwDpid);
+ if (sw13 != null) {
+ GroupChain tunnelIdSwGroupChain = tunnelIdGroupChain.get(targetSwDpid);
+ List<Integer> groupsPointedByInnermostGroup = new ArrayList<Integer>();
+ for (PortNumber sp:tunnelIdSwGroupChain.getGroupChain().keySet()) {
+ List<Integer> portGroupList =
+ tunnelIdSwGroupChain.getGroupChain().get(sp);
+ /* Get the last group in the list.
+ * This will be pointed by innermost group
+ */
+ int groupId = portGroupList.get(portGroupList.size()-1);
+ groupsPointedByInnermostGroup.add(groupId);
+ }
+
+ if (groupsPointedByInnermostGroup.size() >0) {
+ if (!sw13.removeOutGroupBucketsFromGroup(
+ tunnelIdSwGroupChain.getInnermostGroupId(),
+ groupsPointedByInnermostGroup)) {
+ log.warn("Faied to remove outgroup buckets "
+ + "from group {} tunnelset {} at driver",
+ tunnelIdSwGroupChain.getInnermostGroupId(),
+ tunnelsetId);
+ return false;
+ }
+ for (List<Integer> groupList: tunnelIdSwGroupChain.getGroupChain().values()) {
+ for (int i = groupList.size()-1; i >= 0; i--) {
+ int groupId = groupList.get(i);
+ if (!sw13.removeGroup(groupId)) {
+ log.warn("Faied to remove the tunnelset {} at driver",
+ tunnelsetId);
+ return false;
+ }
+ }
+ }
+ }
+ else
+ {
+ /* No Group chain created for this tunnel in this switch
+ * Just remove the innermost group
+ */
+ if (!sw13.removeGroup(
+ tunnelIdSwGroupChain.getInnermostGroupId())) {
+ log.warn("Faied to remove innermost group "
+ + "{} of tunnelset {} at driver",
+ tunnelIdSwGroupChain.getInnermostGroupId(),
+ tunnelsetId);
+ return false;
+ }
+ }
+ List<GroupChain> swGroupChainList = tunnelsetGroupChain.get(targetSwDpid);
+ for (int idx=0;idx<swGroupChainList.size();idx++) {
+ if (swGroupChainList.get(idx).getId().equals(tunnelId)) {
+ swGroupChainList.remove(idx);
+ }
+ }
+ if (swGroupChainList.size()==0)
+ tunnelsetGroupChain.remove(targetSwDpid);
+ }
+ }
+ tunnelIdGroupChainMap.remove(tunnelId);
+ tunnelMap.remove(tunnelId);
+ }
+ return true;
+ }
+ /**
+ * Remove the tunnelset.
+ * It requests driver to remove all groups for the tunnelset
+ *
+ * @return true if succeeds, false otherwise.
+ */
+ public boolean removeTunnelset() {
+
+ for (String targetSwDpid:tunnelsetGroupChain.keySet()) {
+ IOF13Switch sw13 = srManager.getIOF13Switch(targetSwDpid);
+ if (sw13 != null) {
+ List<GroupChain> groupChainList = tunnelsetGroupChain.get(targetSwDpid);
+
+ if (groupChainList != null) {
+ // Innermost Group needs to be removed first because
+ // the group being pointed by any other group cannot be removed
+ int innermostGroupId = groupChainList.
+ get(0).getInnermostGroupId();
+ if (!sw13.removeGroup(innermostGroupId)) {
+ log.warn("Faied to remove the tunnelset {} at driver",
+ tunnelsetId);
+ return false;
+ }
+
+ for (GroupChain groupChain: groupChainList) {
+ HashMap<PortNumber,List<Integer>> portGroupChain =
+ groupChain.getGroupChain();
+ for (List<Integer> groupList: portGroupChain.values()) {
+ for (int i = groupList.size()-1; i >= 0; i--) {
+ int groupId = groupList.get(i);
+ if (!sw13.removeGroup(groupId)) {
+ log.warn("Faied to remove the tunnelset {} at driver",
+ tunnelsetId);
+ return false;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ tunnelsetGroupChain.clear();
+ tunnelIdGroupChainMap.clear();
+
+ return true;
+ }
public String getTunnelsetId() {
return this.tunnelsetId;
diff --git a/src/main/java/net/onrc/onos/apps/segmentrouting/web/SegmentRouterPolicyResource.java b/src/main/java/net/onrc/onos/apps/segmentrouting/web/SegmentRouterPolicyResource.java
index 2aab718..f038867 100644
--- a/src/main/java/net/onrc/onos/apps/segmentrouting/web/SegmentRouterPolicyResource.java
+++ b/src/main/java/net/onrc/onos/apps/segmentrouting/web/SegmentRouterPolicyResource.java
@@ -48,12 +48,15 @@
return "fail";
}
- String tunnelId = createParams.getTunnel_id();
+ String tunnelId = null;
boolean isTunnelsetId = false;
- if (createParams.getTunnelset_id() != null) {
+ if (createParams.getPolicy_type().equals("loadbalance")) {
tunnelId = createParams.getTunnelset_id();
isTunnelsetId = true;
}
+ else if (createParams.getPolicy_type().equals("tunnel-flow")) {
+ tunnelId = createParams.getTunnel_id();
+ }
log.debug("createPolicy of type {} with params id {} src_ip {} dst_ip {}"
+ "proto {} src_port {} dst_port {} priority {} tunnel_id {} isSet {}",
@@ -127,9 +130,14 @@
SegmentRoutingPolicy policy = piI.next();
String policyId = policy.getPolicyId();
String tunnelId = null;
+ boolean isTunnelset = false;
if (policy.getType() == PolicyType.TUNNEL_FLOW) {
tunnelId = ((SegmentRoutingPolicyTunnel)policy).getTunnelId();
}
+ else if (policy.getType() == PolicyType.LOADBALANCE) {
+ tunnelId = ((SegmentRoutingPolicyTunnel)policy).getTunnelId();
+ isTunnelset = true;
+ }
int priority = policy.getPriority();
String policyType = policy.getType().name();
PacketMatch flowEntries = policy.getMatch();
diff --git a/src/main/java/net/onrc/onos/apps/segmentrouting/web/SegmentRouterTunnelsetRESTParams.java b/src/main/java/net/onrc/onos/apps/segmentrouting/web/SegmentRouterTunnelsetRESTParams.java
index 6faf4e7..639ea82 100644
--- a/src/main/java/net/onrc/onos/apps/segmentrouting/web/SegmentRouterTunnelsetRESTParams.java
+++ b/src/main/java/net/onrc/onos/apps/segmentrouting/web/SegmentRouterTunnelsetRESTParams.java
@@ -12,6 +12,7 @@
//@JsonDeserialize(contentUsing = SegmentRouterTunnelRESTParams.class)
private List<SegmentRouterTunnelRESTParams> tunnel_params =
new ArrayList<SegmentRouterTunnelRESTParams>();
+ private List<String> remove_tunnel_params = new ArrayList<String>();
public SegmentRouterTunnelsetRESTParams() {
//this.tunnelset_id = null;
@@ -31,6 +32,14 @@
}
public List<SegmentRouterTunnelRESTParams> getTunnelParams() {
- return this.tunnel_params;
+ return (this.tunnel_params.size() > 0)?this.tunnel_params:null;
}
+
+ public List<String> getRemove_tunnel_params() {
+ return (remove_tunnel_params.size()>0)?remove_tunnel_params:null;
+ }
+
+ public void setRemove_tunnel_params(List<String> remove_tunnel_params) {
+ this.remove_tunnel_params = remove_tunnel_params;
+ }
}
diff --git a/src/main/java/net/onrc/onos/apps/segmentrouting/web/SegmentRouterTunnelsetResource.java b/src/main/java/net/onrc/onos/apps/segmentrouting/web/SegmentRouterTunnelsetResource.java
index 46e6126..ad9dfda 100644
--- a/src/main/java/net/onrc/onos/apps/segmentrouting/web/SegmentRouterTunnelsetResource.java
+++ b/src/main/java/net/onrc/onos/apps/segmentrouting/web/SegmentRouterTunnelsetResource.java
@@ -49,34 +49,34 @@
return "fail";
}
log.debug("createTunnelset with tunnelsetId {} tunnel params{}",
- createParams.getTunnelset_id(), createParams.getTunnelParams().get(0));
+ createParams.getTunnelset_id(), createParams);
boolean result = true;
- result = segmentRoutingService.createTunnelset(createParams.getTunnelset_id(),
+ result = segmentRoutingService.createUpdateTunnelset(createParams.getTunnelset_id(),
createParams);
return (result == true) ? "success" : "fail";
}
-/*
+
@Delete("json")
- public String deleteTunnel(String tunnelParams) {
+ public String deleteTunnelset(String tunnelsetParams) {
ISegmentRoutingService segmentRoutingService =
(ISegmentRoutingService) getContext().getAttributes().
get(ISegmentRoutingService.class.getCanonicalName());
ObjectMapper mapper = new ObjectMapper();
- SegmentRouterTunnelRESTParams createParams = null;
+ SegmentRouterTunnelsetRESTParams createParams = null;
try {
- if (tunnelParams != null) {
- createParams = mapper.readValue(tunnelParams,
- SegmentRouterTunnelRESTParams.class);
+ if (tunnelsetParams != null) {
+ createParams = mapper.readValue(tunnelsetParams,
+ SegmentRouterTunnelsetRESTParams.class);
}
} catch (IOException ex) {
log.error("Exception occurred parsing inbound JSON", ex);
return "fail";
}
- log.debug("deleteTunnel with Id {}", createParams.getTunnel_id());
- removeTunnelMessages result = segmentRoutingService.removeTunnel(
- createParams.getTunnel_id());
+ log.debug("deleteTunnelset with Id {}", createParams.getTunnelset_id());
+ removeTunnelMessages result = segmentRoutingService.removeTunnelset(
+ createParams.getTunnelset_id());
return result.name()+" "+result.toString();
- }*/
+ }
@Get("json")
public Object getTunnelset() {
@@ -97,7 +97,7 @@
String policiesId = "";
while(piI.hasNext()){
SegmentRoutingPolicy policy = piI.next();
- if(policy.getType() == PolicyType.TUNNEL_FLOW &&
+ if(policy.getType() == PolicyType.LOADBALANCE &&
(((SegmentRoutingPolicyTunnel)policy).isTunnelsetId() &&
((SegmentRoutingPolicyTunnel)policy).getTunnelId().equals(tunnelsetId))){
policiesId += (policy.getPolicyId()+",");
diff --git a/src/main/java/net/onrc/onos/core/drivermanager/OFSwitchImplSpringOpenTTP.java b/src/main/java/net/onrc/onos/core/drivermanager/OFSwitchImplSpringOpenTTP.java
index d45a13b..b11ac27 100644
--- a/src/main/java/net/onrc/onos/core/drivermanager/OFSwitchImplSpringOpenTTP.java
+++ b/src/main/java/net/onrc/onos/core/drivermanager/OFSwitchImplSpringOpenTTP.java
@@ -2263,13 +2263,140 @@
groupChain.setInnermostGroupId(innermostGroupId);
}
log.debug(
- "createInnermostLabelGroup: Creating select group {} in sw {} "
+ "createGroupChain: Creating select group {} in sw {} "
+ "with: {}", innermostGroupId, getStringId(), ecmpInfo);
}
return groupChains;
}
+ public List<GroupChain> addNewEntryToGroupChain(List<GroupChain> currentGroupChainList,
+ List<GroupChainParams> groupChainParams) {
+
+ int innermostGroupId = currentGroupChainList.get(0).getInnermostGroupId();
+ EcmpInfo innermostGroupInfo = userDefinedGroups.get(innermostGroupId);
+
+ if (innermostGroupInfo == null) {
+ log.warn("addNewEntryToGroupChain in sw {} with wrong "
+ + "input parameters", getStringId());
+ return null;
+ }
+
+ List<BucketInfo> buckets = innermostGroupInfo.buckets;
+ List<GroupChain> newGroupChainList = new ArrayList<IOF13Switch.GroupChain>();
+ boolean groupUpdated = false;
+ for (GroupChainParams i: groupChainParams) {
+ List<PortNumber> ports = i.getPorts();
+ if (ports == null) {
+ log.warn("createGroupChain in sw {} with wrong "
+ + "input parameters", getStringId());
+ return null;
+ }
+
+ List<PortNumber> activePorts = new ArrayList<PortNumber>();
+ for (PortNumber port : ports) {
+ if (portEnabled((int) port.value()))
+ activePorts.add(port);
+ }
+ if (activePorts.isEmpty()) {
+ log.warn("addNewEntryToGroupChain in sw {} with no "
+ + "active ports for groupChainParams id {}",
+ getStringId(), i.getId());
+ continue;
+ }
+
+ int labelStackSize = (i.getLabelStack() != null) ?
+ i.getLabelStack().size() : 0;
+ GroupChain groupChain = new GroupChain(i.getId());
+ newGroupChainList.add(groupChain);
+
+ if (labelStackSize > 0) {
+ for (PortNumber sp : activePorts) {
+ int previousGroupId = -1;
+ for (int idx=0; idx < i.getLabelStack().size(); idx++) {
+ if (idx == (labelStackSize - 1)) {
+ int label = i.getLabelStack().get(idx).intValue();
+ Dpid neighborDpid = portToNeighbors.get(sp);
+ BucketInfo b = new BucketInfo(neighborDpid,
+ MacAddress.of(srConfig.getRouterMac()),
+ getNeighborRouterMacAddress(neighborDpid),
+ sp, label, true, previousGroupId);
+ buckets.add(b);
+ groupUpdated = true;
+ }
+ else {
+ int currGroupId = getNextFreeGroupId();
+ EcmpInfo indirectGroup = createIndirectGroup(currGroupId,
+ null, null, sp, previousGroupId,
+ i.getLabelStack().get(idx).intValue(), false);
+ previousGroupId = currGroupId;
+ userDefinedGroups.put(currGroupId, indirectGroup);
+ groupChain.addGroupToChain(sp, currGroupId);
+ }
+ }
+ }
+ }
+ else
+ {
+ for (PortNumber sp : activePorts) {
+ Dpid neighborDpid = portToNeighbors.get(sp);
+ BucketInfo b = new BucketInfo(neighborDpid,
+ MacAddress.of(srConfig.getRouterMac()),
+ getNeighborRouterMacAddress(neighborDpid),
+ sp, -1, false, -1);
+ buckets.add(b);
+ groupUpdated = true;
+ }
+ }
+ }
+
+ if (groupUpdated) {
+ modifyEcmpGroup(innermostGroupInfo);
+ for (GroupChain groupChain:newGroupChainList) {
+ groupChain.setInnermostGroupId(innermostGroupId);
+ currentGroupChainList.add(groupChain);
+ }
+ log.debug(
+ "addNewEntryToGroupChain: Updating select group {} in sw {} "
+ + "with: {}", innermostGroupId, getStringId(), innermostGroupInfo);
+ return currentGroupChainList;
+ }
+
+ return null;
+
+ }
+
+ public boolean removeOutGroupBucketsFromGroup(
+ int innermostGroupId, List<Integer> chainedGroups) {
+ EcmpInfo innermostGroupInfo = userDefinedGroups.get(innermostGroupId);
+ if (innermostGroupInfo == null) {
+ log.warn("removeOutGroupBucketsFromGroup in sw {}: "
+ + "with invalid group id", getStringId());
+ return false;
+ }
+
+ Iterator<BucketInfo> it = innermostGroupInfo.buckets.iterator();
+ log.debug("removeOutGroupBucketsFromGroup: Group {} on Switch {} has {} buckets",
+ innermostGroupId, getStringId(),
+ innermostGroupInfo.buckets.size());
+ boolean groupUpdated = false;
+ while (it.hasNext()) {
+ BucketInfo bucket = it.next();
+ if (chainedGroups.contains(bucket.togroupNo)) {
+ it.remove();
+ groupUpdated = true;
+ }
+ }
+ if (groupUpdated) {
+ log.debug("removeOutGroupBucketsFromGroup: Modifying Group "
+ + "on Switch {} with {}",
+ getStringId(), innermostGroupInfo);
+ modifyEcmpGroup(innermostGroupInfo);
+ return true;
+ }
+ return false;
+ }
+
/**
* Remove the specified group
*