blob: 0dd5f21504a29b533a8ba3209b9b3de5e5634e46 [file] [log] [blame]
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -04001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -04003 *
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 */
16
Andrea Campanella0288c872017-08-07 18:32:51 +020017package org.onosproject.drivers.p4runtime;
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040018
Carmelo Cascone58136812018-07-19 03:40:16 +020019import com.google.common.collect.ImmutableList;
Yi Tseng8d355132018-04-13 01:40:48 +080020import com.google.common.collect.Sets;
Carmelo Cascone58136812018-07-19 03:40:16 +020021import com.google.common.util.concurrent.Striped;
Carmelo Casconee75b7942017-11-21 17:14:49 -080022import org.onosproject.drivers.p4runtime.mirror.P4RuntimeGroupMirror;
Carmelo Cascone58136812018-07-19 03:40:16 +020023import org.onosproject.drivers.p4runtime.mirror.P4RuntimeMulticastGroupMirror;
Yi Tseng76737cf2018-01-31 17:13:21 -080024import org.onosproject.drivers.p4runtime.mirror.TimedEntry;
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040025import org.onosproject.net.DeviceId;
Carmelo Casconee75b7942017-11-21 17:14:49 -080026import org.onosproject.net.group.DefaultGroup;
Yi Tsengfe13f3e2018-08-19 03:09:54 +080027import org.onosproject.net.group.DefaultGroupDescription;
Yi Tseng82512da2017-08-16 19:46:36 -070028import org.onosproject.net.group.Group;
Carmelo Cascone58136812018-07-19 03:40:16 +020029import org.onosproject.net.group.GroupDescription;
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040030import org.onosproject.net.group.GroupOperation;
31import org.onosproject.net.group.GroupOperations;
32import org.onosproject.net.group.GroupProgrammable;
Yi Tseng82512da2017-08-16 19:46:36 -070033import org.onosproject.net.group.GroupStore;
Carmelo Cascone87892e22017-11-13 16:01:29 -080034import org.onosproject.net.pi.model.PiActionProfileId;
Carmelo Casconee75b7942017-11-21 17:14:49 -080035import org.onosproject.net.pi.model.PiActionProfileModel;
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040036import org.onosproject.net.pi.runtime.PiActionGroup;
Carmelo Casconee75b7942017-11-21 17:14:49 -080037import org.onosproject.net.pi.runtime.PiActionGroupHandle;
Yi Tseng8d355132018-04-13 01:40:48 +080038import org.onosproject.net.pi.runtime.PiActionGroupMember;
Carmelo Cascone58136812018-07-19 03:40:16 +020039import org.onosproject.net.pi.runtime.PiMulticastGroupEntry;
40import org.onosproject.net.pi.runtime.PiMulticastGroupEntryHandle;
Carmelo Casconee75b7942017-11-21 17:14:49 -080041import org.onosproject.net.pi.service.PiGroupTranslator;
Carmelo Cascone58136812018-07-19 03:40:16 +020042import org.onosproject.net.pi.service.PiMulticastGroupTranslator;
Carmelo Casconee75b7942017-11-21 17:14:49 -080043import org.onosproject.net.pi.service.PiTranslatedEntity;
Carmelo Cascone326ad2d2017-11-28 18:09:13 -080044import org.onosproject.net.pi.service.PiTranslationException;
Carmelo Cascone58136812018-07-19 03:40:16 +020045import org.onosproject.p4runtime.api.P4RuntimeClient;
Yi Tseng82512da2017-08-16 19:46:36 -070046import org.slf4j.Logger;
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040047
Yi Tseng82512da2017-08-16 19:46:36 -070048import java.util.Collection;
49import java.util.Collections;
Carmelo Casconee75b7942017-11-21 17:14:49 -080050import java.util.Objects;
Yi Tseng82512da2017-08-16 19:46:36 -070051import java.util.concurrent.CompletableFuture;
Yi Tseng82512da2017-08-16 19:46:36 -070052import java.util.concurrent.locks.Lock;
Carmelo Casconee75b7942017-11-21 17:14:49 -080053import java.util.stream.Collectors;
54import java.util.stream.Stream;
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040055
Carmelo Casconee5b28722018-06-22 17:28:28 +020056import static java.lang.String.format;
Carmelo Casconee75b7942017-11-21 17:14:49 -080057import static org.onosproject.p4runtime.api.P4RuntimeClient.WriteOperationType.DELETE;
58import static org.onosproject.p4runtime.api.P4RuntimeClient.WriteOperationType.INSERT;
Yi Tseng8d355132018-04-13 01:40:48 +080059import static org.onosproject.p4runtime.api.P4RuntimeClient.WriteOperationType.MODIFY;
Yi Tseng82512da2017-08-16 19:46:36 -070060import static org.slf4j.LoggerFactory.getLogger;
61
62/**
63 * Implementation of the group programmable behaviour for P4Runtime.
Carmelo Cascone58136812018-07-19 03:40:16 +020064 * <p>
65 * This implementation distinguishes between ALL groups, and other types. ALL
66 * groups are handled via PRE multicast group programming, while other types are
67 * handled via action profile group programming.
Yi Tseng82512da2017-08-16 19:46:36 -070068 */
Carmelo Casconee75b7942017-11-21 17:14:49 -080069public class P4RuntimeGroupProgrammable
70 extends AbstractP4RuntimeHandlerBehaviour
71 implements GroupProgrammable {
72
Carmelo Casconee75b7942017-11-21 17:14:49 -080073 private static final String ACT_GRP_MEMS_STR = "action group members";
74 private static final String DELETE_STR = "delete";
75 private static final String ACT_GRP_STR = "action group";
76 private static final String INSERT_STR = "insert";
Yi Tseng8d355132018-04-13 01:40:48 +080077 private static final String MODIFY_STR = "modify";
Carmelo Casconee75b7942017-11-21 17:14:49 -080078
Yi Tseng82512da2017-08-16 19:46:36 -070079 private static final Logger log = getLogger(P4RuntimeGroupProgrammable.class);
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040080
Carmelo Casconee75b7942017-11-21 17:14:49 -080081 // If true, we ignore re-installing groups that are already known in the
82 // device mirror.
Yi Tsengf325a602018-06-27 18:26:33 +080083 private static final String CHECK_MIRROR_BEFORE_UPDATE = "checkMirrorBeforeUpdate";
84 private static final boolean DEFAULT_CHECK_MIRROR_BEFORE_UPDATE = true;
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040085
Yi Tseng76737cf2018-01-31 17:13:21 -080086 // If true, we avoid querying the device and return what's already known by
87 // the ONOS store.
Yi Tsengf325a602018-06-27 18:26:33 +080088 private static final String IGNORE_DEVICE_WHEN_GET = "ignoreDeviceWhenGet";
89 private static final boolean DEFAULT_IGNORE_DEVICE_WHEN_GET = false;
Yi Tseng76737cf2018-01-31 17:13:21 -080090
Esin Karaman971fb7f2017-12-28 13:44:52 +000091 protected GroupStore groupStore;
Carmelo Casconee75b7942017-11-21 17:14:49 -080092 private P4RuntimeGroupMirror groupMirror;
Carmelo Cascone58136812018-07-19 03:40:16 +020093 private PiGroupTranslator groupTranslator;
94 private P4RuntimeMulticastGroupMirror mcGroupMirror;
95 private PiMulticastGroupTranslator mcGroupTranslator;
Yi Tseng82512da2017-08-16 19:46:36 -070096
97 // Needed to synchronize operations over the same group.
Carmelo Cascone58136812018-07-19 03:40:16 +020098 private static final Striped<Lock> STRIPED_LOCKS = Striped.lock(30);
Yi Tseng82512da2017-08-16 19:46:36 -070099
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400100 @Override
Carmelo Casconee75b7942017-11-21 17:14:49 -0800101 protected boolean setupBehaviour() {
102 if (!super.setupBehaviour()) {
103 return false;
104 }
105 groupMirror = this.handler().get(P4RuntimeGroupMirror.class);
Carmelo Cascone58136812018-07-19 03:40:16 +0200106 mcGroupMirror = this.handler().get(P4RuntimeMulticastGroupMirror.class);
Carmelo Casconee75b7942017-11-21 17:14:49 -0800107 groupStore = handler().get(GroupStore.class);
Carmelo Cascone58136812018-07-19 03:40:16 +0200108 groupTranslator = piTranslationService.groupTranslator();
109 mcGroupTranslator = piTranslationService.multicastGroupTranslator();
Carmelo Casconee75b7942017-11-21 17:14:49 -0800110 return true;
111 }
112
113 @Override
114 public void performGroupOperation(DeviceId deviceId,
115 GroupOperations groupOps) {
Carmelo Cascone87b9b392017-10-02 18:33:20 +0200116 if (!setupBehaviour()) {
Yi Tseng82512da2017-08-16 19:46:36 -0700117 return;
118 }
Yi Tsengfe13f3e2018-08-19 03:09:54 +0800119 groupOps.operations().forEach(op -> {
120 // ONOS-7785 We need app cookie (action profile id) from the group
121 Group groupOnStore = groupStore.getGroup(deviceId, op.groupId());
122 GroupDescription groupDesc = new DefaultGroupDescription(deviceId,
123 op.groupType(),
124 op.buckets(),
125 groupOnStore.appCookie(),
126 op.groupId().id(),
127 groupOnStore.appId());
128 DefaultGroup groupToApply = new DefaultGroup(op.groupId(), groupDesc);
129 if (op.groupType().equals(GroupDescription.Type.ALL)) {
130 processMcGroupOp(deviceId, groupToApply, op.opType());
131 } else {
132
133 processGroupOp(deviceId, groupToApply, op.opType());
134 }
135 });
Yi Tseng82512da2017-08-16 19:46:36 -0700136 }
137
Yi Tseng82512da2017-08-16 19:46:36 -0700138 @Override
139 public Collection<Group> getGroups() {
Carmelo Cascone87b9b392017-10-02 18:33:20 +0200140 if (!setupBehaviour()) {
141 return Collections.emptyList();
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400142 }
Carmelo Cascone58136812018-07-19 03:40:16 +0200143 final ImmutableList.Builder<Group> groups = ImmutableList.builder();
144
Yi Tsengf325a602018-06-27 18:26:33 +0800145 if (!driverBoolProperty(IGNORE_DEVICE_WHEN_GET, DEFAULT_IGNORE_DEVICE_WHEN_GET)) {
Carmelo Cascone58136812018-07-19 03:40:16 +0200146 groups.addAll(pipeconf.pipelineModel().actionProfiles().stream()
147 .map(PiActionProfileModel::id)
148 .flatMap(this::streamGroupsFromDevice)
149 .iterator());
150 // FIXME: enable reading MC groups from device once reading from
151 // PRE is supported in PI
152 // groups.addAll(getMcGroupsFromDevice());
Yi Tseng76737cf2018-01-31 17:13:21 -0800153 } else {
Carmelo Cascone58136812018-07-19 03:40:16 +0200154 groups.addAll(groupMirror.getAll(deviceId).stream()
155 .map(TimedEntry::entry)
156 .map(this::forgeGroupEntry)
157 .iterator());
Yi Tseng76737cf2018-01-31 17:13:21 -0800158 }
Carmelo Cascone58136812018-07-19 03:40:16 +0200159 // FIXME: same as before..
160 groups.addAll(mcGroupMirror.getAll(deviceId).stream()
161 .map(TimedEntry::entry)
162 .map(this::forgeMcGroupEntry)
163 .iterator());
164
165 return groups.build();
Carmelo Casconee75b7942017-11-21 17:14:49 -0800166 }
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400167
Carmelo Cascone58136812018-07-19 03:40:16 +0200168 private void processGroupOp(DeviceId deviceId, Group pdGroup, GroupOperation.Type opType) {
Carmelo Casconee75b7942017-11-21 17:14:49 -0800169 final PiActionGroup piGroup;
170 try {
Carmelo Cascone58136812018-07-19 03:40:16 +0200171 piGroup = groupTranslator.translate(pdGroup, pipeconf);
Carmelo Casconee75b7942017-11-21 17:14:49 -0800172 } catch (PiTranslationException e) {
Carmelo Cascone58136812018-07-19 03:40:16 +0200173 log.warn("Unable to translate group, aborting {} operation: {} [{}]",
174 opType, e.getMessage(), pdGroup);
Carmelo Casconee75b7942017-11-21 17:14:49 -0800175 return;
176 }
Carmelo Casconee75b7942017-11-21 17:14:49 -0800177 final PiActionGroupHandle handle = PiActionGroupHandle.of(deviceId, piGroup);
178
179 final PiActionGroup groupOnDevice = groupMirror.get(handle) == null
180 ? null
181 : groupMirror.get(handle).entry();
182
Carmelo Cascone58136812018-07-19 03:40:16 +0200183 final Lock lock = STRIPED_LOCKS.get(handle);
Carmelo Casconee75b7942017-11-21 17:14:49 -0800184 lock.lock();
185 try {
Carmelo Casconee75b7942017-11-21 17:14:49 -0800186 processPiGroup(handle, piGroup,
Carmelo Cascone58136812018-07-19 03:40:16 +0200187 groupOnDevice, pdGroup, opType);
188 } finally {
189 lock.unlock();
190 }
191 }
192
193 private void processMcGroupOp(DeviceId deviceId, Group pdGroup, GroupOperation.Type opType) {
194 final PiMulticastGroupEntry mcGroup;
195 try {
196 mcGroup = mcGroupTranslator.translate(pdGroup, pipeconf);
197 } catch (PiTranslationException e) {
198 log.warn("Unable to translate multicast group, aborting {} operation: {} [{}]",
199 opType, e.getMessage(), pdGroup);
200 return;
201 }
202 final PiMulticastGroupEntryHandle handle = PiMulticastGroupEntryHandle.of(
203 deviceId, mcGroup);
204 final PiMulticastGroupEntry groupOnDevice = mcGroupMirror.get(handle) == null
205 ? null
206 : mcGroupMirror.get(handle).entry();
207 final Lock lock = STRIPED_LOCKS.get(handle);
208 lock.lock();
209 try {
210 processMcGroup(handle, mcGroup,
211 groupOnDevice, pdGroup, opType);
Carmelo Casconee75b7942017-11-21 17:14:49 -0800212 } finally {
213 lock.unlock();
Yi Tseng82512da2017-08-16 19:46:36 -0700214 }
215 }
216
Carmelo Casconee75b7942017-11-21 17:14:49 -0800217 private void processPiGroup(PiActionGroupHandle handle,
218 PiActionGroup groupToApply,
219 PiActionGroup groupOnDevice,
Yi Tseng8d355132018-04-13 01:40:48 +0800220 Group pdGroup, GroupOperation.Type operationType) {
221 if (operationType == GroupOperation.Type.ADD) {
Carmelo Casconee75b7942017-11-21 17:14:49 -0800222 if (groupOnDevice != null) {
Yi Tseng8d355132018-04-13 01:40:48 +0800223 log.warn("Unable to add group {} since group already on device {}",
224 groupToApply.id(), deviceId);
225 log.debug("To apply: {}", groupToApply);
226 log.debug("On device: {}", groupOnDevice);
227 return;
Carmelo Casconee75b7942017-11-21 17:14:49 -0800228 }
Yi Tseng8d355132018-04-13 01:40:48 +0800229
Carmelo Casconee75b7942017-11-21 17:14:49 -0800230 if (writeGroupToDevice(groupToApply)) {
231 groupMirror.put(handle, groupToApply);
Carmelo Cascone58136812018-07-19 03:40:16 +0200232 groupTranslator.learn(handle, new PiTranslatedEntity<>(
Carmelo Casconee75b7942017-11-21 17:14:49 -0800233 pdGroup, groupToApply, handle));
234 }
Yi Tseng8d355132018-04-13 01:40:48 +0800235 } else if (operationType == GroupOperation.Type.MODIFY) {
236 if (groupOnDevice == null) {
237 log.warn("Group {} does not exists on device {}, can not modify it",
238 groupToApply.id(), deviceId);
239 return;
240 }
Yi Tsengf325a602018-06-27 18:26:33 +0800241 if (driverBoolProperty(CHECK_MIRROR_BEFORE_UPDATE, DEFAULT_CHECK_MIRROR_BEFORE_UPDATE)
Yi Tseng8d355132018-04-13 01:40:48 +0800242 && groupOnDevice.equals(groupToApply)) {
243 // Group on device has the same members, ignore operation.
244 return;
245 }
246 if (modifyGroupFromDevice(groupToApply, groupOnDevice)) {
247 groupMirror.put(handle, groupToApply);
Carmelo Cascone58136812018-07-19 03:40:16 +0200248 groupTranslator.learn(handle,
249 new PiTranslatedEntity<>(pdGroup, groupToApply, handle));
Yi Tseng8d355132018-04-13 01:40:48 +0800250 }
Carmelo Casconee75b7942017-11-21 17:14:49 -0800251 } else {
Yi Tseng8d355132018-04-13 01:40:48 +0800252 if (groupOnDevice == null) {
253 log.warn("Unable to remove group {} from device {} since it does" +
254 "not exists on device.", groupToApply.id(), deviceId);
255 return;
256 }
257 if (deleteGroupFromDevice(groupOnDevice)) {
Carmelo Casconee75b7942017-11-21 17:14:49 -0800258 groupMirror.remove(handle);
Carmelo Cascone58136812018-07-19 03:40:16 +0200259 groupTranslator.forget(handle);
Carmelo Casconee75b7942017-11-21 17:14:49 -0800260 }
261 }
262 }
263
Carmelo Cascone58136812018-07-19 03:40:16 +0200264 private void processMcGroup(PiMulticastGroupEntryHandle handle,
265 PiMulticastGroupEntry groupToApply,
266 PiMulticastGroupEntry groupOnDevice,
267 Group pdGroup, GroupOperation.Type opType) {
268 if (opType == GroupOperation.Type.DELETE) {
269 if (writeMcGroupOnDevice(groupToApply, DELETE)) {
270 mcGroupMirror.remove(handle);
271 mcGroupTranslator.forget(handle);
272 }
273 return;
274 }
275
276 final P4RuntimeClient.WriteOperationType p4OpType =
277 opType == GroupOperation.Type.ADD ? INSERT : MODIFY;
278
279 if (driverBoolProperty(CHECK_MIRROR_BEFORE_UPDATE,
280 DEFAULT_CHECK_MIRROR_BEFORE_UPDATE)
281 && p4OpType == MODIFY
282 && groupOnDevice != null
283 && groupOnDevice.equals(groupToApply)) {
284 // Ignore.
285 return;
286 }
287
288 if (writeMcGroupOnDevice(groupToApply, p4OpType)) {
289 mcGroupMirror.put(handle, groupToApply);
290 mcGroupTranslator.learn(handle, new PiTranslatedEntity<>(
291 pdGroup, groupToApply, handle));
292 }
293 }
294
295 private boolean writeMcGroupOnDevice(PiMulticastGroupEntry group, P4RuntimeClient.WriteOperationType opType) {
296 return getFutureWithDeadline(
297 client.writePreMulticastGroupEntries(
298 Collections.singleton(group), opType),
299 "performing multicast group " + opType, false);
300 }
301
Yi Tseng8d355132018-04-13 01:40:48 +0800302 private boolean modifyGroupFromDevice(PiActionGroup groupToApply, PiActionGroup groupOnDevice) {
303 PiActionProfileId groupProfileId = groupToApply.actionProfileId();
304 Collection<PiActionGroupMember> membersToRemove = Sets.newHashSet(groupOnDevice.members());
305 membersToRemove.removeAll(groupToApply.members());
306 Collection<PiActionGroupMember> membersToAdd = Sets.newHashSet(groupToApply.members());
307 membersToAdd.removeAll(groupOnDevice.members());
308
309 if (!membersToAdd.isEmpty() &&
310 !completeFuture(client.writeActionGroupMembers(groupProfileId, membersToAdd, INSERT, pipeconf),
311 ACT_GRP_MEMS_STR, INSERT_STR)) {
312 // remove what we added
313 completeFuture(client.writeActionGroupMembers(groupProfileId, membersToAdd, DELETE, pipeconf),
314 ACT_GRP_MEMS_STR, INSERT_STR);
315 return false;
316 }
317
318 if (!completeFuture(client.writeActionGroup(groupToApply, MODIFY, pipeconf),
319 ACT_GRP_STR, MODIFY_STR)) {
320 // recover group information
321 completeFuture(client.writeActionGroup(groupOnDevice, MODIFY, pipeconf),
322 ACT_GRP_STR, MODIFY_STR);
323 // remove what we added
324 completeFuture(client.writeActionGroupMembers(groupProfileId, membersToAdd, DELETE, pipeconf),
325 ACT_GRP_MEMS_STR, INSERT_STR);
326 return false;
327 }
328
329 if (!membersToRemove.isEmpty() &&
330 !completeFuture(client.writeActionGroupMembers(groupProfileId, membersToRemove, DELETE, pipeconf),
Carmelo Casconee5b28722018-06-22 17:28:28 +0200331 ACT_GRP_MEMS_STR, DELETE_STR)) {
Yi Tseng8d355132018-04-13 01:40:48 +0800332 // add what we removed
333 completeFuture(client.writeActionGroupMembers(groupProfileId, membersToRemove, INSERT, pipeconf),
334 ACT_GRP_MEMS_STR, DELETE_STR);
335 // recover group information
336 completeFuture(client.writeActionGroup(groupOnDevice, MODIFY, pipeconf),
337 ACT_GRP_STR, MODIFY_STR);
338 // remove what we added
339 completeFuture(client.writeActionGroupMembers(groupProfileId, membersToAdd, DELETE, pipeconf),
340 ACT_GRP_MEMS_STR, INSERT_STR);
341 return false;
342 }
343
344 return true;
345 }
346
Carmelo Casconee75b7942017-11-21 17:14:49 -0800347 private boolean writeGroupToDevice(PiActionGroup groupToApply) {
348 // First insert members, then group.
349 // The operation is deemed successful if both operations are successful.
350 // FIXME: add transactional semantics, i.e. remove members if group fails.
351 final boolean membersSuccess = completeFuture(
Yi Tseng8d355132018-04-13 01:40:48 +0800352 client.writeActionGroupMembers(groupToApply.actionProfileId(),
353 groupToApply.members(),
354 INSERT, pipeconf),
Carmelo Casconee75b7942017-11-21 17:14:49 -0800355 ACT_GRP_MEMS_STR, INSERT_STR);
356 return membersSuccess && completeFuture(
357 client.writeActionGroup(groupToApply, INSERT, pipeconf),
358 ACT_GRP_STR, INSERT_STR);
359 }
360
361 private boolean deleteGroupFromDevice(PiActionGroup piActionGroup) {
362 // First delete group, then members.
363 // The operation is deemed successful if both operations are successful.
364 final boolean groupSuccess = completeFuture(
365 client.writeActionGroup(piActionGroup, DELETE, pipeconf),
366 ACT_GRP_STR, DELETE_STR);
367 return groupSuccess && completeFuture(
Yi Tseng8d355132018-04-13 01:40:48 +0800368 client.writeActionGroupMembers(piActionGroup.actionProfileId(),
369 piActionGroup.members(),
370 DELETE, pipeconf),
Carmelo Casconee75b7942017-11-21 17:14:49 -0800371 ACT_GRP_MEMS_STR, DELETE_STR);
372 }
373
374 private boolean completeFuture(CompletableFuture<Boolean> completableFuture,
375 String topic, String action) {
Carmelo Casconee5b28722018-06-22 17:28:28 +0200376 return getFutureWithDeadline(
377 completableFuture, format("performing %s %s", action, topic), false);
Carmelo Casconee75b7942017-11-21 17:14:49 -0800378 }
379
380 private Stream<Group> streamGroupsFromDevice(PiActionProfileId actProfId) {
Carmelo Casconee5b28722018-06-22 17:28:28 +0200381 // Read PI groups and return original PD one.
382 Collection<PiActionGroup> groups = getFutureWithDeadline(
383 client.dumpGroups(actProfId, pipeconf),
384 "dumping groups", Collections.emptyList());
385 return groups.stream()
386 .map(this::forgeGroupEntry)
387 .filter(Objects::nonNull);
Carmelo Casconee75b7942017-11-21 17:14:49 -0800388 }
389
Carmelo Cascone58136812018-07-19 03:40:16 +0200390 private Collection<Group> getMcGroupsFromDevice() {
391 Collection<PiMulticastGroupEntry> groups = getFutureWithDeadline(
392 client.readAllMulticastGroupEntries(),
393 "dumping multicast groups", Collections.emptyList());
394 return groups.stream()
395 .map(this::forgeMcGroupEntry)
396 .filter(Objects::nonNull)
397 .collect(Collectors.toList());
398 }
399
Carmelo Casconee75b7942017-11-21 17:14:49 -0800400 private Group forgeGroupEntry(PiActionGroup piGroup) {
401 final PiActionGroupHandle handle = PiActionGroupHandle.of(deviceId, piGroup);
Carmelo Cascone58136812018-07-19 03:40:16 +0200402 if (!groupTranslator.lookup(handle).isPresent()) {
Carmelo Casconee75b7942017-11-21 17:14:49 -0800403 log.warn("Missing PI group from translation store: {} - {}:{}",
404 pipeconf.id(), piGroup.actionProfileId(),
405 piGroup.id());
406 return null;
407 }
408 final long life = groupMirror.get(handle) != null
409 ? groupMirror.get(handle).lifeSec() : 0;
Carmelo Cascone58136812018-07-19 03:40:16 +0200410 final Group original = groupTranslator.lookup(handle).get().original();
411 return addedGroup(original, life);
412 }
413
414 private Group forgeMcGroupEntry(PiMulticastGroupEntry mcGroup) {
415 final PiMulticastGroupEntryHandle handle = PiMulticastGroupEntryHandle.of(
416 deviceId, mcGroup);
417 if (!mcGroupTranslator.lookup(handle).isPresent()) {
418 log.warn("Missing PI multicast group {} from translation store",
419 mcGroup.groupId());
420 return null;
421 }
422 final long life = mcGroupMirror.get(handle) != null
423 ? mcGroupMirror.get(handle).lifeSec() : 0;
424 final Group original = mcGroupTranslator.lookup(handle).get().original();
425 return addedGroup(original, life);
426 }
427
428 private Group addedGroup(Group original, long life) {
Carmelo Casconee75b7942017-11-21 17:14:49 -0800429 final DefaultGroup forgedGroup = new DefaultGroup(original.id(), original);
430 forgedGroup.setState(Group.GroupState.ADDED);
431 forgedGroup.setLife(life);
432 return forgedGroup;
433 }
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400434}