blob: a28765389560cb70e3820b08af840a10713f1595 [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;
Carmelo Cascone158b8c42018-07-04 19:42:37 +020020import com.google.common.util.concurrent.Striped;
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040021import io.grpc.ManagedChannel;
Yi Tseng2a340f72018-11-02 16:52:47 -070022import org.onosproject.grpc.ctl.AbstractGrpcClientController;
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040023import org.onosproject.net.DeviceId;
Carmelo Casconee5b28722018-06-22 17:28:28 +020024import org.onosproject.net.device.DeviceAgentEvent;
25import org.onosproject.net.device.DeviceAgentListener;
Carmelo Cascone9e4972c2018-08-30 00:29:16 -070026import org.onosproject.net.provider.ProviderId;
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040027import org.onosproject.p4runtime.api.P4RuntimeClient;
Yi Tseng2a340f72018-11-02 16:52:47 -070028import org.onosproject.p4runtime.api.P4RuntimeClientKey;
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040029import org.onosproject.p4runtime.api.P4RuntimeController;
30import org.onosproject.p4runtime.api.P4RuntimeEvent;
31import org.onosproject.p4runtime.api.P4RuntimeEventListener;
Yi Tseng3e7f1452017-10-20 10:31:53 -070032import org.onosproject.store.service.StorageService;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070033import org.osgi.service.component.annotations.Activate;
34import org.osgi.service.component.annotations.Component;
35import org.osgi.service.component.annotations.Deactivate;
36import org.osgi.service.component.annotations.Reference;
37import org.osgi.service.component.annotations.ReferenceCardinality;
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040038import org.slf4j.Logger;
39
Carmelo Casconee5b28722018-06-22 17:28:28 +020040import java.math.BigInteger;
Carmelo Casconee5b28722018-06-22 17:28:28 +020041import java.util.concurrent.ConcurrentMap;
Carmelo Cascone158b8c42018-07-04 19:42:37 +020042import java.util.concurrent.locks.Lock;
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040043
44import static com.google.common.base.Preconditions.checkNotNull;
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040045import static org.slf4j.LoggerFactory.getLogger;
46
47/**
48 * P4Runtime controller implementation.
49 */
Ray Milkeyd84f89b2018-08-17 14:54:17 -070050@Component(immediate = true, service = P4RuntimeController.class)
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040051public class P4RuntimeControllerImpl
Yi Tseng2a340f72018-11-02 16:52:47 -070052 extends AbstractGrpcClientController
53 <P4RuntimeClientKey, P4RuntimeClient, P4RuntimeEvent, P4RuntimeEventListener>
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040054 implements P4RuntimeController {
55
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040056 private final Logger log = getLogger(getClass());
Carmelo Cascone158b8c42018-07-04 19:42:37 +020057
Carmelo Cascone9e4972c2018-08-30 00:29:16 -070058 private final ConcurrentMap<DeviceId, ConcurrentMap<ProviderId, DeviceAgentListener>>
59 deviceAgentListeners = Maps.newConcurrentMap();
Carmelo Cascone158b8c42018-07-04 19:42:37 +020060 private final Striped<Lock> stripedLocks = Striped.lock(30);
61
Carmelo Casconee5b28722018-06-22 17:28:28 +020062 private DistributedElectionIdGenerator electionIdGenerator;
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040063
Ray Milkeyd84f89b2018-08-17 14:54:17 -070064 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Carmelo Cascone44448a52018-06-25 23:36:57 +020065 private StorageService storageService;
Yi Tseng3e7f1452017-10-20 10:31:53 -070066
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040067 @Activate
68 public void activate() {
Yi Tseng2a340f72018-11-02 16:52:47 -070069 super.activate();
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +020070 eventDispatcher.addSink(P4RuntimeEvent.class, listenerRegistry);
Carmelo Casconee5b28722018-06-22 17:28:28 +020071 electionIdGenerator = new DistributedElectionIdGenerator(storageService);
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040072 log.info("Started");
73 }
74
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040075 @Deactivate
76 public void deactivate() {
Yi Tseng2a340f72018-11-02 16:52:47 -070077 super.deactivate();
Carmelo Cascone158b8c42018-07-04 19:42:37 +020078 deviceAgentListeners.clear();
Carmelo Casconee5b28722018-06-22 17:28:28 +020079 electionIdGenerator.destroy();
80 electionIdGenerator = null;
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040081 log.info("Stopped");
82 }
83
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040084 @Override
Yi Tseng2a340f72018-11-02 16:52:47 -070085 protected P4RuntimeClient createClientInstance(P4RuntimeClientKey clientKey, ManagedChannel channel) {
86 return new P4RuntimeClientImpl(clientKey, channel, this);
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040087 }
88
Yi Tseng3e7f1452017-10-20 10:31:53 -070089 @Override
Carmelo Cascone9e4972c2018-08-30 00:29:16 -070090 public void addDeviceAgentListener(DeviceId deviceId, ProviderId providerId, DeviceAgentListener listener) {
Carmelo Cascone7044efd2018-07-06 13:01:36 +020091 checkNotNull(deviceId, "deviceId cannot be null");
Carmelo Cascone9e4972c2018-08-30 00:29:16 -070092 checkNotNull(deviceId, "providerId cannot be null");
Carmelo Cascone7044efd2018-07-06 13:01:36 +020093 checkNotNull(listener, "listener cannot be null");
Carmelo Cascone9e4972c2018-08-30 00:29:16 -070094 deviceAgentListeners.putIfAbsent(deviceId, Maps.newConcurrentMap());
95 deviceAgentListeners.get(deviceId).put(providerId, listener);
Yi Tseng3e7f1452017-10-20 10:31:53 -070096 }
97
Andrea Campanella1e573442018-05-17 17:07:13 +020098 @Override
Carmelo Cascone9e4972c2018-08-30 00:29:16 -070099 public void removeDeviceAgentListener(DeviceId deviceId, ProviderId providerId) {
Carmelo Cascone7044efd2018-07-06 13:01:36 +0200100 checkNotNull(deviceId, "deviceId cannot be null");
Carmelo Cascone9e4972c2018-08-30 00:29:16 -0700101 checkNotNull(providerId, "listener cannot be null");
Carmelo Casconee5b28722018-06-22 17:28:28 +0200102 deviceAgentListeners.computeIfPresent(deviceId, (did, listeners) -> {
Carmelo Cascone9e4972c2018-08-30 00:29:16 -0700103 listeners.remove(providerId);
Carmelo Casconee5b28722018-06-22 17:28:28 +0200104 return listeners;
Andrea Campanella1e573442018-05-17 17:07:13 +0200105 });
106 }
107
Carmelo Casconee5b28722018-06-22 17:28:28 +0200108 BigInteger newMasterElectionId(DeviceId deviceId) {
109 return electionIdGenerator.generate(deviceId);
Andrea Campanella1e573442018-05-17 17:07:13 +0200110 }
111
Carmelo Cascone44448a52018-06-25 23:36:57 +0200112 void postEvent(P4RuntimeEvent event) {
Carmelo Casconee5b28722018-06-22 17:28:28 +0200113 switch (event.type()) {
114 case CHANNEL_EVENT:
115 handleChannelEvent(event);
116 break;
117 case ARBITRATION_RESPONSE:
118 handleArbitrationReply(event);
119 break;
Carmelo Casconede3b6842018-09-05 17:45:10 -0700120 case PERMISSION_DENIED:
121 handlePermissionDenied(event);
122 break;
Carmelo Casconee5b28722018-06-22 17:28:28 +0200123 default:
124 post(event);
125 break;
Andrea Campanella1e573442018-05-17 17:07:13 +0200126 }
Carmelo Casconef7aa3f92017-07-06 23:56:50 -0400127 }
Carmelo Cascone44448a52018-06-25 23:36:57 +0200128
Carmelo Casconede3b6842018-09-05 17:45:10 -0700129 private void handlePermissionDenied(P4RuntimeEvent event) {
130 postDeviceAgentEvent(event.subject().deviceId(), new DeviceAgentEvent(
131 DeviceAgentEvent.Type.NOT_MASTER, event.subject().deviceId()));
132 }
133
Carmelo Casconee5b28722018-06-22 17:28:28 +0200134 private void handleChannelEvent(P4RuntimeEvent event) {
135 final ChannelEvent channelEvent = (ChannelEvent) event.subject();
136 final DeviceId deviceId = channelEvent.deviceId();
137 final DeviceAgentEvent.Type agentEventType;
138 switch (channelEvent.type()) {
139 case OPEN:
140 agentEventType = DeviceAgentEvent.Type.CHANNEL_OPEN;
141 break;
142 case CLOSED:
143 agentEventType = DeviceAgentEvent.Type.CHANNEL_CLOSED;
144 break;
145 case ERROR:
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200146 agentEventType = !isReachable(deviceId)
Carmelo Casconee5b28722018-06-22 17:28:28 +0200147 ? DeviceAgentEvent.Type.CHANNEL_CLOSED
148 : DeviceAgentEvent.Type.CHANNEL_ERROR;
149 break;
150 default:
151 log.warn("Unrecognized channel event type {}", channelEvent.type());
152 return;
153 }
154 postDeviceAgentEvent(deviceId, new DeviceAgentEvent(agentEventType, deviceId));
155 }
156
157 private void handleArbitrationReply(P4RuntimeEvent event) {
158 final DeviceId deviceId = event.subject().deviceId();
159 final ArbitrationResponse response = (ArbitrationResponse) event.subject();
160 final DeviceAgentEvent.Type roleType = response.isMaster()
161 ? DeviceAgentEvent.Type.ROLE_MASTER
162 : DeviceAgentEvent.Type.ROLE_STANDBY;
163 postDeviceAgentEvent(deviceId, new DeviceAgentEvent(
164 roleType, response.deviceId()));
165 }
166
167 private void postDeviceAgentEvent(DeviceId deviceId, DeviceAgentEvent event) {
168 if (deviceAgentListeners.containsKey(deviceId)) {
Carmelo Cascone9e4972c2018-08-30 00:29:16 -0700169 deviceAgentListeners.get(deviceId).values().forEach(l -> l.event(event));
Carmelo Casconee5b28722018-06-22 17:28:28 +0200170 }
171 }
Carmelo Casconef7aa3f92017-07-06 23:56:50 -0400172}