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.Futures;
18 import com.google.common.util.concurrent.JdkFutureAdapters;
19 import com.google.common.util.concurrent.ListenableFuture;
20 import io.netty.util.Timeout;
21 import io.netty.util.TimerTask;
22 import java.util.concurrent.Future;
23 import java.util.concurrent.Semaphore;
24 import java.util.concurrent.TimeUnit;
25 import javax.annotation.Nullable;
26 import org.opendaylight.controller.md.sal.common.api.clustering.CandidateAlreadyRegisteredException;
27 import org.opendaylight.controller.md.sal.common.api.clustering.Entity;
28 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipCandidateRegistration;
29 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
30 import org.opendaylight.openflowplugin.api.OFConstants;
31 import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
32 import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
33 import org.opendaylight.openflowplugin.api.openflow.device.DeviceState;
34 import org.opendaylight.openflowplugin.api.openflow.device.RequestContext;
35 import org.opendaylight.openflowplugin.api.openflow.role.RoleContext;
36 import org.opendaylight.openflowplugin.impl.rpc.AbstractRequestContext;
37 import org.opendaylight.openflowplugin.impl.services.SalRoleServiceImpl;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.OfpRole;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SalRoleService;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SetRoleInput;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SetRoleInputBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SetRoleOutput;
44 import org.opendaylight.yangtools.yang.common.RpcResult;
45 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
50 * Created by kramesha on 9/12/15.
52 public class RoleContextImpl implements RoleContext {
53 private static final Logger LOG = LoggerFactory.getLogger(RoleContextImpl.class);
55 private final EntityOwnershipService entityOwnershipService;
56 private EntityOwnershipCandidateRegistration entityOwnershipCandidateRegistration;
57 private final DeviceContext deviceContext;
58 private final Entity entity;
59 private SalRoleService salRoleService;
61 private EntityOwnershipCandidateRegistration txEntityOwnershipCandidateRegistration;
62 private final Entity txEntity;
64 private final Semaphore mainCandidateGuard = new Semaphore(1, true);
65 private final Semaphore txCandidateGuard = new Semaphore(1, true);
66 private volatile ROLE_CONTEXT_STATE state;
67 private volatile boolean txLockOwned;
68 private volatile OfpRole propagatingRole;
70 public RoleContextImpl(final DeviceContext deviceContext, final EntityOwnershipService entityOwnershipService,
71 final Entity entity, final Entity txEnitity) {
72 this.entityOwnershipService = Preconditions.checkNotNull(entityOwnershipService);
73 this.deviceContext = Preconditions.checkNotNull(deviceContext);
74 this.entity = Preconditions.checkNotNull(entity);
75 this.txEntity = Preconditions.checkNotNull(txEnitity);
77 salRoleService = new SalRoleServiceImpl(this, deviceContext);
81 public void initialization() throws CandidateAlreadyRegisteredException {
82 state = ROLE_CONTEXT_STATE.STARTING;
83 LOG.debug("Initialization requestOpenflowEntityOwnership for entity {}", entity);
84 entityOwnershipCandidateRegistration = entityOwnershipService.registerCandidate(entity);
85 LOG.debug("RoleContextImpl : Candidate registered with ownership service for device :{}", deviceContext
86 .getPrimaryConnectionContext().getNodeId().getValue());
90 public ListenableFuture<Void> onRoleChanged(final OfpRole oldRole, final OfpRole newRole) {
91 LOG.trace("onRoleChanged method call for Entity {}", entity);
93 if (!isDeviceConnected()) {
94 // this can happen as after the disconnect, we still get a last messsage from EntityOwnershipService.
95 LOG.info("Device {} is disconnected from this node. Hence not attempting a role change.",
96 deviceContext.getPrimaryConnectionContext().getNodeId());
97 LOG.debug("SetRole cancelled for entity [{}], reason = device disconnected.", entity);
98 return Futures.immediateFailedFuture(new Exception(
99 "Device disconnected - stopped by setRole: " + deviceContext
100 .getPrimaryConnectionContext().getNodeId()));
103 LOG.debug("Role change received from ownership listener from {} to {} for device:{}", oldRole, newRole,
104 deviceContext.getPrimaryConnectionContext().getNodeId());
106 final SetRoleInput setRoleInput = (new SetRoleInputBuilder())
107 .setControllerRole(newRole)
108 .setNode(new NodeRef(deviceContext.getDeviceState().getNodeInstanceIdentifier()))
111 final Future<RpcResult<SetRoleOutput>> setRoleOutputFuture = salRoleService.setRole(setRoleInput);
113 return Futures.transform(JdkFutureAdapters.listenInPoolThread(setRoleOutputFuture),
114 new AsyncFunction<RpcResult<SetRoleOutput>, Void>() {
116 public ListenableFuture<Void> apply(final RpcResult<SetRoleOutput> setRoleOutputRpcResult) throws Exception {
117 LOG.debug("Rolechange {} successful made on switch :{}", newRole, deviceContext.getDeviceState().getNodeId());
118 final ListenableFuture<Void> nextStepFuture;
121 if (OfpRole.BECOMESLAVE.equals(newRole)) {
122 getDeviceState().setRole(newRole);
123 nextStepFuture = Futures.immediateFuture(null);
124 } else if (OfpRole.BECOMEMASTER.equals(newRole)) {
125 nextStepFuture = deviceContext.onClusterRoleChange(newRole);
127 nextStepFuture = Futures.immediateFuture(null);
132 nextStepFuture = deviceContext.onClusterRoleChange(newRole);
136 nextStepFuture = Futures.immediateFuture(null);
140 return nextStepFuture;
146 public void setupTxCandidate() throws CandidateAlreadyRegisteredException {
147 LOG.debug("setupTxCandidate for entity {} and Transaction entity {}", entity, txEntity);
148 Verify.verify(txEntity != null);
150 txEntityOwnershipCandidateRegistration = entityOwnershipService.registerCandidate(txEntity);
154 public void close() {
155 if (entityOwnershipCandidateRegistration != null) {
156 LOG.debug("Closing EntityOwnershipCandidateRegistration for {}", entity);
157 entityOwnershipCandidateRegistration.close();
159 promoteStateToTearingDown();
163 public Entity getEntity() {
168 public Entity getTxEntity() {
172 private boolean isDeviceConnected() {
173 return ConnectionContext.CONNECTION_STATE.WORKING.equals(
174 deviceContext.getPrimaryConnectionContext().getConnectionState());
179 public <T> RequestContext<T> createRequestContext() {
180 final AbstractRequestContext<T> ret = new AbstractRequestContext<T>(deviceContext.getReservedXid()) {
182 public void close() {
189 void setSalRoleService(final SalRoleService salRoleService) {
190 this.salRoleService = salRoleService;
194 public DeviceState getDeviceState() {
195 return deviceContext.getDeviceState();
199 public void suspendTxCandidate() {
200 if (txEntityOwnershipCandidateRegistration != null) {
201 txEntityOwnershipCandidateRegistration.close();
202 txEntityOwnershipCandidateRegistration = null;
207 public DeviceContext getDeviceContext() {
208 return deviceContext;
212 public Semaphore getMainCandidateGuard() {
213 return mainCandidateGuard;
217 public Semaphore getTxCandidateGuard() {
218 return txCandidateGuard;
222 public ROLE_CONTEXT_STATE getState() {
227 public boolean isTxLockOwned() {
232 public void setTxLockOwned(final boolean txLockOwned) {
233 this.txLockOwned = txLockOwned;
236 private void promoteStateToTearingDown() {
237 state = ROLE_CONTEXT_STATE.TEARING_DOWN;
241 public void promoteStateToWorking() {
242 state = ROLE_CONTEXT_STATE.WORKING;
246 public OfpRole getPropagatingRole() {
247 return propagatingRole;
251 public void setPropagatingRole(final OfpRole propagatingRole) {
252 this.propagatingRole = propagatingRole;
255 private ListenableFuture<Void> sendRoleChangeToDevice(final OfpRole newRole, final AsyncFunction<RpcResult<SetRoleOutput>, Void> function) {
256 LOG.debug("Send new Role {} to Device {}", newRole, deviceContext.getDeviceState().getNodeId());
257 final Future<RpcResult<SetRoleOutput>> setRoleOutputFuture;
258 if (deviceContext.getDeviceState().getFeatures().getVersion() < OFConstants.OFP_VERSION_1_3) {
259 LOG.debug("Device OF version {} not support ROLE", deviceContext.getDeviceState().getFeatures().getVersion());
260 setRoleOutputFuture = Futures.immediateFuture(RpcResultBuilder.<SetRoleOutput> success().build());
262 final SetRoleInput setRoleInput = (new SetRoleInputBuilder()).setControllerRole(newRole)
263 .setNode(new NodeRef(deviceContext.getDeviceState().getNodeInstanceIdentifier())).build();
264 setRoleOutputFuture = salRoleService.setRole(setRoleInput);
265 final TimerTask timerTask = new TimerTask() {
268 public void run(final Timeout timeout) throws Exception {
269 if (!setRoleOutputFuture.isDone()) {
270 LOG.info("New Role {} was not propagated to device {} during 10 sec. Close connection immediately.",
271 newRole, deviceContext.getDeviceState().getNodeId());
272 deviceContext.close();
276 deviceContext.getTimer().newTimeout(timerTask, 10, TimeUnit.SECONDS);
278 return Futures.transform(JdkFutureAdapters.listenInPoolThread(setRoleOutputFuture), function);