blob: a4b89c182f52f79eebf8394bb70cca5de62f900a [file] [log] [blame]
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -08001/*
2 * Copyright 2015 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070016package org.onosproject.segmentrouting.grouphandler;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080017
18import static com.google.common.base.Preconditions.checkNotNull;
19import static org.slf4j.LoggerFactory.getLogger;
20
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -070021import java.net.URI;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080022import java.util.ArrayList;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070023import java.util.Collections;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080024import java.util.HashSet;
25import java.util.List;
sangho1e575652015-05-14 00:39:53 -070026import java.util.Map;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080027import java.util.Set;
Saurav Das8a0732e2015-11-20 15:27:53 -080028import java.util.concurrent.ConcurrentHashMap;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070029import java.util.stream.Collectors;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080030
Charles Chanc42e84e2015-10-20 16:24:19 -070031import org.onlab.packet.Ip4Prefix;
32import org.onlab.packet.IpPrefix;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080033import org.onlab.packet.MacAddress;
sangho32a59322015-02-17 12:07:41 -080034import org.onlab.packet.MplsLabel;
Saurav Das423fe2b2015-12-04 10:52:59 -080035import org.onlab.packet.VlanId;
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -070036import org.onlab.util.KryoNamespace;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080037import org.onosproject.core.ApplicationId;
38import org.onosproject.net.DeviceId;
39import org.onosproject.net.Link;
40import org.onosproject.net.PortNumber;
Saurav Das423fe2b2015-12-04 10:52:59 -080041import org.onosproject.net.flow.DefaultTrafficSelector;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080042import org.onosproject.net.flow.DefaultTrafficTreatment;
Saurav Das8a0732e2015-11-20 15:27:53 -080043import org.onosproject.net.flow.TrafficSelector;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080044import org.onosproject.net.flow.TrafficTreatment;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070045import org.onosproject.net.flowobjective.DefaultNextObjective;
46import org.onosproject.net.flowobjective.FlowObjectiveService;
47import org.onosproject.net.flowobjective.NextObjective;
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -070048import org.onosproject.net.flowobjective.Objective;
49import org.onosproject.net.flowobjective.ObjectiveContext;
50import org.onosproject.net.flowobjective.ObjectiveError;
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -070051import org.onosproject.net.group.DefaultGroupKey;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080052import org.onosproject.net.group.GroupKey;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080053import org.onosproject.net.link.LinkService;
Saurav Das423fe2b2015-12-04 10:52:59 -080054import org.onosproject.segmentrouting.SegmentRoutingManager;
Charles Chan0b4e6182015-11-03 10:42:14 -080055import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
56import org.onosproject.segmentrouting.config.DeviceProperties;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070057import org.onosproject.store.service.EventuallyConsistentMap;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080058import org.slf4j.Logger;
59
60/**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070061 * Default ECMP group handler creation module. This component creates a set of
62 * ECMP groups for every neighbor that this device is connected to based on
63 * whether the current device is an edge device or a transit device.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080064 */
65public class DefaultGroupHandler {
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -070066 protected static final Logger log = getLogger(DefaultGroupHandler.class);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080067
68 protected final DeviceId deviceId;
69 protected final ApplicationId appId;
70 protected final DeviceProperties deviceConfig;
71 protected final List<Integer> allSegmentIds;
Charles Chan0b4e6182015-11-03 10:42:14 -080072 protected int nodeSegmentId = -1;
73 protected boolean isEdgeRouter = false;
74 protected MacAddress nodeMacAddr = null;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080075 protected LinkService linkService;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070076 protected FlowObjectiveService flowObjectiveService;
Saurav Das423fe2b2015-12-04 10:52:59 -080077 // local store for neighbor-device-ids and the set of ports on this device
78 // that connect to the same neighbor
Saurav Das8a0732e2015-11-20 15:27:53 -080079 protected ConcurrentHashMap<DeviceId, Set<PortNumber>> devicePortMap =
80 new ConcurrentHashMap<>();
Saurav Das423fe2b2015-12-04 10:52:59 -080081 //local store for ports on this device connected to neighbor-device-id
Saurav Das8a0732e2015-11-20 15:27:53 -080082 protected ConcurrentHashMap<PortNumber, DeviceId> portDeviceMap =
83 new ConcurrentHashMap<>();
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070084 protected EventuallyConsistentMap<
85 NeighborSetNextObjectiveStoreKey, Integer> nsNextObjStore = null;
Charles Chanc42e84e2015-10-20 16:24:19 -070086 protected EventuallyConsistentMap<
87 SubnetNextObjectiveStoreKey, Integer> subnetNextObjStore = null;
Saurav Das4ce45962015-11-24 23:21:05 -080088 protected EventuallyConsistentMap<
89 PortNextObjectiveStoreKey, Integer> portNextObjStore = null;
Charles Chan188ebf52015-12-23 00:15:11 -080090 private SegmentRoutingManager srManager;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080091
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -070092 protected KryoNamespace.Builder kryo = new KryoNamespace.Builder()
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070093 .register(URI.class).register(HashSet.class)
94 .register(DeviceId.class).register(PortNumber.class)
95 .register(NeighborSet.class).register(PolicyGroupIdentifier.class)
96 .register(PolicyGroupParams.class)
97 .register(GroupBucketIdentifier.class)
98 .register(GroupBucketIdentifier.BucketOutputType.class);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080099
Charles Chan188ebf52015-12-23 00:15:11 -0800100 // TODO Access stores through srManager
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700101 protected DefaultGroupHandler(DeviceId deviceId, ApplicationId appId,
102 DeviceProperties config,
103 LinkService linkService,
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700104 FlowObjectiveService flowObjService,
Saurav Das4ce45962015-11-24 23:21:05 -0800105 EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey,
Charles Chanc42e84e2015-10-20 16:24:19 -0700106 Integer> nsNextObjStore,
107 EventuallyConsistentMap<SubnetNextObjectiveStoreKey,
Saurav Das4ce45962015-11-24 23:21:05 -0800108 Integer> subnetNextObjStore,
109 EventuallyConsistentMap<PortNextObjectiveStoreKey,
Charles Chan188ebf52015-12-23 00:15:11 -0800110 Integer> portNextObjStore,
111 SegmentRoutingManager srManager) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800112 this.deviceId = checkNotNull(deviceId);
113 this.appId = checkNotNull(appId);
114 this.deviceConfig = checkNotNull(config);
115 this.linkService = checkNotNull(linkService);
Charles Chan0b4e6182015-11-03 10:42:14 -0800116 this.allSegmentIds = checkNotNull(config.getAllDeviceSegmentIds());
117 try {
118 this.nodeSegmentId = config.getSegmentId(deviceId);
119 this.isEdgeRouter = config.isEdgeDevice(deviceId);
120 this.nodeMacAddr = checkNotNull(config.getDeviceMac(deviceId));
121 } catch (DeviceConfigNotFoundException e) {
122 log.warn(e.getMessage()
123 + " Skipping value assignment in DefaultGroupHandler");
124 }
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700125 this.flowObjectiveService = flowObjService;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700126 this.nsNextObjStore = nsNextObjStore;
Charles Chanc42e84e2015-10-20 16:24:19 -0700127 this.subnetNextObjStore = subnetNextObjStore;
Saurav Das4ce45962015-11-24 23:21:05 -0800128 this.portNextObjStore = portNextObjStore;
Charles Chan188ebf52015-12-23 00:15:11 -0800129 this.srManager = srManager;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800130
131 populateNeighborMaps();
132 }
133
134 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700135 * Creates a group handler object based on the type of device. If device is
136 * of edge type it returns edge group handler, else it returns transit group
137 * handler.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800138 *
139 * @param deviceId device identifier
140 * @param appId application identifier
141 * @param config interface to retrieve the device properties
142 * @param linkService link service object
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700143 * @param flowObjService flow objective service object
Charles Chanc42e84e2015-10-20 16:24:19 -0700144 * @param nsNextObjStore NeighborSet next objective store map
145 * @param subnetNextObjStore subnet next objective store map
Charles Chan0b4e6182015-11-03 10:42:14 -0800146 * @throws DeviceConfigNotFoundException if the device configuration is not found
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800147 * @return default group handler type
148 */
Saurav Das4ce45962015-11-24 23:21:05 -0800149 public static DefaultGroupHandler createGroupHandler(
150 DeviceId deviceId,
151 ApplicationId appId,
152 DeviceProperties config,
153 LinkService linkService,
154 FlowObjectiveService flowObjService,
155 EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey,
156 Integer> nsNextObjStore,
157 EventuallyConsistentMap<SubnetNextObjectiveStoreKey,
158 Integer> subnetNextObjStore,
159 EventuallyConsistentMap<PortNextObjectiveStoreKey,
Charles Chan188ebf52015-12-23 00:15:11 -0800160 Integer> portNextObjStore,
161 SegmentRoutingManager srManager)
Saurav Das4ce45962015-11-24 23:21:05 -0800162 throws DeviceConfigNotFoundException {
Charles Chan0b4e6182015-11-03 10:42:14 -0800163 // handle possible exception in the caller
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800164 if (config.isEdgeDevice(deviceId)) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700165 return new DefaultEdgeGroupHandler(deviceId, appId, config,
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700166 linkService,
167 flowObjService,
Charles Chanc42e84e2015-10-20 16:24:19 -0700168 nsNextObjStore,
Saurav Das4ce45962015-11-24 23:21:05 -0800169 subnetNextObjStore,
Charles Chan188ebf52015-12-23 00:15:11 -0800170 portNextObjStore,
171 srManager
172 );
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800173 } else {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700174 return new DefaultTransitGroupHandler(deviceId, appId, config,
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700175 linkService,
176 flowObjService,
Charles Chanc42e84e2015-10-20 16:24:19 -0700177 nsNextObjStore,
Saurav Das4ce45962015-11-24 23:21:05 -0800178 subnetNextObjStore,
Charles Chan188ebf52015-12-23 00:15:11 -0800179 portNextObjStore,
180 srManager);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800181 }
182 }
183
184 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700185 * Creates the auto created groups for this device based on the current
186 * snapshot of the topology.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800187 */
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700188 // Empty implementations to be overridden by derived classes
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800189 public void createGroups() {
190 }
191
192 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700193 * Performs group creation or update procedures when a new link is
194 * discovered on this device.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800195 *
196 * @param newLink new neighbor link
197 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800198 public void linkUp(Link newLink, boolean isMaster) {
sanghob35a6192015-04-01 13:05:26 -0700199
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800200 if (newLink.type() != Link.Type.DIRECT) {
201 log.warn("linkUp: unknown link type");
202 return;
203 }
204
205 if (!newLink.src().deviceId().equals(deviceId)) {
206 log.warn("linkUp: deviceId{} doesn't match with link src{}",
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700207 deviceId, newLink.src().deviceId());
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800208 return;
209 }
210
Saurav Das8a0732e2015-11-20 15:27:53 -0800211 log.info("* LinkUP: Device {} linkUp at local port {} to neighbor {}", deviceId,
212 newLink.src().port(), newLink.dst().deviceId());
Charles Chan0b4e6182015-11-03 10:42:14 -0800213 MacAddress dstMac;
214 try {
215 dstMac = deviceConfig.getDeviceMac(newLink.dst().deviceId());
216 } catch (DeviceConfigNotFoundException e) {
217 log.warn(e.getMessage() + " Aborting linkUp.");
218 return;
219 }
220
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700221 addNeighborAtPort(newLink.dst().deviceId(),
222 newLink.src().port());
223 /*if (devicePortMap.get(newLink.dst().deviceId()) == null) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800224 // New Neighbor
225 newNeighbor(newLink);
226 } else {
227 // Old Neighbor
228 newPortToExistingNeighbor(newLink);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700229 }*/
230 Set<NeighborSet> nsSet = nsNextObjStore.keySet()
231 .stream()
232 .filter((nsStoreEntry) -> (nsStoreEntry.deviceId().equals(deviceId)))
233 .map((nsStoreEntry) -> (nsStoreEntry.neighborSet()))
234 .filter((ns) -> (ns.getDeviceIds()
235 .contains(newLink.dst().deviceId())))
236 .collect(Collectors.toSet());
237 log.trace("linkUp: nsNextObjStore contents for device {}:",
sangho0b2b6d12015-05-20 22:16:38 -0700238 deviceId,
239 nsSet);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700240 for (NeighborSet ns : nsSet) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700241 Integer nextId = nsNextObjStore.
242 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
Saurav Das4ce45962015-11-24 23:21:05 -0800243 if (nextId != null && isMaster) {
Saurav Das423fe2b2015-12-04 10:52:59 -0800244 // Create the new bucket to be updated
245 TrafficTreatment.Builder tBuilder =
246 DefaultTrafficTreatment.builder();
247 tBuilder.setOutput(newLink.src().port())
248 .setEthDst(dstMac)
249 .setEthSrc(nodeMacAddr);
250 if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) {
251 tBuilder.pushMpls()
252 .copyTtlOut()
253 .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel()));
254 }
255 // setup metadata to pass to nextObjective - indicate the vlan on egress
256 // if needed by the switch pipeline. Since hashed next-hops are always to
257 // other neighboring routers, there is no subnet assigned on those ports.
258 TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder();
259 metabuilder.matchVlanId(
260 VlanId.vlanId(SegmentRoutingManager.ASSIGNED_VLAN_NO_SUBNET));
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700261
Saurav Das423fe2b2015-12-04 10:52:59 -0800262 NextObjective.Builder nextObjBuilder = DefaultNextObjective.builder()
263 .withId(nextId)
264 .withType(NextObjective.Type.HASHED)
265 .addTreatment(tBuilder.build())
266 .withMeta(metabuilder.build())
267 .fromApp(appId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800268 log.info("**linkUp in device {}: Adding Bucket "
Saurav Das4ce45962015-11-24 23:21:05 -0800269 + "with Port {} to next object id {}",
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700270 deviceId,
271 newLink.src().port(),
Saurav Das4ce45962015-11-24 23:21:05 -0800272 nextId);
273 NextObjective nextObjective = nextObjBuilder.
274 addToExisting(new SRNextObjectiveContext(deviceId));
275 flowObjectiveService.next(deviceId, nextObjective);
Saurav Das423fe2b2015-12-04 10:52:59 -0800276
277 // the addition of a bucket may actually change the neighborset
278 // update the global store
279 /*
280 Set<DeviceId> neighbors = new HashSet<DeviceId>(ns.getDeviceIds());
281 boolean newadd = neighbors.add(newLink.dst().deviceId());
282 if (newadd) {
283 NeighborSet nsnew = new NeighborSet(neighbors, ns.getEdgeLabel());
284 nsNextObjStore.put(new NeighborSetNextObjectiveStoreKey(deviceId, nsnew),
285 nextId);
286 nsNextObjStore.remove(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
287 }*/
Saurav Das4ce45962015-11-24 23:21:05 -0800288 } else if (isMaster) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800289 log.warn("linkUp in device {}, but global store has no record "
290 + "for neighbor-set {}", deviceId, ns);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700291 }
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800292 }
293 }
294
295 /**
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700296 * Performs group recovery procedures when a port goes down on this device.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800297 *
298 * @param port port number that has gone down
299 */
Saurav Das423fe2b2015-12-04 10:52:59 -0800300 public void portDown(PortNumber port, boolean isMaster) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800301 if (portDeviceMap.get(port) == null) {
302 log.warn("portDown: unknown port");
303 return;
304 }
Charles Chan0b4e6182015-11-03 10:42:14 -0800305
306 MacAddress dstMac;
307 try {
308 dstMac = deviceConfig.getDeviceMac(portDeviceMap.get(port));
309 } catch (DeviceConfigNotFoundException e) {
310 log.warn(e.getMessage() + " Aborting portDown.");
311 return;
312 }
313
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700314 log.debug("Device {} portDown {} to neighbor {}", deviceId, port,
315 portDeviceMap.get(port));
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700316 /*Set<NeighborSet> nsSet = computeImpactedNeighborsetForPortEvent(portDeviceMap
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700317 .get(port),
318 devicePortMap
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700319 .keySet());*/
320 Set<NeighborSet> nsSet = nsNextObjStore.keySet()
321 .stream()
322 .filter((nsStoreEntry) -> (nsStoreEntry.deviceId().equals(deviceId)))
323 .map((nsStoreEntry) -> (nsStoreEntry.neighborSet()))
324 .filter((ns) -> (ns.getDeviceIds()
325 .contains(portDeviceMap.get(port))))
326 .collect(Collectors.toSet());
Saurav Das423fe2b2015-12-04 10:52:59 -0800327 log.debug("portDown: nsNextObjStore contents for device {}:{}",
328 deviceId, nsSet);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800329 for (NeighborSet ns : nsSet) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700330 Integer nextId = nsNextObjStore.
331 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
Saurav Das423fe2b2015-12-04 10:52:59 -0800332 if (nextId != null && isMaster) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800333 log.info("**portDown in device {}: Removing Bucket "
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700334 + "with Port {} to next object id {}",
335 deviceId,
336 port,
337 nextId);
Saurav Das423fe2b2015-12-04 10:52:59 -0800338 // Create the bucket to be removed
339 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment
340 .builder();
341 tBuilder.setOutput(port)
342 .setEthDst(dstMac)
343 .setEthSrc(nodeMacAddr);
344 if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) {
345 tBuilder.pushMpls()
346 .copyTtlOut()
347 .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel()));
348 }
349 NextObjective.Builder nextObjBuilder = DefaultNextObjective
350 .builder()
351 .withType(NextObjective.Type.HASHED) //same as original
352 .withId(nextId)
353 .fromApp(appId)
354 .addTreatment(tBuilder.build());
355 NextObjective nextObjective = nextObjBuilder.
356 removeFromExisting(new SRNextObjectiveContext(deviceId));
sangho834e4b02015-05-01 09:38:25 -0700357
Saurav Das423fe2b2015-12-04 10:52:59 -0800358 flowObjectiveService.next(deviceId, nextObjective);
359
360 // the removal of a bucket may actually change the neighborset
361 // update the global store
362 /*
363 Set<DeviceId> neighbors = new HashSet<DeviceId>(ns.getDeviceIds());
364 boolean removed = neighbors.remove(portDeviceMap.get(port));
365 if (removed) {
366 NeighborSet nsnew = new NeighborSet(neighbors, ns.getEdgeLabel());
367 nsNextObjStore.put(new NeighborSetNextObjectiveStoreKey(deviceId, nsnew),
368 nextId);
369 nsNextObjStore.remove(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
370 }*/
sangho834e4b02015-05-01 09:38:25 -0700371 }
372
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800373 }
374
375 devicePortMap.get(portDeviceMap.get(port)).remove(port);
376 portDeviceMap.remove(port);
377 }
378
379 /**
Saurav Das4ce45962015-11-24 23:21:05 -0800380 * Returns the next objective of type hashed associated with the neighborset.
381 * If there is no next objective for this neighborset, this method
Saurav Das8a0732e2015-11-20 15:27:53 -0800382 * would create a next objective and return. Optionally metadata can be
383 * passed in for the creation of the next objective.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800384 *
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700385 * @param ns neighborset
Saurav Das8a0732e2015-11-20 15:27:53 -0800386 * @param meta metadata passed into the creation of a Next Objective
387 * @return int if found or -1 if there are errors in the creation of the
388 * neighbor set.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800389 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800390 public int getNextObjectiveId(NeighborSet ns, TrafficSelector meta) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700391 Integer nextId = nsNextObjStore.
392 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700393 if (nextId == null) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700394 log.trace("getNextObjectiveId in device{}: Next objective id "
395 + "not found for {} and creating", deviceId, ns);
396 log.trace("getNextObjectiveId: nsNextObjStore contents for device {}: {}",
397 deviceId,
398 nsNextObjStore.entrySet()
399 .stream()
400 .filter((nsStoreEntry) ->
401 (nsStoreEntry.getKey().deviceId().equals(deviceId)))
402 .collect(Collectors.toList()));
Saurav Das8a0732e2015-11-20 15:27:53 -0800403 createGroupsFromNeighborsets(Collections.singleton(ns), meta);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700404 nextId = nsNextObjStore.
405 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700406 if (nextId == null) {
407 log.warn("getNextObjectiveId: unable to create next objective");
408 return -1;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700409 } else {
410 log.debug("getNextObjectiveId in device{}: Next objective id {} "
Sho SHIMIZUaf973432015-09-11 14:24:50 -0700411 + "created for {}", deviceId, nextId, ns);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700412 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700413 } else {
414 log.trace("getNextObjectiveId in device{}: Next objective id {} "
Sho SHIMIZUaf973432015-09-11 14:24:50 -0700415 + "found for {}", deviceId, nextId, ns);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700416 }
Sho SHIMIZUaf973432015-09-11 14:24:50 -0700417 return nextId;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800418 }
419
sangho0b2b6d12015-05-20 22:16:38 -0700420 /**
Saurav Das4ce45962015-11-24 23:21:05 -0800421 * Returns the next objective of type broadcast associated with the subnet,
422 * or -1 if no such objective exists. Note that this method does NOT create
423 * the next objective as a side-effect. It is expected that is objective is
424 * created at startup from network configuration.
Charles Chanc42e84e2015-10-20 16:24:19 -0700425 *
426 * @param prefix subnet information
427 * @return int if found or -1
428 */
429 public int getSubnetNextObjectiveId(IpPrefix prefix) {
430 Integer nextId = subnetNextObjStore.
431 get(new SubnetNextObjectiveStoreKey(deviceId, prefix));
Charles Chan9f676b62015-10-29 14:58:10 -0700432
433 return (nextId != null) ? nextId : -1;
Charles Chanc42e84e2015-10-20 16:24:19 -0700434 }
435
436 /**
Saurav Das4ce45962015-11-24 23:21:05 -0800437 * Returns the next objective of type simple associated with the port on the
438 * device, given the treatment. Different treatments to the same port result
439 * in different next objectives. If no such objective exists, this method
440 * creates one and returns the id. Optionally metadata can be passed in for
441 * the creation of the objective.
442 *
443 * @param portNum the port number for the simple next objective
444 * @param treatment the actions to apply on the packets (should include outport)
445 * @param meta optional metadata passed into the creation of the next objective
446 * @return int if found or created, -1 if there are errors during the
447 * creation of the next objective.
448 */
449 public int getPortNextObjectiveId(PortNumber portNum, TrafficTreatment treatment,
450 TrafficSelector meta) {
451 Integer nextId = portNextObjStore.
452 get(new PortNextObjectiveStoreKey(deviceId, portNum, treatment));
453 if (nextId == null) {
454 log.trace("getPortNextObjectiveId in device{}: Next objective id "
455 + "not found for {} and {} creating", deviceId, portNum);
456 createGroupFromPort(portNum, treatment, meta);
457 nextId = portNextObjStore.get(
458 new PortNextObjectiveStoreKey(deviceId, portNum, treatment));
459 if (nextId == null) {
460 log.warn("getPortNextObjectiveId: unable to create next obj"
461 + "for dev:{} port{}", deviceId, portNum);
462 return -1;
463 }
464 }
465 return nextId;
466 }
467
468 /**
sangho0b2b6d12015-05-20 22:16:38 -0700469 * Checks if the next objective ID (group) for the neighbor set exists or not.
470 *
471 * @param ns neighbor set to check
472 * @return true if it exists, false otherwise
473 */
474 public boolean hasNextObjectiveId(NeighborSet ns) {
475 Integer nextId = nsNextObjStore.
476 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
477 if (nextId == null) {
478 return false;
479 }
480
481 return true;
482 }
483
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700484 // Empty implementation
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800485 protected void newNeighbor(Link newLink) {
486 }
487
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700488 // Empty implementation
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800489 protected void newPortToExistingNeighbor(Link newLink) {
490 }
491
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700492 // Empty implementation
493 protected Set<NeighborSet>
494 computeImpactedNeighborsetForPortEvent(DeviceId impactedNeighbor,
495 Set<DeviceId> updatedNeighbors) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800496 return null;
497 }
498
499 private void populateNeighborMaps() {
500 Set<Link> outgoingLinks = linkService.getDeviceEgressLinks(deviceId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700501 for (Link link : outgoingLinks) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800502 if (link.type() != Link.Type.DIRECT) {
503 continue;
504 }
505 addNeighborAtPort(link.dst().deviceId(), link.src().port());
506 }
507 }
508
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700509 protected void addNeighborAtPort(DeviceId neighborId,
510 PortNumber portToNeighbor) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800511 // Update DeviceToPort database
512 log.debug("Device {} addNeighborAtPort: neighbor {} at port {}",
513 deviceId, neighborId, portToNeighbor);
Saurav Das8a0732e2015-11-20 15:27:53 -0800514 Set<PortNumber> ports = Collections
515 .newSetFromMap(new ConcurrentHashMap<PortNumber, Boolean>());
516 ports.add(portToNeighbor);
517 Set<PortNumber> portnums = devicePortMap.putIfAbsent(neighborId, ports);
518 if (portnums != null) {
519 portnums.add(portToNeighbor);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800520 }
521
522 // Update portToDevice database
Saurav Das8a0732e2015-11-20 15:27:53 -0800523 DeviceId prev = portDeviceMap.putIfAbsent(portToNeighbor, neighborId);
524 if (prev != null) {
525 log.warn("Device: {} port: {} has neighbor: {}. NOT updating "
526 + "to neighbor: {}", deviceId, portToNeighbor, prev, neighborId);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800527 }
528 }
529
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700530 protected Set<Set<DeviceId>> getPowerSetOfNeighbors(Set<DeviceId> neighbors) {
Sho SHIMIZU6cfc02d2015-09-11 11:19:11 -0700531 List<DeviceId> list = new ArrayList<>(neighbors);
532 Set<Set<DeviceId>> sets = new HashSet<>();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800533 // get the number of elements in the neighbors
534 int elements = list.size();
535 // the number of members of a power set is 2^n
536 // including the empty set
537 int powerElements = (1 << elements);
538
539 // run a binary counter for the number of power elements
540 // NOTE: Exclude empty set
541 for (long i = 1; i < powerElements; i++) {
Sho SHIMIZU6cfc02d2015-09-11 11:19:11 -0700542 Set<DeviceId> neighborSubSet = new HashSet<>();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800543 for (int j = 0; j < elements; j++) {
544 if ((i >> j) % 2 == 1) {
545 neighborSubSet.add(list.get(j));
546 }
547 }
548 sets.add(neighborSubSet);
549 }
550 return sets;
551 }
552
553 private boolean isSegmentIdSameAsNodeSegmentId(DeviceId deviceId, int sId) {
Charles Chan0b4e6182015-11-03 10:42:14 -0800554 int segmentId;
555 try {
556 segmentId = deviceConfig.getSegmentId(deviceId);
557 } catch (DeviceConfigNotFoundException e) {
558 log.warn(e.getMessage() + " Aborting isSegmentIdSameAsNodeSegmentId.");
559 return false;
560 }
561
562 return segmentId == sId;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800563 }
564
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700565 protected List<Integer> getSegmentIdsTobePairedWithNeighborSet(Set<DeviceId> neighbors) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800566
Sho SHIMIZU6cfc02d2015-09-11 11:19:11 -0700567 List<Integer> nsSegmentIds = new ArrayList<>();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800568
sanghob35a6192015-04-01 13:05:26 -0700569 // Always pair up with no edge label
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700570 // If (neighbors.size() == 1) {
sanghob35a6192015-04-01 13:05:26 -0700571 nsSegmentIds.add(-1);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700572 // }
sanghob35a6192015-04-01 13:05:26 -0700573
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800574 // Filter out SegmentIds matching with the
575 // nodes in the combo
576 for (Integer sId : allSegmentIds) {
577 if (sId.equals(nodeSegmentId)) {
578 continue;
579 }
580 boolean filterOut = false;
581 // Check if the edge label being set is of
582 // any node in the Neighbor set
583 for (DeviceId deviceId : neighbors) {
584 if (isSegmentIdSameAsNodeSegmentId(deviceId, sId)) {
585 filterOut = true;
586 break;
587 }
588 }
589 if (!filterOut) {
590 nsSegmentIds.add(sId);
591 }
592 }
593 return nsSegmentIds;
594 }
595
sangho1e575652015-05-14 00:39:53 -0700596 /**
597 * Creates Groups from a set of NeighborSet given.
598 *
599 * @param nsSet a set of NeighborSet
Saurav Das8a0732e2015-11-20 15:27:53 -0800600 * @param meta metadata passed into the creation of a Next Objective
sangho1e575652015-05-14 00:39:53 -0700601 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800602 public void createGroupsFromNeighborsets(Set<NeighborSet> nsSet,
603 TrafficSelector meta) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800604 for (NeighborSet ns : nsSet) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700605 int nextId = flowObjectiveService.allocateNextId();
606 NextObjective.Builder nextObjBuilder = DefaultNextObjective
607 .builder().withId(nextId)
608 .withType(NextObjective.Type.HASHED).fromApp(appId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800609 for (DeviceId neighborId : ns.getDeviceIds()) {
610 if (devicePortMap.get(neighborId) == null) {
611 log.warn("Neighbor {} is not in the port map yet for dev:{}",
612 neighborId, deviceId);
sangho834e4b02015-05-01 09:38:25 -0700613 return;
Saurav Das8a0732e2015-11-20 15:27:53 -0800614 } else if (devicePortMap.get(neighborId).size() == 0) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700615 log.warn("There are no ports for "
Saurav Das8a0732e2015-11-20 15:27:53 -0800616 + "the Device {} in the port map yet", neighborId);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700617 return;
sangho834e4b02015-05-01 09:38:25 -0700618 }
619
Saurav Das8a0732e2015-11-20 15:27:53 -0800620 MacAddress neighborMac;
Charles Chan0b4e6182015-11-03 10:42:14 -0800621 try {
Saurav Das8a0732e2015-11-20 15:27:53 -0800622 neighborMac = deviceConfig.getDeviceMac(neighborId);
Charles Chan0b4e6182015-11-03 10:42:14 -0800623 } catch (DeviceConfigNotFoundException e) {
624 log.warn(e.getMessage() + " Aborting createGroupsFromNeighborsets.");
625 return;
626 }
627
Saurav Das8a0732e2015-11-20 15:27:53 -0800628 for (PortNumber sp : devicePortMap.get(neighborId)) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700629 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment
630 .builder();
Saurav Das8a0732e2015-11-20 15:27:53 -0800631 tBuilder.setEthDst(neighborMac)
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700632 .setEthSrc(nodeMacAddr);
633 if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) {
Charles Chan68aa62d2015-11-09 16:37:23 -0800634 tBuilder.pushMpls()
635 .copyTtlOut()
636 .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel()));
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700637 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800638 tBuilder.setOutput(sp);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700639 nextObjBuilder.addTreatment(tBuilder.build());
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800640 }
641 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800642 if (meta != null) {
Saurav Das4ce45962015-11-24 23:21:05 -0800643 nextObjBuilder.withMeta(meta);
Saurav Das8a0732e2015-11-20 15:27:53 -0800644 }
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -0700645 NextObjective nextObj = nextObjBuilder.
646 add(new SRNextObjectiveContext(deviceId));
Saurav Das8a0732e2015-11-20 15:27:53 -0800647 log.info("**createGroupsFromNeighborsets: Submited "
648 + "next objective {} in device {}",
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700649 nextId, deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800650 flowObjectiveService.next(deviceId, nextObj);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700651 nsNextObjStore.put(new NeighborSetNextObjectiveStoreKey(deviceId, ns),
652 nextId);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800653 }
654 }
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700655
Saurav Das4ce45962015-11-24 23:21:05 -0800656 /**
657 * Creates broadcast groups for all ports in the same configured subnet.
658 *
659 */
Charles Chanc42e84e2015-10-20 16:24:19 -0700660 public void createGroupsFromSubnetConfig() {
661 Map<Ip4Prefix, List<PortNumber>> subnetPortMap =
662 this.deviceConfig.getSubnetPortsMap(this.deviceId);
Charles Chanc42e84e2015-10-20 16:24:19 -0700663 // Construct a broadcast group for each subnet
664 subnetPortMap.forEach((subnet, ports) -> {
Charles Chan9f676b62015-10-29 14:58:10 -0700665 SubnetNextObjectiveStoreKey key =
666 new SubnetNextObjectiveStoreKey(deviceId, subnet);
667
668 if (subnetNextObjStore.containsKey(key)) {
669 log.debug("Broadcast group for device {} and subnet {} exists",
670 deviceId, subnet);
671 return;
672 }
673
Charles Chan188ebf52015-12-23 00:15:11 -0800674 VlanId assignedVlanId =
675 srManager.getSubnetAssignedVlanId(this.deviceId, subnet);
676 TrafficSelector metadata =
677 DefaultTrafficSelector.builder().matchVlanId(assignedVlanId).build();
678
Charles Chanc42e84e2015-10-20 16:24:19 -0700679 int nextId = flowObjectiveService.allocateNextId();
680
681 NextObjective.Builder nextObjBuilder = DefaultNextObjective
682 .builder().withId(nextId)
Charles Chan188ebf52015-12-23 00:15:11 -0800683 .withType(NextObjective.Type.BROADCAST).fromApp(appId)
684 .withMeta(metadata);
Charles Chanc42e84e2015-10-20 16:24:19 -0700685
686 ports.forEach(port -> {
687 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
Saurav Das4f980082015-11-05 13:39:15 -0800688 tBuilder.popVlan();
Charles Chanc42e84e2015-10-20 16:24:19 -0700689 tBuilder.setOutput(port);
690 nextObjBuilder.addTreatment(tBuilder.build());
691 });
692
693 NextObjective nextObj = nextObjBuilder.add();
694 flowObjectiveService.next(deviceId, nextObj);
695 log.debug("createGroupFromSubnetConfig: Submited "
696 + "next objective {} in device {}",
697 nextId, deviceId);
Charles Chan9f676b62015-10-29 14:58:10 -0700698
Charles Chanc42e84e2015-10-20 16:24:19 -0700699 subnetNextObjStore.put(key, nextId);
700 });
701 }
702
Saurav Das4ce45962015-11-24 23:21:05 -0800703
704 /**
705 * Create simple next objective for a single port. The treatments can include
706 * all outgoing actions that need to happen on the packet.
707 *
708 * @param portNum the outgoing port on the device
709 * @param treatment the actions to apply on the packets (should include outport)
710 * @param meta optional data to pass to the driver
711 */
712 public void createGroupFromPort(PortNumber portNum, TrafficTreatment treatment,
713 TrafficSelector meta) {
714 int nextId = flowObjectiveService.allocateNextId();
715 PortNextObjectiveStoreKey key = new PortNextObjectiveStoreKey(
716 deviceId, portNum, treatment);
717
718 NextObjective.Builder nextObjBuilder = DefaultNextObjective
719 .builder().withId(nextId)
720 .withType(NextObjective.Type.SIMPLE)
721 .addTreatment(treatment)
722 .fromApp(appId)
723 .withMeta(meta);
724
725 NextObjective nextObj = nextObjBuilder.add();
726 flowObjectiveService.next(deviceId, nextObj);
727 log.debug("createGroupFromPort: Submited next objective {} in device {} "
728 + "for port {}", nextId, deviceId, portNum);
729
730 portNextObjStore.put(key, nextId);
731 }
732
733
sanghob35a6192015-04-01 13:05:26 -0700734 public GroupKey getGroupKey(Object obj) {
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700735 return new DefaultGroupKey(kryo.build().serialize(obj));
736 }
sanghob35a6192015-04-01 13:05:26 -0700737
sangho1e575652015-05-14 00:39:53 -0700738 /**
739 * Removes groups for the next objective ID given.
740 *
741 * @param objectiveId next objective ID to remove
742 * @return true if succeeds, false otherwise
743 */
744 public boolean removeGroup(int objectiveId) {
745
746 if (nsNextObjStore.containsValue(objectiveId)) {
747 NextObjective.Builder nextObjBuilder = DefaultNextObjective
748 .builder().withId(objectiveId)
749 .withType(NextObjective.Type.HASHED).fromApp(appId);
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -0700750 NextObjective nextObjective = nextObjBuilder.
751 remove(new SRNextObjectiveContext(deviceId));
Saurav Das8a0732e2015-11-20 15:27:53 -0800752 log.info("**removeGroup: Submited "
753 + "next objective {} in device {}",
754 objectiveId, deviceId);
sangho1e575652015-05-14 00:39:53 -0700755 flowObjectiveService.next(deviceId, nextObjective);
756
757 for (Map.Entry<NeighborSetNextObjectiveStoreKey, Integer> entry: nsNextObjStore.entrySet()) {
758 if (entry.getValue().equals(objectiveId)) {
759 nsNextObjStore.remove(entry.getKey());
760 break;
761 }
762 }
sangho0b2b6d12015-05-20 22:16:38 -0700763 return true;
sangho1e575652015-05-14 00:39:53 -0700764 }
765
766 return false;
767 }
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -0700768
Saurav Das423fe2b2015-12-04 10:52:59 -0800769 public void removeAllGroups() {
770 for (Map.Entry<NeighborSetNextObjectiveStoreKey, Integer> entry:
771 nsNextObjStore.entrySet()) {
772 removeGroup(entry.getValue());
773 }
774 for (Map.Entry<PortNextObjectiveStoreKey, Integer> entry:
775 portNextObjStore.entrySet()) {
776 removeGroup(entry.getValue());
777 }
778 for (Map.Entry<SubnetNextObjectiveStoreKey, Integer> entry:
779 subnetNextObjStore.entrySet()) {
780 removeGroup(entry.getValue());
781 }
782 // should probably clean local stores port-neighbor
783 }
784
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -0700785 protected static class SRNextObjectiveContext implements ObjectiveContext {
786 final DeviceId deviceId;
787
788 SRNextObjectiveContext(DeviceId deviceId) {
789 this.deviceId = deviceId;
790 }
791 @Override
792 public void onSuccess(Objective objective) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800793 log.info("Next objective {} operation successful in device {}",
794 objective.id(), deviceId);
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -0700795 }
796
797 @Override
798 public void onError(Objective objective, ObjectiveError error) {
799 log.warn("Next objective {} operation failed with error: {} in device {}",
Saurav Das8a0732e2015-11-20 15:27:53 -0800800 objective.id(), error, deviceId);
Srikanth Vavilapallif3a8bc02015-05-22 13:47:31 -0700801 }
802 }
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800803}