2 * Copyright (c) 2014, 2017 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.openflowplugin.applications.frm.impl;
10 import com.google.common.base.Preconditions;
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 java.util.concurrent.Future;
16 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
17 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
18 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
19 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
20 import org.opendaylight.infrautils.utils.concurrent.JdkFutures;
21 import org.opendaylight.openflowplugin.applications.frm.ForwardingRulesManager;
22 import org.opendaylight.openflowplugin.common.wait.SimpleTaskRetryLooper;
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.AddGroupInput;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.AddGroupInputBuilder;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.AddGroupOutput;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.RemoveGroupInputBuilder;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.RemoveGroupOutput;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.UpdateGroupInput;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.UpdateGroupInputBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.UpdateGroupOutput;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.OriginalGroupBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.UpdatedGroupBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupRef;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.StaleGroup;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.StaleGroupBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.StaleGroupKey;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
45 import org.opendaylight.yangtools.concepts.ListenerRegistration;
46 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
47 import org.opendaylight.yangtools.yang.common.RpcResult;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
52 * GroupForwarder It implements
53 * {@link org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener}
54 * for WildCardedPath to {@link Group} and ForwardingRulesCommiter interface for
55 * methods: add, update and remove {@link Group} processing for
56 * {@link org.opendaylight.controller.md.sal.binding.api.DataTreeModification}.
58 public class GroupForwarder extends AbstractListeningCommiter<Group> {
60 private static final Logger LOG = LoggerFactory.getLogger(GroupForwarder.class);
61 private final DataBroker dataBroker;
62 private ListenerRegistration<GroupForwarder> listenerRegistration;
64 @SuppressWarnings("IllegalCatch")
65 public GroupForwarder(final ForwardingRulesManager manager, final DataBroker db) {
67 dataBroker = Preconditions.checkNotNull(db, "DataBroker can not be null!");
68 final DataTreeIdentifier<Group> treeId = new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION,
72 SimpleTaskRetryLooper looper = new SimpleTaskRetryLooper(ForwardingRulesManagerImpl.STARTUP_LOOP_TICK,
73 ForwardingRulesManagerImpl.STARTUP_LOOP_MAX_RETRIES);
74 listenerRegistration = looper
75 .loopUntilNoException(() -> db.registerDataTreeChangeListener(treeId, GroupForwarder.this));
76 } catch (final Exception e) {
77 LOG.warn("FRM Group DataTreeChange listener registration fail!");
78 LOG.debug("FRM Group DataTreeChange listener registration fail ..", e);
79 throw new IllegalStateException("GroupForwarder startup fail! System needs restart.", e);
85 if (listenerRegistration != null) {
86 listenerRegistration.close();
87 listenerRegistration = null;
92 protected InstanceIdentifier<Group> getWildCardPath() {
93 return InstanceIdentifier.create(Nodes.class).child(Node.class).augmentation(FlowCapableNode.class)
98 public void remove(final InstanceIdentifier<Group> identifier, final Group removeDataObj,
99 final InstanceIdentifier<FlowCapableNode> nodeIdent) {
101 final Group group = removeDataObj;
102 final RemoveGroupInputBuilder builder = new RemoveGroupInputBuilder(group);
103 final NodeId nodeId = getNodeIdFromNodeIdentifier(nodeIdent);
105 builder.setNode(new NodeRef(nodeIdent.firstIdentifierOf(Node.class)));
106 builder.setGroupRef(new GroupRef(identifier));
107 builder.setTransactionUri(new Uri(provider.getNewTransactionId()));
109 final ListenableFuture<RpcResult<RemoveGroupOutput>> resultFuture =
110 this.provider.getSalGroupService().removeGroup(builder.build());
111 Futures.addCallback(resultFuture,
112 new RemoveGroupCallBack(removeDataObj.getGroupId().getValue(), nodeId),
113 MoreExecutors.directExecutor());
114 JdkFutures.addErrorLogging(resultFuture, LOG, "removeGroup");
117 // TODO: Pull this into ForwardingRulesCommiter and override it here
119 public Future<RpcResult<RemoveGroupOutput>> removeWithResult(final InstanceIdentifier<Group> identifier,
120 final Group removeDataObj, final InstanceIdentifier<FlowCapableNode> nodeIdent) {
122 final Group group = removeDataObj;
123 final RemoveGroupInputBuilder builder = new RemoveGroupInputBuilder(group);
125 builder.setNode(new NodeRef(nodeIdent.firstIdentifierOf(Node.class)));
126 builder.setGroupRef(new GroupRef(identifier));
127 builder.setTransactionUri(new Uri(provider.getNewTransactionId()));
128 return this.provider.getSalGroupService().removeGroup(builder.build());
132 public void update(final InstanceIdentifier<Group> identifier, final Group original, final Group update,
133 final InstanceIdentifier<FlowCapableNode> nodeIdent) {
135 final Group originalGroup = original;
136 final Group updatedGroup = update;
137 final UpdateGroupInputBuilder builder = new UpdateGroupInputBuilder();
138 final NodeId nodeId = getNodeIdFromNodeIdentifier(nodeIdent);
139 builder.setNode(new NodeRef(nodeIdent.firstIdentifierOf(Node.class)));
140 builder.setGroupRef(new GroupRef(identifier));
141 builder.setTransactionUri(new Uri(provider.getNewTransactionId()));
142 builder.setUpdatedGroup(new UpdatedGroupBuilder(updatedGroup).build());
143 builder.setOriginalGroup(new OriginalGroupBuilder(originalGroup).build());
144 nodeConfigurator.enqueueJob(nodeId.getValue(), () -> {
145 UpdateGroupInput updateGroupInput = builder.build();
146 final ListenableFuture<RpcResult<UpdateGroupOutput>> resultFuture;
147 resultFuture = this.provider.getSalGroupService().updateGroup(updateGroupInput);
148 JdkFutures.addErrorLogging(resultFuture, LOG, "updateGroup");
149 Futures.addCallback(resultFuture,
150 new UpdateGroupCallBack(updateGroupInput.getOriginalGroup().getGroupId().getValue(), nodeId),
151 MoreExecutors.directExecutor());
157 public Future<RpcResult<AddGroupOutput>> add(final InstanceIdentifier<Group> identifier, final Group addDataObj,
158 final InstanceIdentifier<FlowCapableNode> nodeIdent) {
160 final Group group = addDataObj;
161 final AddGroupInputBuilder builder = new AddGroupInputBuilder(group);
162 final NodeId nodeId = getNodeIdFromNodeIdentifier(nodeIdent);
164 builder.setNode(new NodeRef(nodeIdent.firstIdentifierOf(Node.class)));
165 builder.setGroupRef(new GroupRef(identifier));
166 builder.setTransactionUri(new Uri(provider.getNewTransactionId()));
167 AddGroupInput addGroupInput = builder.build();
168 return nodeConfigurator
169 .enqueueJob(nodeId.getValue(), () -> {
170 final ListenableFuture<RpcResult<AddGroupOutput>> resultFuture;
171 resultFuture = this.provider.getSalGroupService().addGroup(addGroupInput);
172 Futures.addCallback(resultFuture,
173 new AddGroupCallBack(addGroupInput.getGroupId().getValue(), nodeId),
174 MoreExecutors.directExecutor());
180 public void createStaleMarkEntity(InstanceIdentifier<Group> identifier, Group del,
181 InstanceIdentifier<FlowCapableNode> nodeIdent) {
182 LOG.debug("Creating Stale-Mark entry for the switch {} for Group {} ", nodeIdent.toString(), del.toString());
183 StaleGroup staleGroup = makeStaleGroup(identifier, del, nodeIdent);
184 persistStaleGroup(staleGroup, nodeIdent);
188 private StaleGroup makeStaleGroup(InstanceIdentifier<Group> identifier, Group del,
189 InstanceIdentifier<FlowCapableNode> nodeIdent) {
190 StaleGroupBuilder staleGroupBuilder = new StaleGroupBuilder(del);
191 return staleGroupBuilder.setGroupId(del.getGroupId()).build();
194 private void persistStaleGroup(StaleGroup staleGroup, InstanceIdentifier<FlowCapableNode> nodeIdent) {
195 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
196 writeTransaction.put(LogicalDatastoreType.CONFIGURATION, getStaleGroupInstanceIdentifier(staleGroup, nodeIdent),
199 ListenableFuture<Void> submitFuture = writeTransaction.submit();
200 handleStaleGroupResultFuture(submitFuture);
203 private void handleStaleGroupResultFuture(ListenableFuture<Void> submitFuture) {
204 Futures.addCallback(submitFuture, new FutureCallback<Void>() {
206 public void onSuccess(Void result) {
207 LOG.debug("Stale Group creation success");
211 public void onFailure(Throwable throwable) {
212 LOG.error("Stale Group creation failed {}", throwable);
214 }, MoreExecutors.directExecutor());
218 private InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.group
219 .types.rev131018.groups.StaleGroup> getStaleGroupInstanceIdentifier(
220 StaleGroup staleGroup, InstanceIdentifier<FlowCapableNode> nodeIdent) {
221 return nodeIdent.child(StaleGroup.class, new StaleGroupKey(new GroupId(staleGroup.getGroupId())));
224 private final class AddGroupCallBack implements FutureCallback<RpcResult<AddGroupOutput>> {
225 private final Long groupId;
226 private final NodeId nodeId;
228 private AddGroupCallBack(final Long groupId, final NodeId nodeId) {
229 this.groupId = groupId;
230 this.nodeId = nodeId;
234 public void onSuccess(RpcResult<AddGroupOutput> result) {
235 if (result.isSuccessful()) {
236 provider.getDevicesGroupRegistry().storeGroup(nodeId, groupId);
237 LOG.debug("Group add with id {} finished without error for node {}", groupId, nodeId);
239 LOG.debug("Group add with id {} failed for node {} with error {}", groupId, nodeId,
240 result.getErrors().toString());
245 public void onFailure(Throwable throwable) {
246 LOG.error("Service call for adding group {} failed for node with error {}", groupId, nodeId, throwable);
250 private final class UpdateGroupCallBack implements FutureCallback<RpcResult<UpdateGroupOutput>> {
251 private final Long groupId;
252 private final NodeId nodeId;
254 private UpdateGroupCallBack(final Long groupId, final NodeId nodeId) {
255 this.groupId = groupId;
256 this.nodeId = nodeId;
259 public void onSuccess(RpcResult<UpdateGroupOutput> result) {
260 if (result.isSuccessful()) {
261 provider.getDevicesGroupRegistry().storeGroup(nodeId, groupId);
262 LOG.debug("Group update with id {} finished without error for node {}", groupId, nodeId);
264 LOG.debug("Group update with id {} failed for node {} with error {}", groupId, nodeId,
265 result.getErrors().toString());
270 public void onFailure(Throwable throwable) {
271 LOG.error("Service call for updating group {} failed for node {} with error {}", groupId, nodeId,
276 private final class RemoveGroupCallBack implements FutureCallback<RpcResult<RemoveGroupOutput>> {
277 private final Long groupId;
278 private final NodeId nodeId;
280 private RemoveGroupCallBack(final Long groupId, final NodeId nodeId) {
281 this.groupId = groupId;
282 this.nodeId = nodeId;
286 public void onSuccess(RpcResult<RemoveGroupOutput> result) {
287 if (result.isSuccessful()) {
288 LOG.debug("Group remove with id {} finished without error for node {}", groupId, nodeId);
289 provider.getDevicesGroupRegistry().removeGroup(nodeId, groupId);
291 LOG.debug("Group remove with id {} failed for node {} with error {}", groupId, nodeId,
292 result.getErrors().toString());
297 public void onFailure(Throwable throwable) {
298 LOG.error("Service call for removing group {} failed for node with error {}", groupId, nodeId, throwable);