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 :{}",
86 deviceContext.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());
107 final AsyncFunction<RpcResult<SetRoleOutput>, Void> roleChangeRpcFunction = new AsyncFunction<RpcResult<SetRoleOutput>, Void>() {
109 public ListenableFuture<Void> apply(final RpcResult<SetRoleOutput> setRoleOutputRpcResult) throws Exception {
110 LOG.debug("Rolechange {} successful made on switch :{}", newRole, deviceContext.getDeviceState().getNodeId());
111 final ListenableFuture<Void> nextStepFuture;
114 if (OfpRole.BECOMESLAVE.equals(newRole)) {
115 getDeviceState().setRole(newRole);
116 nextStepFuture = Futures.immediateFuture(null);
117 } else if (OfpRole.BECOMEMASTER.equals(newRole)) {
118 nextStepFuture = deviceContext.onClusterRoleChange(oldRole, newRole);
120 nextStepFuture = Futures.immediateFuture(null);
125 nextStepFuture = deviceContext.onClusterRoleChange(oldRole, newRole);
129 nextStepFuture = Futures.immediateFuture(null);
133 return nextStepFuture;
137 return sendRoleChangeToDevice(newRole, roleChangeRpcFunction);
141 public void setupTxCandidate() throws CandidateAlreadyRegisteredException {
142 LOG.debug("setupTxCandidate for entity {} and Transaction entity {}", entity, txEntity);
143 Verify.verify(txEntity != null);
145 txEntityOwnershipCandidateRegistration = entityOwnershipService.registerCandidate(txEntity);
149 public void close() {
150 if (entityOwnershipCandidateRegistration != null) {
151 LOG.debug("Closing EntityOwnershipCandidateRegistration for {}", entity);
152 entityOwnershipCandidateRegistration.close();
154 promoteStateToTearingDown();
158 public Entity getEntity() {
163 public Entity getTxEntity() {
167 private boolean isDeviceConnected() {
168 return ConnectionContext.CONNECTION_STATE.WORKING.equals(
169 deviceContext.getPrimaryConnectionContext().getConnectionState());
174 public <T> RequestContext<T> createRequestContext() {
175 final AbstractRequestContext<T> ret = new AbstractRequestContext<T>(deviceContext.reservedXidForDeviceMessage()) {
177 public void close() {
184 void setSalRoleService(final SalRoleService salRoleService) {
185 this.salRoleService = salRoleService;
189 public DeviceState getDeviceState() {
190 return deviceContext.getDeviceState();
194 public void suspendTxCandidate() {
195 if (txEntityOwnershipCandidateRegistration != null) {
196 txEntityOwnershipCandidateRegistration.close();
197 txEntityOwnershipCandidateRegistration = null;
202 public DeviceContext getDeviceContext() {
203 return deviceContext;
207 public Semaphore getMainCandidateGuard() {
208 return mainCandidateGuard;
212 public Semaphore getTxCandidateGuard() {
213 return txCandidateGuard;
217 public ROLE_CONTEXT_STATE getState() {
222 public boolean isTxLockOwned() {
227 public void setTxLockOwned(final boolean txLockOwned) {
228 this.txLockOwned = txLockOwned;
231 private void promoteStateToTearingDown() {
232 state = ROLE_CONTEXT_STATE.TEARING_DOWN;
236 public void promoteStateToWorking() {
237 state = ROLE_CONTEXT_STATE.WORKING;
241 public OfpRole getPropagatingRole() {
242 return propagatingRole;
246 public void setPropagatingRole(final OfpRole propagatingRole) {
247 this.propagatingRole = propagatingRole;
250 private ListenableFuture<Void> sendRoleChangeToDevice(final OfpRole newRole, final AsyncFunction<RpcResult<SetRoleOutput>, Void> function) {
251 LOG.debug("Send new Role {} to Device {}", newRole, deviceContext.getDeviceState().getNodeId());
252 final Future<RpcResult<SetRoleOutput>> setRoleOutputFuture;
253 if (deviceContext.getDeviceState().getFeatures().getVersion() < OFConstants.OFP_VERSION_1_3) {
254 LOG.debug("Device OF version {} not support ROLE", deviceContext.getDeviceState().getFeatures().getVersion());
255 setRoleOutputFuture = Futures.immediateFuture(RpcResultBuilder.<SetRoleOutput> success().build());
257 final SetRoleInput setRoleInput = (new SetRoleInputBuilder()).setControllerRole(newRole)
258 .setNode(new NodeRef(deviceContext.getDeviceState().getNodeInstanceIdentifier())).build();
259 setRoleOutputFuture = salRoleService.setRole(setRoleInput);
260 final TimerTask timerTask = new TimerTask() {
263 public void run(final Timeout timeout) throws Exception {
264 if (!setRoleOutputFuture.isDone()) {
265 LOG.info("New Role {} was not propagated to device {} during 10 sec. Close connection immediately.",
266 newRole, deviceContext.getDeviceState().getNodeId());
267 deviceContext.close();
271 deviceContext.getTimer().newTimeout(timerTask, 10, TimeUnit.SECONDS);
273 return Futures.transform(JdkFutureAdapters.listenInPoolThread(setRoleOutputFuture), function);