2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
3 * Copyright (c) 2024 PANTHEON.tech, s.r.o.
5 * This program and the accompanying materials are made available under the
6 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
7 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.openflowplugin.impl.services.sal;
11 import com.google.common.util.concurrent.FutureCallback;
12 import com.google.common.util.concurrent.Futures;
13 import com.google.common.util.concurrent.ListenableFuture;
14 import com.google.common.util.concurrent.MoreExecutors;
15 import com.google.common.util.concurrent.SettableFuture;
16 import java.util.ArrayList;
17 import java.util.List;
18 import org.opendaylight.openflowplugin.api.OFConstants;
19 import org.opendaylight.openflowplugin.api.openflow.FlowGroupStatus;
20 import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
21 import org.opendaylight.openflowplugin.api.openflow.device.RequestContextStack;
22 import org.opendaylight.openflowplugin.api.openflow.registry.flow.DeviceFlowRegistry;
23 import org.opendaylight.openflowplugin.api.openflow.registry.flow.FlowDescriptor;
24 import org.opendaylight.openflowplugin.api.openflow.registry.flow.FlowRegistryKey;
25 import org.opendaylight.openflowplugin.impl.registry.flow.FlowDescriptorFactory;
26 import org.opendaylight.openflowplugin.impl.registry.flow.FlowRegistryKeyFactory;
27 import org.opendaylight.openflowplugin.impl.util.FlowCreatorUtil;
28 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.ConvertorExecutor;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInputBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInputBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlow;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowInput;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowOutput;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.OriginalFlow;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.UpdatedFlow;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowRef;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.FlowModInputBuilder;
40 import org.opendaylight.yangtools.yang.common.ErrorType;
41 import org.opendaylight.yangtools.yang.common.RpcError;
42 import org.opendaylight.yangtools.yang.common.RpcResult;
43 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
44 import org.opendaylight.yangtools.yang.common.Uint8;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
48 public final class UpdateFlowImpl extends AbstractFlowRpc<UpdateFlowOutput> implements UpdateFlow {
49 private static final Logger LOG = LoggerFactory.getLogger(UpdateFlowImpl.class);
51 public UpdateFlowImpl(final RequestContextStack requestContextStack, final DeviceContext deviceContext,
52 final ConvertorExecutor convertorExecutor) {
53 super(requestContextStack, deviceContext, convertorExecutor, UpdateFlowOutput.class);
57 public ListenableFuture<RpcResult<UpdateFlowOutput>> invoke(final UpdateFlowInput input) {
58 final var updated = input.getUpdatedFlow();
59 final var original = input.getOriginalFlow();
60 final var allFlowMods = new ArrayList<FlowModInputBuilder>();
61 final List<FlowModInputBuilder> ofFlowModInputs;
63 ListenableFuture<RpcResult<UpdateFlowOutput>> future;
64 if (single.canUseSingleLayerSerialization()) {
66 if (!FlowCreatorUtil.canModifyFlow(original, updated, single.getVersion())) {
67 final var objectSettableFuture = SettableFuture.<RpcResult<UpdateFlowOutput>>create();
68 final var listListenableFuture = Futures.successfulAsList(
69 single.handleServiceCall(input.getOriginalFlow()),
70 single.handleServiceCall(input.getUpdatedFlow()));
72 Futures.addCallback(listListenableFuture, new FutureCallback<>() {
74 public void onSuccess(final List<RpcResult<UpdateFlowOutput>> results) {
75 final var errors = new ArrayList<RpcError>();
76 for (var flowModResult : results) {
77 if (flowModResult == null) {
78 errors.add(RpcResultBuilder.newError(
79 ErrorType.PROTOCOL, OFConstants.APPLICATION_TAG,
80 "unexpected flowMod result (null) occurred"));
81 } else if (!flowModResult.isSuccessful()) {
82 errors.addAll(flowModResult.getErrors());
86 final var rpcResultBuilder = errors.isEmpty() ? RpcResultBuilder.<UpdateFlowOutput>success()
87 : RpcResultBuilder.<UpdateFlowOutput>failed().withRpcErrors(errors);
89 objectSettableFuture.set(rpcResultBuilder.build());
93 public void onFailure(final Throwable throwable) {
94 objectSettableFuture.set(RpcResultBuilder.<UpdateFlowOutput>failed().build());
96 }, MoreExecutors.directExecutor());
98 future = objectSettableFuture;
100 future = single.handleServiceCall(input.getUpdatedFlow());
103 if (!FlowCreatorUtil.canModifyFlow(original, updated, multi.getVersion())) {
104 // We would need to remove original and add updated.
107 final RemoveFlowInputBuilder removeflow = new RemoveFlowInputBuilder(original);
108 final List<FlowModInputBuilder> ofFlowRemoveInput = multi.toFlowModInputs(removeflow.build());
109 // remove flow should be the first
110 allFlowMods.addAll(ofFlowRemoveInput);
111 final AddFlowInputBuilder addFlowInputBuilder = new AddFlowInputBuilder(updated);
112 ofFlowModInputs = multi.toFlowModInputs(addFlowInputBuilder.build());
114 ofFlowModInputs = multi.toFlowModInputs(updated);
117 allFlowMods.addAll(ofFlowModInputs);
119 future = multi.processFlowModInputBuilders(allFlowMods);
122 Futures.addCallback(future, new UpdateFlowCallback(input), MoreExecutors.directExecutor());
127 private final class UpdateFlowCallback implements FutureCallback<RpcResult<UpdateFlowOutput>> {
128 private final UpdateFlowInput input;
130 private UpdateFlowCallback(final UpdateFlowInput input) {
135 public void onSuccess(final RpcResult<UpdateFlowOutput> updateFlowOutputRpcResult) {
136 final DeviceFlowRegistry deviceFlowRegistry = deviceContext.getDeviceFlowRegistry();
137 final UpdatedFlow updated = input.getUpdatedFlow();
138 final OriginalFlow original = input.getOriginalFlow();
139 final FlowRegistryKey origFlowRegistryKey =
140 FlowRegistryKeyFactory.create(deviceContext.getDeviceInfo().getVersion(), original);
141 final FlowRegistryKey updatedFlowRegistryKey =
142 FlowRegistryKeyFactory.create(deviceContext.getDeviceInfo().getVersion(), updated);
143 final FlowDescriptor origFlowDescriptor = deviceFlowRegistry.retrieveDescriptor(origFlowRegistryKey);
145 final boolean isUpdate = origFlowDescriptor != null;
146 final FlowDescriptor updatedFlowDescriptor;
147 final FlowRef flowRef = input.getFlowRef();
148 if (flowRef != null) {
149 final Uint8 tableId = updated.getTableId();
150 final FlowId flowId = flowRef.getValue().firstKeyOf(Flow.class).getId();
151 // FIXME: this does not look right, we probably want better integration
152 deviceFlowRegistry.appendHistoryFlow(flowId, tableId, FlowGroupStatus.MODIFIED);
154 updatedFlowDescriptor = FlowDescriptorFactory.create(tableId, flowId);
155 } else if (isUpdate) {
156 updatedFlowDescriptor = origFlowDescriptor;
158 deviceFlowRegistry.store(updatedFlowRegistryKey);
159 updatedFlowDescriptor = deviceFlowRegistry.retrieveDescriptor(updatedFlowRegistryKey);
163 deviceFlowRegistry.addMark(origFlowRegistryKey);
164 deviceFlowRegistry.storeDescriptor(updatedFlowRegistryKey, updatedFlowDescriptor);
169 public void onFailure(final Throwable throwable) {
170 LOG.warn("Service call for updating flow={} failed", input, throwable);