blob: ac1d90fafe103c67000e7b5b921988bab96b7f80 [file] [log] [blame]
Carmelo Casconef7aa3f92017-07-06 23:56:50 -04001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Carmelo Casconef7aa3f92017-07-06 23:56:50 -04003 *
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
17package org.onosproject.p4runtime.ctl;
18
19import com.google.common.collect.Maps;
20import io.grpc.ManagedChannel;
Yi Tseng2a340f72018-11-02 16:52:47 -070021import org.onosproject.grpc.ctl.AbstractGrpcClientController;
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040022import org.onosproject.net.DeviceId;
Carmelo Casconee5b28722018-06-22 17:28:28 +020023import org.onosproject.net.device.DeviceAgentEvent;
24import org.onosproject.net.device.DeviceAgentListener;
Carmelo Cascone9e4972c2018-08-30 00:29:16 -070025import org.onosproject.net.provider.ProviderId;
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040026import org.onosproject.p4runtime.api.P4RuntimeClient;
Yi Tseng2a340f72018-11-02 16:52:47 -070027import org.onosproject.p4runtime.api.P4RuntimeClientKey;
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040028import org.onosproject.p4runtime.api.P4RuntimeController;
29import org.onosproject.p4runtime.api.P4RuntimeEvent;
30import org.onosproject.p4runtime.api.P4RuntimeEventListener;
Yi Tseng3e7f1452017-10-20 10:31:53 -070031import org.onosproject.store.service.StorageService;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070032import org.osgi.service.component.annotations.Activate;
33import org.osgi.service.component.annotations.Component;
34import org.osgi.service.component.annotations.Deactivate;
35import org.osgi.service.component.annotations.Reference;
36import org.osgi.service.component.annotations.ReferenceCardinality;
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040037import org.slf4j.Logger;
38
Carmelo Casconee5b28722018-06-22 17:28:28 +020039import java.math.BigInteger;
Carmelo Casconee5b28722018-06-22 17:28:28 +020040import java.util.concurrent.ConcurrentMap;
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040041
42import static com.google.common.base.Preconditions.checkNotNull;
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040043import static org.slf4j.LoggerFactory.getLogger;
44
45/**
46 * P4Runtime controller implementation.
47 */
Ray Milkeyd84f89b2018-08-17 14:54:17 -070048@Component(immediate = true, service = P4RuntimeController.class)
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040049public class P4RuntimeControllerImpl
Yi Tseng2a340f72018-11-02 16:52:47 -070050 extends AbstractGrpcClientController
51 <P4RuntimeClientKey, P4RuntimeClient, P4RuntimeEvent, P4RuntimeEventListener>
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040052 implements P4RuntimeController {
53
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040054 private final Logger log = getLogger(getClass());
Carmelo Cascone158b8c42018-07-04 19:42:37 +020055
Carmelo Cascone9e4972c2018-08-30 00:29:16 -070056 private final ConcurrentMap<DeviceId, ConcurrentMap<ProviderId, DeviceAgentListener>>
57 deviceAgentListeners = Maps.newConcurrentMap();
Carmelo Cascone158b8c42018-07-04 19:42:37 +020058
Carmelo Casconee5b28722018-06-22 17:28:28 +020059 private DistributedElectionIdGenerator electionIdGenerator;
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040060
Ray Milkeyd84f89b2018-08-17 14:54:17 -070061 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Carmelo Cascone44448a52018-06-25 23:36:57 +020062 private StorageService storageService;
Yi Tseng3e7f1452017-10-20 10:31:53 -070063
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040064 @Activate
65 public void activate() {
Yi Tseng2a340f72018-11-02 16:52:47 -070066 super.activate();
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +020067 eventDispatcher.addSink(P4RuntimeEvent.class, listenerRegistry);
Carmelo Casconee5b28722018-06-22 17:28:28 +020068 electionIdGenerator = new DistributedElectionIdGenerator(storageService);
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040069 log.info("Started");
70 }
71
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040072 @Deactivate
73 public void deactivate() {
Yi Tseng2a340f72018-11-02 16:52:47 -070074 super.deactivate();
Carmelo Cascone158b8c42018-07-04 19:42:37 +020075 deviceAgentListeners.clear();
Carmelo Casconee5b28722018-06-22 17:28:28 +020076 electionIdGenerator.destroy();
77 electionIdGenerator = null;
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040078 log.info("Stopped");
79 }
80
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040081 @Override
Yi Tseng2a340f72018-11-02 16:52:47 -070082 protected P4RuntimeClient createClientInstance(P4RuntimeClientKey clientKey, ManagedChannel channel) {
83 return new P4RuntimeClientImpl(clientKey, channel, this);
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040084 }
85
Yi Tseng3e7f1452017-10-20 10:31:53 -070086 @Override
Carmelo Cascone9e4972c2018-08-30 00:29:16 -070087 public void addDeviceAgentListener(DeviceId deviceId, ProviderId providerId, DeviceAgentListener listener) {
Carmelo Cascone7044efd2018-07-06 13:01:36 +020088 checkNotNull(deviceId, "deviceId cannot be null");
Carmelo Cascone9e4972c2018-08-30 00:29:16 -070089 checkNotNull(deviceId, "providerId cannot be null");
Carmelo Cascone7044efd2018-07-06 13:01:36 +020090 checkNotNull(listener, "listener cannot be null");
Carmelo Cascone9e4972c2018-08-30 00:29:16 -070091 deviceAgentListeners.putIfAbsent(deviceId, Maps.newConcurrentMap());
92 deviceAgentListeners.get(deviceId).put(providerId, listener);
Yi Tseng3e7f1452017-10-20 10:31:53 -070093 }
94
Andrea Campanella1e573442018-05-17 17:07:13 +020095 @Override
Carmelo Cascone9e4972c2018-08-30 00:29:16 -070096 public void removeDeviceAgentListener(DeviceId deviceId, ProviderId providerId) {
Carmelo Cascone7044efd2018-07-06 13:01:36 +020097 checkNotNull(deviceId, "deviceId cannot be null");
Carmelo Cascone9e4972c2018-08-30 00:29:16 -070098 checkNotNull(providerId, "listener cannot be null");
Carmelo Casconee5b28722018-06-22 17:28:28 +020099 deviceAgentListeners.computeIfPresent(deviceId, (did, listeners) -> {
Carmelo Cascone9e4972c2018-08-30 00:29:16 -0700100 listeners.remove(providerId);
Carmelo Casconee5b28722018-06-22 17:28:28 +0200101 return listeners;
Andrea Campanella1e573442018-05-17 17:07:13 +0200102 });
103 }
104
Carmelo Casconee5b28722018-06-22 17:28:28 +0200105 BigInteger newMasterElectionId(DeviceId deviceId) {
106 return electionIdGenerator.generate(deviceId);
Andrea Campanella1e573442018-05-17 17:07:13 +0200107 }
108
Carmelo Cascone44448a52018-06-25 23:36:57 +0200109 void postEvent(P4RuntimeEvent event) {
Carmelo Casconee5b28722018-06-22 17:28:28 +0200110 switch (event.type()) {
111 case CHANNEL_EVENT:
112 handleChannelEvent(event);
113 break;
114 case ARBITRATION_RESPONSE:
115 handleArbitrationReply(event);
116 break;
Carmelo Casconede3b6842018-09-05 17:45:10 -0700117 case PERMISSION_DENIED:
118 handlePermissionDenied(event);
119 break;
Carmelo Casconee5b28722018-06-22 17:28:28 +0200120 default:
121 post(event);
122 break;
Andrea Campanella1e573442018-05-17 17:07:13 +0200123 }
Carmelo Casconef7aa3f92017-07-06 23:56:50 -0400124 }
Carmelo Cascone44448a52018-06-25 23:36:57 +0200125
Carmelo Casconede3b6842018-09-05 17:45:10 -0700126 private void handlePermissionDenied(P4RuntimeEvent event) {
127 postDeviceAgentEvent(event.subject().deviceId(), new DeviceAgentEvent(
128 DeviceAgentEvent.Type.NOT_MASTER, event.subject().deviceId()));
129 }
130
Carmelo Casconee5b28722018-06-22 17:28:28 +0200131 private void handleChannelEvent(P4RuntimeEvent event) {
132 final ChannelEvent channelEvent = (ChannelEvent) event.subject();
133 final DeviceId deviceId = channelEvent.deviceId();
134 final DeviceAgentEvent.Type agentEventType;
135 switch (channelEvent.type()) {
136 case OPEN:
137 agentEventType = DeviceAgentEvent.Type.CHANNEL_OPEN;
138 break;
139 case CLOSED:
140 agentEventType = DeviceAgentEvent.Type.CHANNEL_CLOSED;
141 break;
142 case ERROR:
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200143 agentEventType = !isReachable(deviceId)
Carmelo Casconee5b28722018-06-22 17:28:28 +0200144 ? DeviceAgentEvent.Type.CHANNEL_CLOSED
145 : DeviceAgentEvent.Type.CHANNEL_ERROR;
146 break;
147 default:
148 log.warn("Unrecognized channel event type {}", channelEvent.type());
149 return;
150 }
151 postDeviceAgentEvent(deviceId, new DeviceAgentEvent(agentEventType, deviceId));
152 }
153
154 private void handleArbitrationReply(P4RuntimeEvent event) {
155 final DeviceId deviceId = event.subject().deviceId();
156 final ArbitrationResponse response = (ArbitrationResponse) event.subject();
157 final DeviceAgentEvent.Type roleType = response.isMaster()
158 ? DeviceAgentEvent.Type.ROLE_MASTER
159 : DeviceAgentEvent.Type.ROLE_STANDBY;
160 postDeviceAgentEvent(deviceId, new DeviceAgentEvent(
161 roleType, response.deviceId()));
162 }
163
164 private void postDeviceAgentEvent(DeviceId deviceId, DeviceAgentEvent event) {
165 if (deviceAgentListeners.containsKey(deviceId)) {
Carmelo Cascone9e4972c2018-08-30 00:29:16 -0700166 deviceAgentListeners.get(deviceId).values().forEach(l -> l.event(event));
Carmelo Casconee5b28722018-06-22 17:28:28 +0200167 }
168 }
Carmelo Casconef7aa3f92017-07-06 23:56:50 -0400169}