Route reprogamming using group substitution during next hop movement
Change-Id: Idf8362dac522722ca67747e245bfd836e6ee6292
diff --git a/app/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java b/app/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java
index 02f2b19..669e136 100644
--- a/app/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java
+++ b/app/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java
@@ -44,9 +44,11 @@
import org.onosproject.segmentrouting.SegmentRoutingManager;
import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
import org.onosproject.segmentrouting.config.DeviceProperties;
+import org.onosproject.segmentrouting.config.DeviceConfiguration;
import org.onosproject.segmentrouting.storekey.DestinationSetNextObjectiveStoreKey;
import org.onosproject.segmentrouting.storekey.PortNextObjectiveStoreKey;
import org.onosproject.segmentrouting.storekey.VlanNextObjectiveStoreKey;
+import org.onosproject.segmentrouting.storekey.MacVlanNextObjectiveStoreKey;
import org.onosproject.store.service.EventuallyConsistentMap;
import org.slf4j.Logger;
@@ -88,6 +90,8 @@
protected MacAddress nodeMacAddr = null;
protected LinkService linkService;
protected FlowObjectiveService flowObjectiveService;
+ private DeviceConfiguration config;
+
/**
* local store for neighbor-device-ids and the set of ports on this device
* that connect to the same neighbor.
@@ -106,6 +110,9 @@
// distributed store for (device+subnet-ip-prefix) mapped to next-id
protected EventuallyConsistentMap<VlanNextObjectiveStoreKey, Integer>
vlanNextObjStore = null;
+ // distributed store for (device+mac+vlan+treatment) mapped to next-id
+ protected EventuallyConsistentMap<MacVlanNextObjectiveStoreKey, Integer>
+ macVlanNextObjStore = null;
// distributed store for (device+port+treatment) mapped to next-id
protected EventuallyConsistentMap<PortNextObjectiveStoreKey, Integer>
portNextObjStore = null;
@@ -145,6 +152,7 @@
this.dsNextObjStore = srManager.dsNextObjStore();
this.vlanNextObjStore = srManager.vlanNextObjStore();
this.portNextObjStore = srManager.portNextObjStore();
+ this.macVlanNextObjStore = srManager.macVlanNextObjStore();
this.srManager = srManager;
executorService.scheduleWithFixedDelay(new BucketCorrector(), 10,
VERIFY_INTERVAL,
@@ -816,6 +824,52 @@
}
/**
+ * Returns the next objective of type simple associated with the mac/vlan on the
+ * device, given the treatment. Different treatments to the same mac/vlan result
+ * in different next objectives. If no such objective exists, this method
+ * creates one (if requested) and returns the id. Optionally metadata can be passed in for
+ * the creation of the objective. Typically this is used for L2 and L3 forwarding
+ * to compute nodes and containers/VMs on the compute nodes directly attached
+ * to the switch.
+ *
+ * @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 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) {
+
+ Integer nextId = macVlanNextObjStore
+ .get(new MacVlanNextObjectiveStoreKey(deviceId, macAddr, vlanId));
+
+ if (nextId != null) {
+ return nextId;
+ }
+
+ log.debug("getMacVlanNextObjectiveId in device {}: Next objective id "
+ + "not found for host : {}/{} .. {}", deviceId, macAddr, vlanId,
+ (createIfMissing) ? "creating" : "aborting");
+
+ if (!createIfMissing) {
+ return -1;
+ }
+
+ /* create missing next objective */
+ nextId = createGroupFromMacVlan(macAddr, vlanId, treatment, meta);
+ if (nextId == null) {
+ log.warn("getMacVlanNextObjectiveId: unable to create next obj"
+ + "for dev:{} host:{}/{}", deviceId, macAddr, vlanId);
+ return -1;
+ }
+ return nextId;
+ }
+
+
+ /**
* Returns the next objective of type simple associated with the port on the
* device, given the treatment. Different treatments to the same port result
* in different next objectives. If no such objective exists, this method
@@ -1177,6 +1231,45 @@
}
/**
+ * Create simple next objective for an indirect host mac/vlan. The treatments can include
+ * all outgoing actions that need to happen on the packet.
+ *
+ * @param macAddr the mac address of the host
+ * @param vlanId the vlan of the host
+ * @param treatment the actions to apply on the packets (should include outport)
+ * @param meta optional data to pass to the driver
+ * @return next objective ID
+ */
+ public int createGroupFromMacVlan(MacAddress macAddr, VlanId vlanId, TrafficTreatment treatment,
+ TrafficSelector meta) {
+ int nextId = flowObjectiveService.allocateNextId();
+ MacVlanNextObjectiveStoreKey key = new MacVlanNextObjectiveStoreKey(deviceId, macAddr, vlanId);
+
+ NextObjective.Builder nextObjBuilder = DefaultNextObjective
+ .builder().withId(nextId)
+ .withType(NextObjective.Type.SIMPLE)
+ .addTreatment(treatment)
+ .fromApp(appId)
+ .withMeta(meta);
+
+ ObjectiveContext context = new DefaultObjectiveContext(
+ (objective) ->
+ log.debug("createGroupFromMacVlan installed "
+ + "NextObj {} on {}", nextId, deviceId),
+ (objective, error) -> {
+ log.warn("createGroupFromMacVlan failed to install NextObj {} on {}: {}", nextId, deviceId, error);
+ srManager.invalidateNextObj(objective.id());
+ });
+ NextObjective nextObj = nextObjBuilder.add(context);
+ flowObjectiveService.next(deviceId, nextObj);
+ log.debug("createGroupFromMacVlan: Submited next objective {} in device {} "
+ + "for host {}/{}", nextId, deviceId, macAddr, vlanId);
+
+ macVlanNextObjStore.put(key, nextId);
+ return nextId;
+ }
+
+ /**
* Create simple next objective for a single port. The treatments can include
* all outgoing actions that need to happen on the packet.
*
@@ -1257,6 +1350,7 @@
portNextObjStore.remove(key);
}
}
+
/**
* Removes groups for the next objective ID given.
*
@@ -1402,6 +1496,94 @@
}
/**
+ * 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.
+ * @param hostVlanId vlan of host for which Next obj is to be updated.
+ * @param port port with which to update the Next Obj.
+ * @param nextId of Next Obj which needs to be updated.
+ */
+ public void updateL3UcastGroupBucket(MacAddress hostMac, VlanId hostVlanId, PortNumber port, int nextId) {
+
+ MacAddress deviceMac;
+ try {
+ deviceMac = deviceConfig.getDeviceMac(deviceId);
+ } catch (DeviceConfigNotFoundException e) {
+ log.warn(e.getMessage() + " in updateL3UcastGroupBucket");
+ return;
+ }
+
+ TrafficSelector metadata =
+ DefaultTrafficSelector.builder().matchVlanId(hostVlanId).build();
+
+ TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
+ tbuilder.deferred()
+ .setEthDst(hostMac)
+ .setEthSrc(deviceMac)
+ .setVlanId(hostVlanId)
+ .setOutput(port);
+
+ log.debug(" update L3Ucast : deviceMac {}, port {}, host {}/{}, nextid {}, Treatment {} Meta {}",
+ deviceMac, port, hostMac, hostVlanId, nextId, tbuilder.build(), metadata);
+
+ NextObjective.Builder nextObjBuilder = DefaultNextObjective
+ .builder().withId(nextId)
+ .withType(NextObjective.Type.SIMPLE).fromApp(appId)
+ .addTreatment(tbuilder.build())
+ .withMeta(metadata);
+
+ ObjectiveContext context = new DefaultObjectiveContext(
+ (objective) -> log.debug(" NextId {} successfully updated host {} vlan {} with port {}",
+ nextId, hostMac, hostVlanId, port),
+ (objective, error) -> {
+ log.warn(" NextId {} failed to update host {} vlan {} with port {}, error : {}",
+ nextId, hostMac, hostVlanId, port, error);
+ srManager.invalidateNextObj(objective.id());
+ });
+
+ NextObjective nextObj = nextObjBuilder.modify(context);
+ flowObjectiveService.next(deviceId, nextObj);
+
+ }
+
+ /**
* Adds a single port to the L2FG or removes it from the L2FG.
*
* @param vlanId the vlan id corresponding to this port