Optimized group updating during host move
In addition,
- Added a fix for host remove issue
- Added a fix for single homed (loc1) to dual homed (loc2).
Change-Id: I1a7344bd77f73d6bed8955dcdbf407b5354d0eee
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/HostHandler.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/HostHandler.java
index 296fbcd..14df622 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/HostHandler.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/HostHandler.java
@@ -129,6 +129,15 @@
});
}
});
+
+ int nextId = srManager.getMacVlanNextObjectiveId(location.deviceId(), hostMac, hostVlanId, null, false);
+ if (nextId != -1) {
+ VlanId vlanId = Optional.ofNullable(srManager.getInternalVlanId(location)).orElse(hostVlanId);
+ log.debug(" Updating next objective for device {}, host {}/{}, port {}, nextid {}",
+ location.deviceId(), hostMac, vlanId, location.port(), nextId);
+ srManager.updateMacVlanTreatment(location.deviceId(), hostMac, vlanId,
+ location.port(), nextId);
+ }
}
void processHostRemovedEvent(HostEvent event) {
@@ -181,6 +190,7 @@
}
});
});
+
});
}
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/RouteHandler.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/RouteHandler.java
index b99f33f..cc03597 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/RouteHandler.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/RouteHandler.java
@@ -32,9 +32,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import java.util.Collection;
import java.util.Objects;
import java.util.Optional;
@@ -234,37 +232,51 @@
log.info("processHostMovedEvent {}", event);
MacAddress hostMac = event.subject().mac();
VlanId hostVlanId = event.subject().vlan();
- // map of nextId for prev port in each device
- Map<DeviceId, Integer> nextIdMap = new HashMap<>();
+
Set<HostLocation> prevLocations = event.prevSubject().locations();
Set<HostLocation> newLocations = event.subject().locations();
- Set<ConnectPoint> connectPoints = newLocations.stream().map(l -> (ConnectPoint) l).collect(Collectors.toSet());
+ Set<ConnectPoint> connectPoints = newLocations.stream()
+ .map(l -> (ConnectPoint) l).collect(Collectors.toSet());
List<Set<IpPrefix>> batchedSubnets =
srManager.deviceConfiguration.getBatchedSubnets(event.subject().id());
+ Set<DeviceId> newDeviceIds = newLocations.stream().map(HostLocation::deviceId)
+ .collect(Collectors.toSet());
+
+ // Set of deviceIDs of the previous locations where the host was connected
+ // Used to determine if host moved to different connect points
+ // on same device or moved to a different device altogether
+ Set<DeviceId> oldDeviceIds = prevLocations.stream().map(HostLocation::deviceId)
+ .collect(Collectors.toSet());
+
+ // L3 Ucast bucket needs to be updated only once per host
+ // and only when the no. of routes with the host as next-hop is not zero
+ if (!batchedSubnets.isEmpty()) {
+ // For each new location, if NextObj exists for the host, update with new location ..
+ Sets.difference(newLocations, prevLocations).forEach(newLocation -> {
+ int nextId = srManager.getMacVlanNextObjectiveId(newLocation.deviceId(),
+ hostMac, hostVlanId, null, false);
+ VlanId vlanId = Optional.ofNullable(srManager.getInternalVlanId(newLocation)).orElse(hostVlanId);
+
+ if (nextId != -1) {
+ //Update the nextId group bucket
+ log.debug("HostMoved. NextId exists, update L3 Ucast Group Bucket {}, {}, {} --> {}",
+ newLocation, hostMac, vlanId, nextId);
+ srManager.updateMacVlanTreatment(newLocation.deviceId(), hostMac, vlanId,
+ newLocation.port(), nextId);
+ } else {
+ log.debug("HostMoved. NextId does not exist for this location {}, host {}/{}",
+ newLocation, hostMac, vlanId);
+ }
+ });
+ }
batchedSubnets.forEach(subnets -> {
log.debug("HostMoved. populateSubnet {}, {}", newLocations, subnets);
srManager.defaultRoutingHandler.populateSubnet(connectPoints, subnets);
subnets.forEach(prefix -> {
- Set<DeviceId> newDeviceIds = newLocations.stream().map(HostLocation::deviceId)
- .collect(Collectors.toSet());
-
- // Set of deviceIDs of the previous locations where the host was connected
- // Used to determine if host moved to different connect points
- // on same device or moved to a different device altogether
- Set<DeviceId> oldDeviceIds = prevLocations.stream().map(HostLocation::deviceId)
- .collect(Collectors.toSet());
-
// For each old location
Sets.difference(prevLocations, newLocations).forEach(prevLocation -> {
- //find next Id for each old port, add to map
- int nextId = srManager.getNextIdForHostPort(prevLocation.deviceId(), hostMac,
- hostVlanId, prevLocation.port());
- log.debug("HostMoved. NextId For Host {}, {}, {}, {} {}", prevLocation, prefix,
- hostMac, hostVlanId, nextId);
-
- nextIdMap.put(prevLocation.deviceId(), nextId);
// Remove flows for unchanged IPs only when the host moves from a switch to another.
// Otherwise, do not remove and let the adding part update the old flow
@@ -297,18 +309,11 @@
log.debug("HostMoved. populateRoute {}, {}, {}, {}", newLocation, prefix, hostMac, hostVlanId);
srManager.defaultRoutingHandler.populateRoute(newLocation.deviceId(), prefix,
hostMac, hostVlanId, newLocation.port(), false);
- } else {
- // update same flow to point to new nextObj
- VlanId vlanId = Optional.ofNullable(srManager.getInternalVlanId(newLocation)).orElse(hostVlanId);
- //use nextIdMap to send new port details to update the nextId group bucket
- log.debug("HostMoved. update L3 Ucast Group Bucket {}, {}, {} --> {}",
- newLocation, hostMac, vlanId, nextIdMap.get(newLocation.deviceId()));
- srManager.updateMacVlanTreatment(newLocation.deviceId(), hostMac, vlanId,
- newLocation.port(), nextIdMap.get(newLocation.deviceId()));
}
});
});
});
+
}
private boolean isReady() {
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
index b864a08..3631e15 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
@@ -453,7 +453,7 @@
// if the objective is to revoke an existing rule, and for some reason
// the next-objective does not exist, then a new one should not be created
nextObjId = srManager.getMacVlanNextObjectiveId(deviceId, hostMac, hostVlanId,
- tbuilder.build(), mbuilder.build(), !revoke);
+ outPort, !revoke);
}
if (nextObjId == -1) {
// Warning log will come from getMacVlanNextObjective method
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
index 7319e56..c8c88c7 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
@@ -1308,18 +1308,15 @@
* @param deviceId Device ID
* @param macAddr mac of host for which Next ID is required.
* @param vlanId vlan of host for which Next ID is required.
- * @param treatment the actions to apply on the packets (should include outport)
- * @param meta metadata passed into the creation of a Next Objective if necessary
+ * @param port port with which to create the Next Obj.
* @param createIfMissing true if a next object should be created if not found
* @return next objective ID or -1 if an error occurred during retrieval or creation
*/
public int getMacVlanNextObjectiveId(DeviceId deviceId, MacAddress macAddr, VlanId vlanId,
- TrafficTreatment treatment,
- TrafficSelector meta,
- boolean createIfMissing) {
+ PortNumber port, boolean createIfMissing) {
DefaultGroupHandler ghdlr = groupHandlerMap.get(deviceId);
if (ghdlr != null) {
- return ghdlr.getMacVlanNextObjectiveId(macAddr, vlanId, treatment, meta, createIfMissing);
+ return ghdlr.getMacVlanNextObjectiveId(macAddr, vlanId, port, createIfMissing);
} else {
log.warn("getMacVlanNextObjectiveId query - groupHandler for device {}"
+ " not found", deviceId);
@@ -1328,27 +1325,6 @@
}
/**
- * Returns the next ID for the given host port from the store.
- *
- * @param deviceId Device ID
- * @param hostMac mac of host for which Next ID is required.
- * @param hostVlanId vlan of host for which Next ID is required.
- * @param port port of device for which next ID is required.
- * @return next objective ID or -1 if an error occurred during retrieval
- */
- public int getNextIdForHostPort(DeviceId deviceId, MacAddress hostMac,
- VlanId hostVlanId, PortNumber port) {
- DefaultGroupHandler ghdlr = groupHandlerMap.get(deviceId);
- if (ghdlr != null) {
- return ghdlr.getNextIdForHostPort(hostMac, hostVlanId, port);
- } else {
- log.warn("getNextIdForHostPort query - groupHandler for device {}"
- + " not found", deviceId);
- return -1;
- }
- }
-
- /**
* Updates the next objective for the given nextId .
*
* @param deviceId Device ID
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java
index 669e136..3431eb6 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java
@@ -834,14 +834,13 @@
*
* @param macAddr the mac addr for the simple next objective
* @param vlanId the vlan for the simple next objective
- * @param treatment the actions to apply on the packets (should include outport)
- * @param meta optional metadata passed into the creation of the next objective
+ * @param port port with which to create the Next Obj.
* @param createIfMissing true if a next object should be created if not found
* @return int if found or created, -1 if there are errors during the
* creation of the next objective.
*/
- public int getMacVlanNextObjectiveId(MacAddress macAddr, VlanId vlanId, TrafficTreatment treatment,
- TrafficSelector meta, boolean createIfMissing) {
+ public int getMacVlanNextObjectiveId(MacAddress macAddr, VlanId vlanId, PortNumber port,
+ boolean createIfMissing) {
Integer nextId = macVlanNextObjStore
.get(new MacVlanNextObjectiveStoreKey(deviceId, macAddr, vlanId));
@@ -858,8 +857,55 @@
return -1;
}
+ MacAddress deviceMac;
+ try {
+ deviceMac = deviceConfig.getDeviceMac(deviceId);
+ } catch (DeviceConfigNotFoundException e) {
+ log.warn(e.getMessage() + " in getMacVlanNextObjectiveId");
+ return -1;
+ }
+
+ // since we are creating now, port cannot be null
+ if (port == null) {
+ log.debug("getMacVlanNextObjectiveId : port information cannot be null "
+ + "for device {}, host {}/{}", deviceId, macAddr, vlanId);
+ return -1;
+ }
+
+ TrafficSelector.Builder meta = DefaultTrafficSelector.builder();
+
+ TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+ treatment.deferred()
+ .setEthDst(macAddr)
+ .setEthSrc(deviceMac)
+ .setOutput(port);
+
+ ConnectPoint connectPoint = new ConnectPoint(deviceId, port);
+ VlanId untaggedVlan = srManager.interfaceService.getUntaggedVlanId(connectPoint);
+ Set<VlanId> taggedVlans = srManager.interfaceService.getTaggedVlanId(connectPoint);
+ VlanId nativeVlan = srManager.interfaceService.getNativeVlanId(connectPoint);
+
+ // Adjust the meta according to VLAN configuration
+ if (taggedVlans.contains(vlanId)) {
+ treatment.setVlanId(vlanId);
+ } else if (vlanId.equals(VlanId.NONE)) {
+ if (untaggedVlan != null) {
+ meta.matchVlanId(untaggedVlan);
+ } else if (nativeVlan != null) {
+ meta.matchVlanId(nativeVlan);
+ } else {
+ log.warn("Untagged nexthop {}/{} is not allowed on {} without untagged or native vlan",
+ macAddr, vlanId, connectPoint);
+ return -1;
+ }
+ } else {
+ log.warn("Tagged nexthop {}/{} is not allowed on {} without VLAN listed"
+ + " in tagged vlan", macAddr, vlanId, connectPoint);
+ return -1;
+ }
+
/* create missing next objective */
- nextId = createGroupFromMacVlan(macAddr, vlanId, treatment, meta);
+ nextId = createGroupFromMacVlan(macAddr, vlanId, treatment.build(), meta.build());
if (nextId == null) {
log.warn("getMacVlanNextObjectiveId: unable to create next obj"
+ "for dev:{} host:{}/{}", deviceId, macAddr, vlanId);
@@ -1496,43 +1542,6 @@
}
/**
- * Returns the next ID for the given host port from the store.
- *
- * @param hostMac mac of host for which Next ID is required.
- * @param hostVlanId vlan of host for which Next ID is required.
- * @param port port of device for which next ID is required.
- * @return next objective ID or -1 if an error occurred during retrieval
- */
- public int getNextIdForHostPort(MacAddress hostMac, VlanId hostVlanId, PortNumber port) {
-
- MacAddress deviceMac;
- try {
- deviceMac = deviceConfig.getDeviceMac(deviceId);
- } catch (DeviceConfigNotFoundException e) {
- log.warn(e.getMessage() + " in getNextIdForHostPort");
- return -1;
- }
-
- TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
- tbuilder.deferred()
- .setEthDst(hostMac)
- .setEthSrc(deviceMac)
- .setVlanId(hostVlanId)
- .setOutput(port);
-
- TrafficSelector metadata =
- DefaultTrafficSelector.builder().matchVlanId(hostVlanId).build();
-
- int nextId = getMacVlanNextObjectiveId(hostMac, hostVlanId,
- tbuilder.build(), metadata, true);
-
- log.debug("getNextId : hostMac {}, deviceMac {}, port {}, hostVlanId {} Treatment {} Meta {} nextId {} ",
- hostMac, deviceMac, port, hostVlanId, tbuilder.build(), metadata, nextId);
-
- return nextId;
- }
-
- /**
* Updates the next objective for the given nextId .
*
* @param hostMac mac of host for which Next obj is to be updated.