Carmelo Cascone | 95dcaa0 | 2019-03-08 10:53:01 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2019-present Open Networking Foundation |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | package org.onosproject.drivers.gnmi; |
| 18 | |
| 19 | import com.google.common.collect.Maps; |
| 20 | import org.onlab.util.SharedExecutors; |
| 21 | import org.onosproject.gnmi.api.GnmiController; |
| 22 | import org.onosproject.net.DeviceId; |
| 23 | import org.onosproject.net.MastershipRole; |
| 24 | import org.onosproject.net.device.DeviceAgentEvent; |
| 25 | import org.onosproject.net.device.DeviceAgentListener; |
| 26 | import org.onosproject.net.device.DeviceHandshaker; |
| 27 | import org.onosproject.net.provider.ProviderId; |
| 28 | |
| 29 | import java.util.TimerTask; |
| 30 | import java.util.concurrent.ConcurrentMap; |
| 31 | |
| 32 | import static com.google.common.base.Preconditions.checkNotNull; |
| 33 | |
| 34 | /** |
| 35 | * Implementation of DeviceHandshaker that allows using the gNMI driver as a |
| 36 | * standalone one. Since gNMI does not support mastership, this driver stores a |
| 37 | * copy of the agent listeners registered by the providers, needed to |
| 38 | * acknowledge whatever role was requested. |
| 39 | */ |
| 40 | public class GnmiHandshakerStandalone |
| 41 | extends GnmiHandshaker implements DeviceHandshaker { |
| 42 | |
| 43 | private static final int ROLE_REPLY_LATENCY_MILLIS = 200; |
| 44 | private static final ConcurrentMap<DeviceId, ConcurrentMap<ProviderId, DeviceAgentListener>> |
| 45 | AGENT_LISTENERS = Maps.newConcurrentMap(); |
| 46 | private static final ConcurrentMap<DeviceId, MastershipRole> |
| 47 | ROLES = Maps.newConcurrentMap(); |
| 48 | |
| 49 | @Override |
| 50 | public void roleChanged(MastershipRole newRole) { |
| 51 | final DeviceAgentEvent.Type eventType; |
| 52 | switch (newRole) { |
| 53 | case MASTER: |
| 54 | eventType = DeviceAgentEvent.Type.ROLE_MASTER; |
| 55 | break; |
| 56 | case STANDBY: |
| 57 | eventType = DeviceAgentEvent.Type.ROLE_STANDBY; |
| 58 | break; |
| 59 | case NONE: |
| 60 | eventType = DeviceAgentEvent.Type.ROLE_NONE; |
| 61 | break; |
| 62 | default: |
| 63 | log.error("Unrecognized mastership role {}", newRole); |
| 64 | return; |
| 65 | } |
| 66 | SharedExecutors.getTimer().schedule(new TimerTask() { |
| 67 | @Override |
| 68 | public void run() { |
| 69 | if (newRole == MastershipRole.NONE) { |
| 70 | ROLES.remove(deviceId); |
| 71 | } else { |
| 72 | ROLES.put(data().deviceId(), newRole); |
| 73 | } |
| 74 | postAgentEvent(new DeviceAgentEvent( |
| 75 | eventType, data().deviceId())); |
| 76 | } |
| 77 | }, ROLE_REPLY_LATENCY_MILLIS); |
| 78 | } |
| 79 | |
| 80 | @Override |
| 81 | public MastershipRole getRole() { |
| 82 | return ROLES.getOrDefault(data().deviceId(), MastershipRole.NONE); |
| 83 | } |
| 84 | |
| 85 | @Override |
| 86 | public void addDeviceAgentListener(ProviderId providerId, DeviceAgentListener listener) { |
| 87 | handler().get(GnmiController.class) |
| 88 | .addDeviceAgentListener(data().deviceId(), providerId, listener); |
| 89 | AGENT_LISTENERS.putIfAbsent(deviceId, Maps.newConcurrentMap()); |
| 90 | AGENT_LISTENERS.get(deviceId).put(providerId, listener); |
| 91 | } |
| 92 | |
| 93 | @Override |
| 94 | public void removeDeviceAgentListener(ProviderId providerId) { |
| 95 | handler().get(GnmiController.class) |
| 96 | .removeDeviceAgentListener(data().deviceId(), providerId); |
| 97 | AGENT_LISTENERS.computeIfPresent(deviceId, (did, listeners) -> { |
| 98 | listeners.remove(providerId); |
| 99 | return listeners.isEmpty() ? null : listeners; |
| 100 | }); |
| 101 | } |
| 102 | |
| 103 | private void postAgentEvent(DeviceAgentEvent event) { |
| 104 | checkNotNull(event); |
| 105 | if (AGENT_LISTENERS.containsKey(event.subject())) { |
| 106 | AGENT_LISTENERS.get(event.subject()).values() |
| 107 | .forEach(l -> l.event(event)); |
| 108 | } |
| 109 | } |
| 110 | |
| 111 | @Override |
| 112 | public void disconnect() { |
| 113 | ROLES.remove(data().deviceId()); |
| 114 | AGENT_LISTENERS.remove(data().deviceId()); |
| 115 | super.disconnect(); |
| 116 | } |
| 117 | } |