2 * Copyright (c) 2015 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.impl.role;
10 import javax.annotation.Nullable;
11 import java.util.concurrent.Future;
13 import com.google.common.annotations.VisibleForTesting;
14 import com.google.common.base.Preconditions;
15 import com.google.common.base.Verify;
16 import com.google.common.util.concurrent.AsyncFunction;
17 import com.google.common.util.concurrent.FutureCallback;
18 import com.google.common.util.concurrent.Futures;
19 import com.google.common.util.concurrent.JdkFutureAdapters;
20 import com.google.common.util.concurrent.ListenableFuture;
21 import io.netty.util.Timeout;
22 import io.netty.util.TimerTask;
23 import java.util.concurrent.Future;
24 import java.util.concurrent.Semaphore;
25 import java.util.concurrent.TimeUnit;
26 import javax.annotation.Nullable;
27 import org.opendaylight.controller.md.sal.common.api.clustering.CandidateAlreadyRegisteredException;
28 import org.opendaylight.controller.md.sal.common.api.clustering.Entity;
29 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipCandidateRegistration;
30 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
31 import org.opendaylight.openflowplugin.api.OFConstants;
32 import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
33 import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
34 import org.opendaylight.openflowplugin.api.openflow.device.DeviceState;
35 import org.opendaylight.openflowplugin.api.openflow.device.RequestContext;
36 import org.opendaylight.openflowplugin.api.openflow.role.RoleContext;
37 import org.opendaylight.openflowplugin.impl.rpc.AbstractRequestContext;
38 import org.opendaylight.openflowplugin.impl.services.SalRoleServiceImpl;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.OfpRole;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SalRoleService;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SetRoleInput;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SetRoleInputBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SetRoleOutput;
45 import org.opendaylight.yangtools.yang.common.RpcResult;
46 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
51 * Created by kramesha on 9/12/15.
53 public class RoleContextImpl implements RoleContext {
54 private static final Logger LOG = LoggerFactory.getLogger(RoleContextImpl.class);
56 private final EntityOwnershipService entityOwnershipService;
57 private EntityOwnershipCandidateRegistration entityOwnershipCandidateRegistration;
58 private final DeviceContext deviceContext;
59 private final Entity entity;
60 private SalRoleService salRoleService;
62 private EntityOwnershipCandidateRegistration txEntityOwnershipCandidateRegistration;
63 private final Entity txEntity;
65 private final Semaphore mainCandidateGuard = new Semaphore(1, true);
66 private final Semaphore txCandidateGuard = new Semaphore(1, true);
68 public RoleContextImpl(final DeviceContext deviceContext, final EntityOwnershipService entityOwnershipService,
69 final Entity entity, final Entity txEnitity) {
70 this.entityOwnershipService = Preconditions.checkNotNull(entityOwnershipService);
71 this.deviceContext = Preconditions.checkNotNull(deviceContext);
72 this.entity = Preconditions.checkNotNull(entity);
73 this.txEntity = Preconditions.checkNotNull(txEnitity);
75 salRoleService = new SalRoleServiceImpl(this, deviceContext);
79 public void initialization() throws CandidateAlreadyRegisteredException {
80 LOG.debug("Initialization RoleContext for Node {}", deviceContext.getDeviceState().getNodeId());
81 final AsyncFunction<RpcResult<SetRoleOutput>, Void> initFunction = new AsyncFunction<RpcResult<SetRoleOutput>, Void>() {
83 public ListenableFuture<Void> apply(final RpcResult<SetRoleOutput> input) throws Exception {
84 LOG.debug("Initialization request OpenflowEntityOwnership for entity {}", entity);
85 getDeviceState().setRole(OfpRole.BECOMESLAVE);
86 entityOwnershipCandidateRegistration = entityOwnershipService.registerCandidate(entity);
87 LOG.debug("RoleContextImpl : Candidate registered with ownership service for device :{}", deviceContext
88 .getPrimaryConnectionContext().getNodeId().getValue());
89 return Futures.immediateFuture(null);
92 final ListenableFuture<Void> roleChange = sendRoleChangeToDevice(OfpRole.BECOMESLAVE, initFunction);
93 Futures.addCallback(roleChange, new FutureCallback<Void>() {
96 public void onSuccess(final Void result) {
97 LOG.debug("Initial RoleContext for Node {} is successful", deviceContext.getDeviceState().getNodeId());
101 public void onFailure(final Throwable t) {
102 LOG.warn("Initial RoleContext for Node {} fail", deviceContext.getDeviceState().getNodeId(), t);
103 deviceContext.close();
109 public ListenableFuture<Void> onRoleChanged(final OfpRole oldRole, final OfpRole newRole) {
110 LOG.trace("onRoleChanged method call for Entity {}", entity);
112 if (!isDeviceConnected()) {
113 // this can happen as after the disconnect, we still get a last messsage from EntityOwnershipService.
114 LOG.info("Device {} is disconnected from this node. Hence not attempting a role change.",
115 deviceContext.getPrimaryConnectionContext().getNodeId());
116 LOG.debug("SetRole cancelled for entity [{}], reason = device disconnected.", entity);
117 return Futures.immediateFailedFuture(new Exception(
118 "Device disconnected - stopped by setRole: " + deviceContext
119 .getPrimaryConnectionContext().getNodeId()));
122 LOG.debug("Role change received from ownership listener from {} to {} for device:{}", oldRole, newRole,
123 deviceContext.getPrimaryConnectionContext().getNodeId());
125 final AsyncFunction<RpcResult<SetRoleOutput>, Void> roleChangeFunction = new AsyncFunction<RpcResult<SetRoleOutput>, Void>() {
127 public ListenableFuture<Void> apply(final RpcResult<SetRoleOutput> setRoleOutputRpcResult) throws Exception {
128 LOG.debug("Role change {} successful made on switch :{}", newRole, deviceContext.getDeviceState()
130 getDeviceState().setRole(newRole);
131 return deviceContext.onClusterRoleChange(oldRole, newRole);
134 return sendRoleChangeToDevice(newRole, roleChangeFunction);
138 public void setupTxCandidate() throws CandidateAlreadyRegisteredException {
139 LOG.debug("setupTxCandidate for entity {} and Transaction entity {}", entity, txEntity);
140 Verify.verify(txEntity != null);
142 txEntityOwnershipCandidateRegistration = entityOwnershipService.registerCandidate(txEntity);
146 public void close() {
147 if (entityOwnershipCandidateRegistration != null) {
148 LOG.debug("Closing EntityOwnershipCandidateRegistration for {}", entity);
149 entityOwnershipCandidateRegistration.close();
154 public Entity getEntity() {
159 public Entity getTxEntity() {
163 private boolean isDeviceConnected() {
164 return ConnectionContext.CONNECTION_STATE.WORKING.equals(
165 deviceContext.getPrimaryConnectionContext().getConnectionState());
170 public <T> RequestContext<T> createRequestContext() {
171 final AbstractRequestContext<T> ret = new AbstractRequestContext<T>(deviceContext.reservedXidForDeviceMessage()) {
173 public void close() {
180 void setSalRoleService(final SalRoleService salRoleService) {
181 this.salRoleService = salRoleService;
185 public DeviceState getDeviceState() {
186 return deviceContext.getDeviceState();
190 public void suspendTxCandidate() {
191 if (txEntityOwnershipCandidateRegistration != null) {
192 txEntityOwnershipCandidateRegistration.close();
193 txEntityOwnershipCandidateRegistration = null;
198 public DeviceContext getDeviceContext() {
199 return deviceContext;
203 public Semaphore getMainCandidateGuard() {
204 return mainCandidateGuard;
208 public Semaphore getTxCandidateGuard() {
209 return txCandidateGuard;
212 private ListenableFuture<Void> sendRoleChangeToDevice(final OfpRole newRole, final AsyncFunction<RpcResult<SetRoleOutput>, Void> function) {
213 LOG.debug("Send new Role {} to Device {}", newRole, deviceContext.getDeviceState().getNodeId());
214 final Future<RpcResult<SetRoleOutput>> setRoleOutputFuture;
215 if (deviceContext.getDeviceState().getFeatures().getVersion() < OFConstants.OFP_VERSION_1_3) {
216 LOG.debug("Device OF version {} not support ROLE", deviceContext.getDeviceState().getFeatures().getVersion());
217 setRoleOutputFuture = Futures.immediateFuture(RpcResultBuilder.<SetRoleOutput> success().build());
219 final SetRoleInput setRoleInput = (new SetRoleInputBuilder()).setControllerRole(newRole)
220 .setNode(new NodeRef(deviceContext.getDeviceState().getNodeInstanceIdentifier())).build();
221 setRoleOutputFuture = salRoleService.setRole(setRoleInput);
222 final TimerTask timerTask = new TimerTask() {
225 public void run(final Timeout timeout) throws Exception {
226 if (!setRoleOutputFuture.isDone()) {
227 LOG.info("New Role {} was not propagated to device {} during 10 sec. Close connection immediately.",
228 newRole, deviceContext.getDeviceState().getNodeId());
229 deviceContext.close();
233 deviceContext.getTimer().newTimeout(timerTask, 10, TimeUnit.SECONDS);
235 return Futures.transform(JdkFutureAdapters.listenInPoolThread(setRoleOutputFuture), function);